当我在查询表达式语法中编写Group By
时,编译器自动选择Enumerable.GroupBy
作为我的预期目标方法,并且我得到IEnumerable
而不是IQueryable
。这意味着随后的g.Sum
调用(在我的Select
内部)期望Func(Of TSource, int)
而不是Expression(Of Func(Of TSource, int))
。是否有一种方法可以强制Group By
使用Queryable.GroupBy
,而不是给我一个IQueryable
?
设计样例代码
Dim myQuery = From x In DataSource.Items
Group By x.Key Into g = Group
Select New With {
.Key = Key,
.RedItems = g.Sum(ItemsOfColor(Colors.Red)) '<== invalid because g.Sum expects a lambda
}
Private Function PurpleItems(color As Integer) As Expression(Of Func(Of Item, Integer))
Return Function(item) If(item.Color = color, 1, 0)
End Function
我为什么要这样做?编译器根据目标变量类型自动在lambda和表达式之间进行转换(即Dim f As Func(Of String, Integer) = Function(x) x.Length()
和Dim e As Expression(Of Func(Of String, Integer)) = Function(x) x.Length()
都是有效的),因此IEnumerable
和IQueryable
之间的代码没有明显的差异。
问题是,LINQ到实体(我假设其他数据库支持的LINQ实现)依赖于表达式树来转换为SQL。这意味着IEnumerable
lambda版本将不工作对IDbSet
,因为我发现在这个老问题。
问题是Queryable.GroupBy()
返回IQueryable<IGrouping<TKey, TSource>>
,其中IGrouping<TKey, TSource>
实现IEnumerable<TSource>
,而不是IQueryable<TSource>
。
我相信你的代码无论如何都不会工作,因为ItemsOfColor()
实际上不会被调用。相反,EF将得到一个调用ItemsOfColor()
的表达式。因为它不知道那个方法,它会抛出一个异常