无法翻译 LINQ 表达式"First()",将在本地进行计算。使用分组时



升级到 ef core 3.0 后。 我在对结果进行分组时遇到问题。 如果我删除分组部分,它可以正常工作。但是,我当然需要获得一笔金额,所以需要它。

IQueryable<ShackGapiModel> models = _context.Offers
.Where(i => i.Amount > 0)
.Select(o => new ShackGapiModel
{
Id = o.Shack.Id,
Title = o.Shack.Title,
AmountOnExchange = o.Amount
})
.GroupBy(i => i.Id)
.Select(s => new ShackGapiModel
{
Id = s.First().Id,
Title = s.First().Title,
AmountOnExchange = s.Sum(a => a.AmountOnExchange)                   
});

原因是 EFCore 无法将 linq 查询转换为 sql 查询。因此,它会将数据放入内存中,然后应用 linq。这是非常消耗内存的事情。

https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/breaking-changes#linq-queries-are-no-longer-evaluated-on-the-client

缓解措施

如果查询无法完全翻译,则重写查询 可以翻译的表单,或使用 AsEnumerable((、ToList(( 或 类似于将数据显式带回客户端,然后可以 使用 LINQ 到对象进一步处理。

作为替代方法,我更喜欢在获取组键以外的值时使用 Max((。

IQueryable<ShackGapiModel> models = _context.Offers
.Where(i => i.Amount > 0)
.GroupBy(i => i.Id)
.Select(s => new ShackGapiModel
{
Id = = s.Key.Value,
Title = s.Max(a => a.title),
AmountOnExchange = s.Sum(a => a.AmountOnExchange)                   
});

我认为您最终想要的实际sql查询是这样的:

SELECT
,   s.Title
,   s.Id
,   Sum(o.Amount) AmountOnExchange
FROM [Offers] o
JOIN [Schack] s ON o.schack_id = s.id
WHERE o.Amount > 0
GROUP BY s.Id, s.Title

在SQL中,您必须按要在选择中引用的每个字段进行分组。 查询优化器足够智能,如果包含 ID,则只需按 ID 进行分组。

将其翻译回 Linq,你会得到类似的东西:

var models = _context.Offers
.Where(o => o.Amount > 0)
.GroupBy(o => new {o.Shack.Id, o.Shack.Title})
.Select(group => new ShackGapiModel
{
Id = = group.Key.Id,
Title = group.Key.Title,
AmountOnExchange = group.Sum(o => o.Amount)                   
});

var models = 
from o in _context.Offers
where o.Amount > 0
group o by new {o.Shack.Id, o.Shack.Title} into g
select new ShackGapiModel
{
Id = = g.Key.Id,
Title = g.Key.Title,
AmountOnExchange = g.Sum(o => o.Amount)                   
};

最新更新