dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.38k stars 3.1k forks source link

KeyNotFoundException during ApplyProjection phase of a groupby query with FirstOrDefault #33216

Open maumar opened 2 months ago

maumar commented 2 months ago
    [ConditionalTheory]
    [MemberData(nameof(IsAsyncData))]
    public virtual Task MyTest(bool async)
        => AssertQuery(
            async,
            ss => from g in ss.Set<Customer>().GroupBy(
                x => x.Orders.Where(x => x.OrderDate.Value.Month == 2).Count(),
                (k, g) => new { FebOrderCount = k, FirstCustomer = g.OrderBy(x => x.CustomerID).FirstOrDefault() })
                  select new { g.FebOrderCount, g.FirstCustomer.CustomerID });

exception:

System.Collections.Generic.KeyNotFoundException : The given key 'EmptyProjectionMember' was not present in the dictionary.

  Stack Trace: 
Dictionary`2.get_Item(TKey key)
ProjectionMemberToIndexConvertingExpressionVisitor.Visit(Expression expression) line 112
StructuralTypeShaperExpression.VisitChildren(ExpressionVisitor visitor) line 207
ProjectionMemberToIndexConvertingExpressionVisitor.Visit(Expression expression) line 118
SelectExpression.ApplyProjection(Expression shaperExpression, ResultCardinality resultCardinality, QuerySplittingBehavior querySplittingBehavior) line 742
SelectExpressionProjectionApplyingExpressionVisitor.VisitExtension(Expression extensionExpression) line 39
RelationalQueryTranslationPostprocessor.Process(Expression query) line 43
SqlServerQueryTranslationPostprocessor.Process(Expression query) line 47
QueryCompilationContext.CreateQueryExecutor[TResult](Expression query) line 165
Database.CompileQuery[TResult](Expression query, Boolean async) line 66
QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async) line 126
<>c__DisplayClass11_0`1.<ExecuteCore>b__0() line 82

possibly similar cause to https://github.com/dotnet/efcore/issues/33215 (?)

maumar commented 2 months ago

projecting a single property instead of entire entity works fine:

    [ConditionalTheory]
    [MemberData(nameof(IsAsyncData))]
    public virtual Task MyTest(bool async)
        => AssertQuery(
            async,
            ss => from g in ss.Set<Customer>().GroupBy(
                x => x.Orders.Where(x => x.OrderDate.Value.Month == 2).Count(),
                (k, g) => new { FebOrderCount = k, FirstCustomer = g.OrderBy(x => x.CustomerID).FirstOrDefault().CustomerID })
                  select new { g.FebOrderCount, g.FirstCustomer/*.CustomerID*/ });

produces:

    Generated query execution expression: 
'queryContext => new SingleQueryingEnumerable<<>f__AnonymousType738<int, string>>(
    (RelationalQueryContext)queryContext, 
    RelationalCommandCache.QueryExpression(
        Projection Mapping:
            FebOrderCount -> 0
            FirstCustomer -> 1
        SELECT c0.Key AS FebOrderCount, (
            SELECT TOP(1) c1.CustomerID
            FROM 
            (
                SELECT c2.CustomerID, (
                    SELECT COUNT(*)
                    FROM Orders AS o0
                    WHERE ((c2.CustomerID != NULL) && (c2.CustomerID == o0.CustomerID)) && (DATEPART(month, o0.OrderDate) == 2)) AS Key
                FROM Customers AS c2
            ) AS c1
            WHERE c0.Key == c1.Key
            ORDER BY c1.CustomerID ASC) AS FirstCustomer
        FROM 
        (
            SELECT (
                SELECT COUNT(*)
                FROM Orders AS o
                WHERE ((c.CustomerID != NULL) && (c.CustomerID == o.CustomerID)) && (DATEPART(month, o.OrderDate) == 2)) AS Key
            FROM Customers AS c
        ) AS c0
        GROUP BY c0.Key), 
    ReaderColumn[] { ReaderColumn<int>, ReaderColumn<object> }, 
    Func<QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator, <>f__AnonymousType738<int, string>>, 
    TestModels.Northwind.NorthwindSqlServerContext, 
    False, 
    True, 
    True
)'