Нужно ли не использовать методы в запросах LINQ?

В следующем коде есть разница, когда я помещаю «dl.DamageCount> 5» непосредственно в запрос или когда я перемещаю «dl.DamageCount> 5» в метод или функцию, а затем просто вызываю его из запроса?

Кажется, когда я перемещаю его в метод, запрос не работает должным образом. Действительно, кажется, что функция/метод всегда возвращает true независимо от оценки условия. Я использую Linq-to-NHibernate.

 var q = from dl in session.Linq<DamageList>()
            where
            dl.DamageCount > 5

person Afshar Mohebi    schedule 21.02.2010    source источник


Ответы (1)


Лучшее, что вы можете сделать, это зафиксировать предикат в Expression<>. Метод уже скомпилирован в IL и поэтому не может быть выделен провайдером Linq.

Expression<Func<DamageList, bool>> predicate = item => item.DamageCount > 5;

Затем вы можете передать этот предикат непосредственно в Where:

var q = session.Linq<DamageList>().Where(predicate);

Если вы хотите динамически объединить два таких выражения, вы либо записываете код для обоих в одно выражение, либо записываете оба в отдельные выражения. Это усложняется, потому что вам нужно, чтобы каждый из них ссылался на передаваемый item. Это действительно другой вопрос, который уже задан: Как динамически создать предикат Expression‹Func‹MyClass, bool››?

Вы можете написать составной предикат, используя оператор &&, и при этом зафиксировать его в выражении:

Expression<Func<DamageList, bool>> predicate = 
    dl => dl.DamageCount > 5 && dl.Name.Contains(criteria);

Вы спрашиваете о вызове методов в таком выражении — ну, этот пример действительно вызывает метод!

Он строит дерево из Expression узлов различных типов. Где-то будет включен узел вызова метода, в котором говорится о вызове метода Contains для string (при условии, что Name является string). Итак, это пример инструкции вызова метода, встроенной в выражение. Чтобы это работало, поставщик Linq должен знать, что делает этот метод, чтобы он мог преобразовать его в эквивалентный SQL (как в случае с типичной системой ORM).

Таким образом, вы можете встраивать определенные стандартные вызовы методов в выражения — для этого требуется, чтобы провайдер Linq знал о них. Методы string хорошо определены, но не каждый провайдер обязательно сможет работать со всеми из них.

Для провайдера Linq не было бы невозможно разрешить вам добавлять свои собственные расширения, которые обрабатывают дополнительные методы, но я не знаю ни одного, поддерживающего это (очевидно, если система с открытым исходным кодом, вы можете добавить свои собственные).

Подводя итог, поставщику Linq требуется дерево узлов выражений, которое он может анализировать для преобразования в какой-либо другой язык, например SQL, для выполнения в другом контексте, например, внутри удаленной базы данных. Если вы пишете обычные методы, компилятор C# скомпилирует их в низкоуровневый исполняемый IL, а не в узлы выражений. Так что это похоже на тупик: нет встроенного средства для превращения IL обратно в узлы выражения.

person Daniel Earwicker    schedule 21.02.2010
comment
Тогда как насчет того, что у меня более одного состояния? Например: где dl.DamageCount › 5 && dl.Name.Contains(criteria) - person Afshar Mohebi; 21.02.2010
comment
Уважаемый Earwicker, еще один вопрос: можно ли вызвать другой метод с этим выражением? Я имею в виду следующее: Expression‹Func‹DamageList, bool›› predicate = MyFunc(); - person Afshar Mohebi; 21.02.2010