我有以下数据模型,我需要将符合以下条件的ResponseItem个数据模型分组:

  • First:Group by ResponseItem.Group
  • Second: Group by 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();
}

但我得到了一个错误:

‘无法转换LINQ表达式’ProjectionBindingExpression:0‘.以可翻译的形式重写查询,或者通过插入对‘AsEnumerable’、‘AsAsyncEnumerable’、‘ToList’或‘ToListAsync’的调用显式切换到客户端计算

正如我在标题中提到的,我在.NET6上使用实体框架.

另一方面,如果我不考虑第二个GROUP BY,则查询可以正常工作:

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核心限制.但在这种情况下不是这样.

对于该特定查询,投影看起来是多余的,因为组中元素的类型与投影类型相同,因此只需将其删除即可

.GroupBy(i => new { i.SubGroup })
.Select(grp => grp.First()) // <-- final projection
.ToList()

因此,这是解决方案/变通方法之一.如果确实需要投影,因为您 Select 的是部分柱或投影到其他类型,则将其移动到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()

Csharp相关问答推荐

.NET将复杂的Dto序列化为SON字符串

从C#重新启动Shell脚本时处理错误?

当MD5被废弃时,如何在Blazor WASM中使用它?

我可以 suppress 规则CS 9035一次吗?

S能够用DATETIME来计算,这有什么错呢?

Azure函数中实体框架核心的依赖注入

TeamsBot SendActivityActivityTypes与ActivityTypes同步.键入不再起作用

调用Task.Run()与DoSomethingAsync()有什么不同?

显示文档的ECDsa签名PDF在Adobe Reader中签名后已被更改或损坏

在不添加不必要的尾随零的情况下本地化浮点型?

.NET:从XPath定位原始XML文档中的 node

如何在.NET AOT中为所有枚举启用JsonStringEnumConverter

使用switch 类型模式时出现奇怪的编译器行为

是否可以在Entity Framework Core中使用只读 struct 作为拥有实体?

C#如何获取字符串中引号之间的文本?

为什么在使用JsonDerivedType序列化泛型时缺少$type?

FakeItEasy自动嘲弄内容

为什么我可以在注册表编辑器中更改值,但不能在以管理员身份运行的C#表单应用程序中更改?

Xamarin Forms应用程序中登录页面的用户名和密码编辑文本之间不需要的空格

.NET8支持Vector512,但为什么向量不能达到512位?