EF6迁移至EF Core 3.1.26时查询抛出KeyNotFoundException问题
问题:EF 6迁移至EF Core 3.1.26时查询抛出KeyNotFoundException
正在将.NET Framework应用从EF 6迁移到EF Core 3.1.26,执行以下查询时抛出KeyNotFoundException:
var data = context.Applications .Select(a => new { a.Id, Attempt = a.Attempts .Select(fa => new { fa.CandidateSubmissionReceivedDateUtc, fa.FingerprintScores }) .FirstOrDefault() }) .SingleOrDefault(a => a.Id == request.ApplicationId);
移除fa.FingerprintScores后查询可正常执行。该属性是Attempts实体上的集合属性,定义如下:
private List<FingerprintScore> _fingerprintScores; public List<FingerprintScore> FingerprintScores => _fingerprintScores = _fingerprintScores ?? new List<FingerprintScore>();
通过SQL Server Profiler未发现请求到达数据库,推测异常发生在表达式树构建阶段。目前通过二次查询获取分数信息作为临时解决方案,但此类查询在代码库中大量存在,需要找到问题根源。
更新信息
通过LINQPad测试发现:
- 移除
fa.FingerprintScores或.FirstOrDefault()均可使查询正常执行 - 所有相同关联关系的查询均存在该现象
以下是异常堆栈跟踪:
at System.Collections.Generic.Dictionary`2.get_Item(TKey key) at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.ShaperRemappingExpressionVisitor.GetProjectionIndex(ProjectionBindingExpression projectionBindingExpression) at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.ShaperRemappingExpressionVisitor.VisitExtension(Expression extensionExpression) at Microsoft.EntityFrameworkCore.Query.CollectionShaperExpression.VisitChildren(ExpressionVisitor visitor) at Microsoft.EntityFrameworkCore.Query.SqlExpressions.SelectExpression.ShaperRemappingExpressionVisitor.VisitExtension(Expression extensionExpression) at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes) at System.Linq.Expressions.ExpressionVisitor.VisitNew(NewExpression node) at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node) at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.VisitNew(NewExpression newExpression) at Microsoft.EntityFrameworkCore.Query.Internal.RelationalProjectionBindingExpressionVisitor.Translate(SelectExpression selectExpression, Expression expression) at Microsoft.EntityFrameworkCore.Query.RelationalQueryableMethodTranslatingExpressionVisitor.TranslateSelect(ShapedQueryExpression source, LambdaExpression selector) at Microsoft.EntityFrameworkCore.Query.QueryableMethodTranslatingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) 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.GetOrAddQueryCore[TFunc](Object cacheKey, Func`1 compiler) 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.Query.Internal.EntityQueryable`1.System.Collections.IEnumerable.GetEnumerator() at LINQPad.UI.ExplorerGrid.ConvertToList(IEnumerable source) at LINQPad.UI.ExplorerGrid.UpdateDataSourceToUse()
问题根源及解决办法
1. 属性定义不符合EF Core要求
EF Core对实体集合属性的定义有更严格的解析规则。当前FingerprintScores使用表达式体属性且在getter中延迟初始化集合,这种写法在EF 6中可行,但EF Core的查询表达式树解析器无法正确处理该逻辑,导致翻译过程中出现键查找失败。
解决:修改集合属性的初始化方式,改为在字段声明时或构造函数中初始化:
private List<FingerprintScore> _fingerprintScores = new List<FingerprintScore>(); public List<FingerprintScore> FingerprintScores => _fingerprintScores;
或者使用自动属性:
public List<FingerprintScore> FingerprintScores { get; set; } = new List<FingerprintScore>();
2. EF Core 3.1的查询翻译局限性
EF Core 3.1对「嵌套查询+集合投影」的支持存在bug,尤其是在FirstOrDefault()嵌套中直接包含集合属性时,表达式树翻译器会出现字典键缺失的异常(对应堆栈中的Dictionary.get_Item调用失败)。
解决:
- 升级EF Core版本:EF Core 3.1是旧版本,后续的5.0+版本修复了大量查询翻译bug,升级到LTS版本(如6.0或8.0)可直接解决此类问题。
- 调整查询写法:避免在嵌套投影中直接包含集合属性,可先通过
Include预加载关联数据,再在内存中完成投影:
var data = context.Applications .Include(a => a.Attempts) .ThenInclude(fa => fa.FingerprintScores) .SingleOrDefault(a => a.Id == request.ApplicationId); var result = new { data.Id, Attempt = data.Attempts .Select(fa => new { fa.CandidateSubmissionReceivedDateUtc, fa.FingerprintScores }) .FirstOrDefault() };
内容的提问来源于stack exchange,提问作者Craig W.
相关产品推荐
相关产品推荐

