在 EFCore 中按多列分组会导致 InvalidOperationException

Grouping by multiple columns in EFCore results in InvalidOperationException

假设我们有模型 A、B 和 C。A 与 B 和 C 之间存在多对多关系。我想创建以下聚合:

+--------+----------------+--------------+---------+
|  a_id  |  b_value_sum   | c_value_sum  | c_count |
+--------+----------------+--------------+---------+
| 1      |  20            | 10           | 40      | 
+--------+----------------+--------------+---------+

查询:

var query = 
    from a in context.A
    from b in a.B.DefaultIfEmpty()
    from c in b.C.DefaultIfEmpty()
    group new { b, c } by new { a.Id } into g
    select new
    {
        Id = g.Key.ToString(),
        ValueBSum = g.Sum(y => y.b.Value),
        ValueCSum = g.Sum(y => y.c.Value),
        ValueCCount = g.Count()
    };

生成的查询:

SELECT 
    [c].[Id], 
    COALESCE(SUM([t].[Value]), 0.0), 
    COALESCE(SUM([t0].[Value]), 0.0), 
    COUNT(*)
FROM [A] AS [c]
LEFT JOIN (
    SELECT 
        [b].[Value], 
        [c1].[A_Id]
    FROM [AB] AS [c1]
    INNER JOIN [B] AS [b] ON [c1].[B_Id] = [b].[Id]
) AS [t] ON [c].[Id] = [t].[A_Id]
LEFT JOIN (
    SELECT 
        [s0].[Value], 
        [s].[A_Id]
    FROM [AC] AS [s]
    INNER JOIN [C] AS [s0] ON [s].[C_Id] = [s0].[Id]
) AS [t0] ON [c].[Id] = [t0].[A_Id]
GROUP BY [c].[Id]

结果

System.InvalidOperationException: Operation is not valid due to the current state of the object.

需要注意的一件事是,外部 select 缺少 AS 语句。例如。作为 BValueSum.

new { a.Id } 替换为 a.id 可解决问题。但是我想按多列分组,这总是给我上面的错误。

堆栈跟踪:

fail: UseCase[0]
       MyProject Request: Unhandled Exception for Request UseCase
      System.InvalidOperationException: Operation is not valid due to the current state of the object.
         at System.Linq.Expressions.ExpressionExtensions.GetConstantValue[T](Expression expression)
         at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.GetProjectionIndex(ProjectionBindingExpression projectionBindingExpression)
         at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitExtension(Expression extensionExpression)
         at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
         at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.ProcessShaper(Expression shaperExpression, RelationalCommandCache& relationalCommandCache, LambdaExpression& relatedDataLoaders, Int32& collectionId)
         at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitShapedQuery(ShapedQueryExpression shapedQueryExpression)
         at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.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__DisplayClass12_0`1.<ExecuteAsync>b__0()
         at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
         at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, Expression expression, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, CancellationToken cancellationToken)
         at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.CountAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
         at MyProject.Shared.Models.PaginatedList`1.CreateAsync(IQueryable`1 source, Int32 pageNumber, Int32 pageSize) in MyProject\Shared\Models\PaginatedList.cs:line 0
         at MyProject.Shared.Behaviours.ValidationBehaviour`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next) in MyProject\Shared\Behaviours\ValidationBehaviour.cs:line 35
         at MyProject.Shared.Behaviours.UnhandledExceptionBehaviour`2.Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate`1 next) in MyProject\Shared\Behaviours\UnhandledExceptionBehaviour.cs:line 18

可能 EF Core 无法从匿名对象为 .ToString() 创建投影。

尝试删除 .ToString(),如果需要,post 在客户端实现后处理记录。