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
),例如摆脱 groupedQuery
和 acceptedGroupedQuery
并只做
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)
});
我有一段 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
),例如摆脱 groupedQuery
和 acceptedGroupedQuery
并只做
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)
});