该异常消息是 EF Core 消息,而不是 EF6。
在 EF 6 中,您的表达式应该可以工作,尽管末尾带有 ToList() 之类的东西。我怀疑您遇到的错误是您可能在实现集合之前尝试做更多事情,这与SelectMany 评估的组冲突。
例如,像这样的 EF 可能会例外:
var results = MyTable
.GroupBy(x => x.SomeField)
.OrderBy(x => x.Key)
.Take(5)
.SelectMany(x => x)
.Select(x => new ViewModel { Id = x.Id, Name = x.Name} )
.ToList();
这样的事情应该在哪里起作用:
var results = MyTable
.GroupBy(x => x.SomeField)
.OrderBy(x => x.Key)
.Take(5)
.SelectMany(x => x.Select(y => new ViewModel { Id = y.Id, Name = y.Name} ))
.ToList();
你不想使用:
MyTable.AsEnumerable(). ...
由于这是将整个表具体化到内存中,如果保证表保持相对较小,这可能没问题,但如果生产系统显着增长,它会随着时间的推移形成级联性能下降。
编辑:做了一些挖掘,感谢这篇文章,因为它看起来确实是 EF Core 解析器中的另一个限制。 (不知道如何在 EF6 中工作的东西无法成功集成到 EF Core 中......我猜是在重新发明轮子)
这应该可行:
var results = MyTable
.GroupBy(x => x.SomeField)
.OrderBy(x => x.Key)
.Take(5)
.Select(x => x.Key)
.SelectMany(x => _context.MyTable.Where(y => y.Key == x))
.ToList();
例如,我有一个 Parent 和 Child 表,我想按 ParentId 分组,选取前 5 个父母并选择他们所有的孩子:
var results = context.Children
.GroupBy(x => x.ParentId)
.OrderBy(x => x.Key) // ParentId
.Take(5)
.Select(x => x.Key) // Select the top 5 parent ID
.SelectMany(x => context.Children.Where(c => c.ParentId == x)).ToList();
EF 通过在 DbSet 上针对选定的组 ID 执行 SelectMany 将其重新组合在一起。
感谢此处的讨论:How to select top N rows for each group in a Entity Framework GroupBy with EF 3.1
编辑 2:我看这个越多,感觉就越 hacky。另一种选择是将其分解为两个更简单的查询:
var keys = MyTable.OrderBy(x => x.SomeField)
.Select(x => x.SomeField)
.Take(5)
.ToList();
var results = MyTable.Where(x => keys.Contains(x.SomeField))
.ToList();
我认为这可以翻译您的原始示例,但要点是首先选择适用的 ID/区分键,然后使用这些键查询所需的数据。因此,对于我的前 5 个有孩子的父母的所有孩子:
var parentIds = context.Children
.Select(x => x.ParentId)
.OrderBy(x => x)
.Take(5)
.ToList();
var children = context.Children
.Where(x => parentIds.Contains(x.ParentId))
.ToList();