EF Core 3.1 意外 SQL 组合连接和分组依据时生成

EF Core 3.1 unexpected SQL generation when combine join and group by

我有一段 C# 代码(使用 EF Core 3.1)执行 SQL 左连接操作。

var groupedQuery = query.GroupBy(x => x.CreatedTime.Date)
    .Select(o => new
    {
        Date = o.Key,
        Count = o.Count()
    });

var acceptedGroupedQuery = query.Where(o => o.Accepted).GroupBy(x => x.CreatedTime.Date)
    .Select(o => new
    {
        Date = o.Key,
        Count = o.Count()
    });

var projectedQuery = groupedQuery.GroupJoin(acceptedGroupedQuery, o => o.Date, i => i.Date,
        (o, i) => new { Total = o, Accepted = i })
    .SelectMany(o => o.Accepted.DefaultIfEmpty(), (joined, accepted) => new 
    {
        Date = joined.Total.Date,
        Total = joined.Total.Count,
        Accepted = accepted.Count
    });

var result = await projectedQuery
    .Skip(model.Skip).Take(model.Take).ToArrayAsync(cancellationToken: cancellationToken);

对应的SQL代为

exec sp_executesql N'SELECT [t].[c] AS [Date], CAST([t].[c0] AS float) AS [Total], CAST([t0].[c0] AS float) AS [Accepted]
FROM (
    SELECT CONVERT(date, [p].[CreatedTime]) AS [c], COUNT(*) AS [c0]
    FROM [PartnerInvitation] AS [p]
    WHERE [p].[DeletedTime] IS NULL
    GROUP BY CONVERT(date, [p].[CreatedTime])
) AS [t]
LEFT JOIN (
    SELECT CONVERT(date, [p0].[CreatedTime]) AS [c], [t].[c0]
    FROM [PartnerInvitation] AS [p0]
    WHERE [p0].[Accepted] = 1 
    GROUP BY CONVERT(date, [p0].[CreatedTime])
) AS [t0] ON [t].[c] = [t0].[c]
ORDER BY (SELECT 1)
OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY',N'@__p_0 int,@__p_1 int',@__p_0=0,@__p_1=10

上述查询给出了以下错误:

Msg 4104, Level 16, State 1, Line 9. The multi-part identifier "t.c0" could not be bound.

我希望左连接中的第二个 select 语句是 SELECT ..., COUNT(*) as [c0] 而不是 SELECT ..., t.[c0]

知道这里发生了什么以及如何解决吗?

Any idea what happened here

显然是 EF Core 3.x 错误 - 在 EF Core 5.x 中相同的查询得到预期的正确翻译。

how to solve it?

修复库错误基本上是不可能的。好的是它是固定的,坏的是它在 v5.x 中固定而不是在 v3.1 中 - 它出现在最新的 v3.1.14 中,并且因为他们已经在 v6 上工作.0,我不认为它会在 v3.1 中修复。

所以一个选择是升级到最新的 v5.x。

另一种选择,但仅针对此特定查询是以不使用连接的方式重写它 - 它所做的可以通过单个 GroupBy 查询和条件 Sum (在 v5.x 中你也可以使用条件 Count),例如摆脱 groupedQueryacceptedGroupedQuery 并只做

var projectedQuery = query
    .GroupBy(e => e.CreatedTime.Date)
    .Select(g => new
    {
        Date = g.Key,
        Total = g.Count(),
        Accepted = g.Sum(e => e.Accepted ? 1 : 0)
    });