Craig W.
Craig W.

Reputation: 18165

Converting from EF 6 to EF Core, existing query throwing "given key was not present in the dictionary"

I'm in the process of converting one of our .NET Framework applications from EF 6 to EF Core (3.1.26). One of our queries is now throwing a KeyNotFoundException.

The query in question is shown here:

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);

If I remove fa.FingerprintScores the query executes fine. With that property in the result set the query throws the KeyNotFoundException. It is a collection property on the Attempts entity and is defined as follows:

private List<FingerprintScore> _fingerprintScores;

public List<FingerprintScore> FingerprintScores =>
    _fingerprintScores = _fingerprintScores ?? new List<FingerprintScore>();

Using SQL Server Profiler never shows the request hitting the database so I'm assuming it's blowing up trying to build the expression tree and not something related to the data it's trying to retrieve.

For now I've resolved the issue by doing a second query to get the score information, but we do this sort of thing throughout the codebase so I'd like to have a better idea of what's going wrong.

UPDATE

Using LINQPad to try out different combinations I discovered that removing either the fa.FingerprintScores or the .FirstOrDefault() causes the query to work. I can reproduce that behavior consistently in any queries that have the same type of relationships.

As someone asked in the comments, here is the stack trace.

   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()

Upvotes: 0

Views: 553

Answers (1)

Svyatoslav Danyliv
Svyatoslav Danyliv

Reputation: 27416

Try the following query. It forces EF Core to use different translation algorithm but give the same result.

var query = 
    from a in context.Applications
    from fa in a.Attempts
        .Select(fa => new
        {
            fa.CandidateSubmissionReceivedDateUtc,
            fa.FingerprintScores
        })
        .Take(1)
        .DefaultIfEmpty()
    select new 
    {
        a.Id,
        Attempt = fa
    };    

var data = query
    .SingleOrDefault(a => a.Id == request.ApplicationId);

Upvotes: 1

Related Questions