我有以下数据模型,我需要根据这些条件对 ResponseItem
列表进行分组:
- 首先:
按 ResponseItem.Group 分组
- 第二个:
按 ResponseItem.SubGroup
分组,但只考虑最近的一个,这意味着考虑ResponseItem.CreationDate
代码:
public class ResponseItem
{
public string Group { get; set; }
public string SubGroup { get; set; }
public double Value { get; set; }
public DateTime CreationDate { get; set; }
}
public class GroupedResponseItem
{
public string Group { get; set; }
public List<ResponseItem> Items { get; set; }
}
方法是:
public List<GroupedResponseItem> GetGroupedData( IQueryable<ResponseItem> responseItems )
{
return responseItems
.OrderByDescending(i => i.CreationDate)
.GroupBy(i => i.Group)
.Select(grp => new GroupedResponseItem()
{
Group = grp.Key,
Items = grp
.GroupBy(i => new { i.SubGroup })
.Select(grp => grp.First())
.Select(i => new ResponseItem()
{
SubGroup = i.SubGroup,
CreationDate = i.CreationDate,
Value = i.Value
}).ToList()
})
.ToList();
}
但是我得到一个错误:
'The LINQ expression 'ProjectionBindingExpression: 0' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'
正如我在标题中提到的,我在 .NET 6 上使用 Entity Framework。
另一方面,如果我不考虑第二个分组依据,查询工作正常:
public List<GroupedResponseItem> GetGroupedData(IQueryable<ResponseItem> responseItems)
{
return responseItems
.OrderByDescending(i => i.CreationDate)
.GroupBy(i => i.Group)
.Select(grp => new GroupedResponseItem()
{
Group = grp.Key,
Items = grp
.Select(i => new ResponseItem()
{
SubGroup = i.SubGroup,
CreationDate = i.CreationDate,
Value = i.Value
})
.ToList()
})
.ToList();
}
最佳答案
罪魁祸首似乎是这里的二次投影(Select
)
.GroupBy(i => new { i.SubGroup })
.Select(grp => grp.First()) // <-- (1)
.Select(i => new ResponseItem() // <-- (2)
{
SubGroup = i.SubGroup,
CreationDate = i.CreationDate,
Value = i.Value
})
.ToList()
虽然 EF Core 6.0 改进了 GroupBy
的翻译,在分组结果集上添加了额外的运算符(键/聚合除外,它们具有自然的 SQL 支持),但仍然存在一些限制/缺陷阻止某些翻译结构体。特别是多重投影。
很快,GroupBy
之后的Select
必须是最终的 LINQ 运算符。这有点令人难过,因为中间投影通常有助于翻译,并且通常用于解决 EF Core 限制。但在这种情况下不是。
对于这个特定的查询,投影看起来是多余的,因为组元素的类型与投影类型相同,所以它可以简单地被删除
.GroupBy(i => new { i.SubGroup })
.Select(grp => grp.First()) // <-- final projection
.ToList()
所以这是解决方案/解决方法之一。如果你真的需要一个投影,因为你正在选择部分列,或者投影到不同的类型,那么将它移动到 GroupBy
之后的 Select
中:
.GroupBy(i => new { i.SubGroup })
.Select(grp => grp
.Select(i => new ResponseItem()
{
SubGroup = i.SubGroup,
CreationDate = i.CreationDate,
Value = i.Value
})
.First()
) // <-- final projection
.ToList()
关于c# - Entity Framework 不翻译 Linq 表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73587447/