LINQ-to-Objects - 不能按对象分组

Posted

技术标签:

【中文标题】LINQ-to-Objects - 不能按对象分组【英文标题】:LINQ-to-Objects - cannot group by Object 【发布时间】:2021-03-17 10:56:32 【问题描述】:

我将 efcore 2.2 升级到 5 并且 simple group by 不起作用, 数据已经在内存中了,看一下:

List<IGrouping<Categories, Businesses>> businessesByCategory = 
    location.Businesses
            .GroupBy(x => x.Category.Parent ?? x.Category)
            .ToList();

在 Ef Core 2.2 中它运行良好,业务按其类别分组,现在它什么都不做。

如果我尝试按 id 分组,它会起作用:

List<IGrouping<int, Businesses>> businessesByCategory = location.Businesses
    .GroupBy(x => x.Category.ParentId ?? x.CategoryId)
   .ToList();

但我需要 Category 实体,这样我只能获得类别 ID。

【问题讨论】:

不,它根本不起作用。它实际上作为 SQL 毫无意义——你会按什么分组,表名? EF Core 1 受到如此限制,它甚至无法处理 GroupBy,因此所有数据都加载到客户端并在那里分组,而索引没有任何好处。客户端评估是一种丑陋的权宜之计,将被删除。 EF 核心 2.2。 可以处理 GroupBy 但仍允许客户端评估并发出警告。如果您检查了应用程序的日志,您会看到客户端评估警告。 EF Core 3.0 终于禁用了客户端评估 换句话说,代码已经有一个严重的性能和逻辑错误,会发出警告,同时在分组之前将整个表加载到内存中。 EF Core 2.2 警告它,而 EF Core 3 最终禁用它 "数据已经在内存中" 所以不是 EF Core (LINQ to Entities),而是标准的内存中 (LINQ to Objects) GroupBy 操作?如果是,可能您已使用无跟踪查询加载了对象? @IvanStoev 你是对的,没有跟踪 @IvanStoev 是的,这是 LINQ to Objects,它曾经在 2.2 版本中工作,没有跟踪,因为它读取数据而不修改。 【参考方案1】:

此问题是由 EF Core 3.0 无跟踪查询行为重大更改引起的 - No-tracking queries no longer perform identity resolution。因此,具有相同 IdCategory 对象现在是不同的实例,因此 LINQ to Objects GroupBy 使用的默认相等比较器将它们视为不同的键,因此根本不分组。

EF Core 5.0 恢复了 2.x 行为 - No-tracking queries with identity resolution,但您必须选择加入,使用 AsNoTrackingWithIdentityResolution 方法代替 AsNoTracking()。或者QueryTrackingBehavior.NoTrackingWithIdentityResolution,如果设置默认ChangeTracker.QueryTrackingBehavior

【讨论】:

有用的信息!令人抓狂的是,如此关键的行为进入、消失、再次进入。但我对 EF Core 5 最终走上一条不那么反复无常的发展道路感到乐观。是时候了…… @Gert 我对 EF 的体验是从 v6 开始的,它似乎已经调整和完成了大部分功能。但是你可能从一开始就在看它,我猜是从 1 到 6 的所有中间版本,可能它有类似的路径直到最终到达它的样子? 没那么长!我开始使用它,并在它从烧毁的初始版本的灰烬中升起时知道它。所以,是的,当时也是一个试探性的开始,但从第 4 版开始,这是一条稳定的开发路径,几乎没有任何重大变化,只有有用的补充。它一直是一个可靠的工具,直到,是的,你知道的。

以上是关于LINQ-to-Objects - 不能按对象分组的主要内容,如果未能解决你的问题,请参考以下文章

是否可以为 linq-to-objects 编译查询

MySQL 按时间戳分组/排序不能按预期工作

按对象 ID 对字典 NSFetchRequest 进行分组

尝试按对象分组作为键时,字段必须是累加器对象错误

MagicalRecord - 获取按月/年分组的对象

Jquery 或 PHP 按日期字段分组对象数组