Скажем, у меня есть очень простая сущность, подобная этой:
public class TestGuy
{
public virtual long Id {get;set;}
public virtual string City {get;set;}
public virtual int InterestingValue {get;set;}
public virtual int OtherValue {get;set;}
}
Этот придуманный пример объекта отображается с помощью NHibernate (с использованием Fluent) и отлично работает.
Время сделать несколько отчетов. В этом примере «testGuys» - это IQueryable с некоторыми уже примененными критериями.
var byCity = testGuys
.GroupBy(c => c.City)
.Select(g => new { City = g.Key, Avg = g.Average(tg => tg.InterestingValue) });
Это работает просто отлично. В NHibernate Profiler я вижу, что генерируется правильный SQL, и результаты такие же, как и ожидалось.
Вдохновленный моим успехом, я хочу сделать его более гибким. Я хочу сделать его настраиваемым, чтобы пользователь мог получить среднее значение OtherValue, а также InterestingValue. Не должно быть слишком сложно, аргумент для Average () выглядит как Func (так как значения в данном случае являются целочисленными). Очень просто. Разве я не могу просто создать метод, который возвращает Func на основе некоторого условия, и использовать его в качестве аргумента?
var fieldToAverageBy = GetAverageField(SomeEnum.Other);
private Func<TestGuy,int> GetAverageField(SomeEnum someCondition)
{
switch(someCondition)
{
case SomeEnum.Interesting:
return tg => tg.InterestingValue;
case SomeEnum.Other:
return tg => tg.OtherValue;
}
throw new InvalidOperationException("Not in my example!");
}
А потом, в другом месте, я мог бы просто сделать это:
var byCity = testGuys
.GroupBy(c => c.City)
.Select(g => new { City = g.Key, Avg = g.Average(fieldToAverageBy) });
Ну, я думал, что смогу это сделать. Однако, когда я перечисляю это, NHibernate подбрасывает:
Object of type 'System.Linq.Expressions.ConstantExpression' cannot be converted to type 'System.Linq.Expressions.LambdaExpression'.
Так что я предполагаю, что за кулисами происходит какое-то преобразование или приведение или что-то подобное, что в первом случае принимает мою лямбду, но во втором случае превращается во что-то, что NHibernate не может преобразовать в SQL. *
Надеюсь, мой вопрос прост - как моя функция GetAverageField может вернуть что-то, что будет работать в качестве параметра для Average (), когда поддержка NHibernate 3.0 LINQ (метод .Query ()) переводит это в SQL?
Любые предложения приветствуются, спасибо!
1027 * EDIT *
Основываясь на комментариях Дэвида Б. в его ответе, я внимательно посмотрел на это. Мое предположение, что Func будет правильным возвращаемым типом, было основано на значении intellisense, которое я получил для метода Average (). Кажется, он основан на типе Enumerable, а не на Queryable. Это странно .. Нужно присмотреться к вещам.
Метод GroupBy имеет следующую возвращаемую подпись:
IQueryable<IGrouping<string,TestGuy>>
Это значит, что это должно дать мне IQueryable, хорошо. Однако затем я перехожу к следующей строке:
.Select(g => new { City = g.Key, Avg = g.Average(tg => tg.InterestingValue) });
Если я проверяю intellisense для данной переменной внутри нового определения объекта {}, он фактически отображается как имеющий тип IGrouping - NOT IQueryable>. Вот почему вызванный метод Average () является Enumerable и почему он не принимает параметр Expression, предложенный Дэвидом Б.
Так что каким-то образом моя групповая ценность где-то потеряла свой статус IQueryable.
Немного интересная заметка:
Я могу изменить выбор на следующее:
.Select(g => new { City = g.Key, Avg = g.AsQueryable<TestGuy>().Average(fieldToAverageBy) });
А теперь он компилируется! Черная магия! Однако это не решает проблему, так как NHibernate больше не любит меня и дает следующее исключение:
Could not parse expression '[-1].AsQueryable()': This overload of the method 'System.Linq.Queryable.AsQueryable' is currently not supported, but you can register your own parser if needed.
Меня сбивает с толку то, что это работает, когда я передаю лямбда-выражение методу Average (), но я не могу найти простой способ представления того же выражения в качестве аргумента. Я явно делаю что-то не так, но не вижу, что ...!?
Я в своем уме. Помоги мне, Джон Скит, ты моя единственная надежда! ;)