Могу ли я указать Queryable.GroupBy (вместо Enumerable.GroupBy) в синтаксисе выражения запроса

Когда я пишу 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

Зачем мне это делать? Компилятор автоматически выполняет преобразование между лямбда-выражением и выражением на основе типа целевой переменной (т. е. допустимы как 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 to Entities (и я предполагаю, что другие реализации LINQ, поддерживаемые базой данных) полагаются на деревья выражений для перевода в SQL. Это означает, что лямбда-версия IEnumerable не будет работать против IDbSet, как я нашел в этом старом вопросе. .


person just.another.programmer    schedule 11.04.2013    source источник
comment
Вы пробовали использовать g.AsQueryable().Sum?   -  person Corey Adler    schedule 11.04.2013
comment
@ IronMan84, да, это недоступно как функция   -  person just.another.programmer    schedule 11.04.2013
comment
Какой тип DataSource.Items?   -  person svick    schedule 11.04.2013
comment
@svick IDbSet(Of Item), который реализует IQueryable(Of Item)   -  person just.another.programmer    schedule 11.04.2013


Ответы (1)


Проблема в том, что Queryable.GroupBy() возвращает IQueryable<IGrouping<TKey, TSource>>, где IGrouping<TKey, TSource> реализует IEnumerable<TSource>, но не IQueryable<TSource>.

И я считаю, что ваш код в любом случае не будет работать, потому что ItemsOfColor() на самом деле не будет вызываться. Вместо этого EF получит выражение, вызывающее ItemsOfColor(). И поскольку он не знает этого метода, он выдаст исключение.

person svick    schedule 11.04.2013
comment
Почему тип IGrouping должен иметь значение, если у меня есть IQueryable<IGrouping<TKey, TSource>>? Кроме того, вы правы, это создает выражение MethodCallExpression. Любой способ заставить метод вызываться немедленно (что-то вроде макроса C)? - person just.another.programmer; 12.04.2013
comment
@just.another.programmer Потому что g в вашем коде представляет IGrouping, а не IQueryable (хотя VB, кажется, делает что-то странное, поэтому g на самом деле просто IEnumerable). - person svick; 12.04.2013
comment
Это имеет смысл, но как компилятор узнает, что нужно переводить все в выражения, если это IEnumerable, а не IQueryable? (например, MethodCallExpression, вызывающий мою проблему здесь, или LambdaExpression, который он создает, когда вы передаете лямбду)? - person just.another.programmer; 13.04.2013
comment
@just.another.programmer Поскольку это IEnumerable используется внутри выражения, поэтому не имеет значения, что оно само по себе просто IEnumerable, поскольку коллекция, содержащая его, - это IQueryable. - person svick; 13.04.2013
comment
Во время во время выполнения я мог видеть, что это имеет значение, но, насколько мне известно, перевод в Expression происходит во время во время компиляции. Когда компилятор видит, что IEnumerable вызывает Sum, он ожидает лямбду, поэтому перевода быть не должно. - person just.another.programmer; 13.04.2013
comment
@just.another.programmer Я говорю только о типах времени компиляции. И когда компилятор видит вызов Enumerable.Sum() с лямбдой внутри, которая сама внутри другой лямбды и эта внешняя скомпилирована как выражение, внутренняя лямбда также скомпилирована как выражение. - person svick; 13.04.2013
comment
Отслеживание, которое должно сделать удивительно сложный процесс компиляции. Спасибо. - person just.another.programmer; 13.04.2013