c# - Entity Framework 不翻译 Linq 表达式

标签 c# entity-framework-core .net-6.0

我有以下数据模型,我需要根据这些条件对 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/

相关文章:

azure - 更改 .NET 6 隔离函数的 OpenAPI 的默认 url

c# - 如何模拟FeatureFilterEvaluationContext参数?

c# - ShortDayPattern 在指定 CultureInfo 时因构建代理而异

c# - 从 C# 6 中的响应 header 中删除 SERVER

asp.net-mvc - 用于 MVC 和 ASP.NET CORE Lambda 表达式的 Telerik UI

c# - 如何将子实体更改为父实体?

c# - 在 Entity Framework 核心中合并迁移

c# - 捕捉到关注方向的道路

c# - 调整 WP8 WebBrowser 高度以适合内容

c# - 如何从 flowlayoutpanel 更改控件的属性?