When I write a Group By
in query expression syntax, the compiler automatically picks Enumerable.GroupBy
as my intended tareget method and I get an IEnumerable
back instead of an IQueryable
. That means a subsequent g.Sum
call (inside of my Select
) expects a Func(Of TSource, int)
instead of an Expression(Of Func(Of TSource, int))
. Is there a way to force the Group By
to use Queryable.GroupBy
instead and give me back an IQueryable
?
Contrived Sample Code
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
Why would I want to do this?
The compiler automatically converts between a lambda and an expression based on the target variable type (ie, both Dim f As Func(Of String, Integer) = Function(x) x.Length()
and Dim e As Expression(Of Func(Of String, Integer)) = Function(x) x.Length()
are valid) so there is no noticable difference in the code between an IEnumerable
and IQueryable
.
The problem is, LINQ to Entities (and I assume other db backed LINQ implementations) relies on expression trees to translate into SQL. That means the IEnumerable
lambda version will not work against an IDbSet
as I found in this old question.
The problem is that Queryable.GroupBy()
returns IQueryable<IGrouping<TKey, TSource>>
, where IGrouping<TKey, TSource>
implemens IEnumerable<TSource>
, but not IQueryable<TSource>
.
And I believe your code wouldn't work anyway, because ItemsOfColor()
wouldn't be actually called. Instead, the EF would get an expression that calls ItemsOfColor()
. And since it doesn't know that method, it would throw an exception.