添加JSON列后无法查询实体(EF Core 8)
问题描述
我们在使用EntityFramework Core 7的JSON特性扩展数据库模型时,添加属性后执行查询始终抛出如下异常:
System.ArgumentException: Expression of type 'System.Object' cannot be used for assignment to type 'System.String' at System.Linq.Expressions.Expression.Assign(Expression left, Expression right) at System.Linq.Expressions.Expression.MakeBinary(ExpressionType binaryType, Expression left, Expression right, Boolean liftToNull, MethodInfo method, LambdaExpression conversion) at System.Linq.Expressions.BinaryExpression.Update(Expression left, LambdaExpression conversion, Expression right) at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block) at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block) at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block) at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block) at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block) at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression`1 node) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes) at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block) at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitSwitchCase(SwitchCase node) at System.Linq.Expressions.ExpressionVisitor.Visit[T](ReadOnlyCollection`1 nodes, Func`2 elementVisitor) at System.Linq.Expressions.ExpressionVisitor.VisitSwitch(SwitchExpression node) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block) at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitLoop(LoopExpression node) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block) at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block) at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block) at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitBinary(BinaryExpression binaryExpression) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block) at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression`1 node) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes) at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitExtension(Expression extensionExpression) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitExtension(Expression extensionExpression) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitExtension(Expression extensionExpression) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.ProcessShaper(Expression shaperExpression, RelationalCommandCache& relationalCommandCache, IReadOnlyList`1& readerColumns, LambdaExpression& relatedDataLoaders, Int32& collectionId) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitShapedQuery(ShapedQueryExpression shapedQueryExpression) at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression) at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression) at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query) at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression) at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToQueryString(IQueryable source)
相关配置与代码
DbContext配置
builder.Entity<Order>(eb => { eb.OwnsOne( o => o.MetricData, b => { b.ToJson(); b.OwnsMany(metric => metric.AdditionalData); }); });
EF迁移代码
migrationBuilder.AddColumn<string>( name: "MetricData", table: "Orders", type: "nvarchar(max)", nullable: true);
查询代码
即使移除x.MetricData == null条件,仅查询OrderId匹配的记录也会触发相同错误:
// 触发错误的查询1 var qs = context.Orders .Where(x => x.OrderId == request.OrderId && x.MetricData == null ).ToQueryString(); // 触发错误的查询2 context.Orders .Where(x => x.OrderId == request.OrderId );
问题原因
这是EF Core 7早期版本的已知bug:当对**拥有实体(OwnsOne)同时使用ToJson()和嵌套OwnsMany()**时,EF Core在处理JSON列的实体反序列化逻辑时,错误地将数据库中的字符串类型JSON列,尝试赋值给Object类型的中间表达式,导致类型不匹配异常。
解决方案
1. 升级EF Core版本到7.0.4及以上
该bug已在EF Core 7.0.4补丁版本中修复,直接升级NuGet包Microsoft.EntityFrameworkCore及对应数据库提供者包(如Microsoft.EntityFrameworkCore.SqlServer)到7.0.4或更高版本即可解决问题。
2. 临时规避方案(无法升级版本时)
如果暂时无法升级版本,可以修改实体配置,放弃使用EF Core的OwnsMany嵌套配置,改为在JSON实体中直接使用集合属性:
修改实体类
public class MetricData { // 用普通集合替换OwnsMany配置的关联集合 public List<AdditionalDataItem> AdditionalData { get; set; } = new(); // 其他属性... } public class AdditionalDataItem { // 你的业务属性... }
修改DbContext配置
移除OwnsMany相关配置,仅保留ToJson():
builder.Entity<Order>(eb => { eb.OwnsOne( o => o.MetricData, b => { b.ToJson(); // 移除b.OwnsMany(metric => metric.AdditionalData); }); });
这种配置下,EF Core会自动将整个MetricData对象(包括集合属性)序列化为JSON字符串存储,查询时也能正确反序列化,不会触发类型转换错误。
3. 验证数据库列类型
确认数据库中MetricData列的类型为字符串类型(如SQL Server的nvarchar(max)),如果迁移生成的列类型不符合预期,重新生成并应用正确的迁移脚本。
内容的提问来源于stack exchange,提问作者Jon Selby
相关产品推荐
相关产品推荐

