Совместное использование предложения where между операторами LINQ - PullRequest
4 голосов
/ 15 декабря 2011

У меня есть несколько запросов LINQ-to-Entities, которые попадают в те же две таблицы и имеют одинаковые условия. Я пытаюсь поделиться предложением where между несколькими запросами. Например, скажем, у меня есть это:

from t0 in db.Table0
from t1 in db.Table1
from t2 in db.Table2
where t0.Field7 == 'something' 
    && t1.Field1 > t2.Field3 
    && t2.NavigationProperty(t => t.Field4 == t1.Field2).Any()
select t0

Я бы хотел сказать что-то вроде этого:

Func<Table1, Table2, bool> specialCondition
    = (t1, t2) => t1.Field1 > t2.Field3 
        && t2.NavigationProperty(t => t.Field4 == t1.Field2).Any();

from t0 in db.Table0
from t1 in db.Table1
from t2 in db.Table2
where t0.Field7 == 'something' && specialCondition(t1, t2)
select t1

Это генерирует The LINQ expression node type 'Invoke' is not supported in LINQ to Entities., который имеет смысл. Он не может анализировать произвольный код функции / делегата .NET во что-то, что он может передать в базу данных.

Все, что я читал в Интернете, говорит, что деревья выражений, однако, могут работать очень хорошо. Моя проблема в том, что я могу объявить это (это почти такой же синтаксис, что и функция), но я не знаю, как его использовать.

Expression<Func<Table1, Table2, bool>> specialCondition
    = (t1, t2) => t1.Field1 > t2.Field3 
        && t2.NavigationProperty(t => t.Field4 == t1.Field2).Any();

Что мне с этим делать? Как передать его в LINQ2EF?

Обновление: Рабочее решение с LinqKit в соответствии с рекомендациями @Mic, полученное из NuGet (обратите внимание на .AsExpandable() и .Invoke, а также на импортированную импортированную ссылку и пространство имен LinqKit):

Expression<Func<Table1, Table2, bool>> specialCondition
    = (t1, t2) => t1.Field1 > t2.Field3 
        && t2.NavigationProperty(t => t.Field4 == t1.Field2).Any();

from t0 in db.Table0.AsExpandable()
from t1 in db.Table1
from t2 in db.Table2
where t0.Field7 == 'something' && specialCondition.Invoke(t1, t2)
select t1

При проверке в LinqPad как первая полностью встроенная версия, так и окончательная версия выражения LinqKit генерируют одинаковые SQL и результаты. Большое спасибо всем за ваши предложения и помощь.

Ответы [ 3 ]

3 голосов
/ 15 декабря 2011

Такие конструкции невозможны в собственном поставщике L2S / L2Entities. Вы должны использовать библиотеку LINQKit , которая поддерживает расширение выражений.

1 голос
/ 15 декабря 2011

Создайте делегата, используя CompiledQuery. Я уверен, что это работает в LINQ to Entities. Вам просто нужно включить тип DataContext в качестве первого параметра.

Func<MyDataContext, Table1, Table2, bool> specialCondition =
    CompiledQuery.Create(
        (MyDataContext dc, Table1 t1, Table2 t2) =>
            t1.Field1 > t2.Field3
         && t2.NavigationProperty(t => t.Field4 == t1.Field2).Any());

Затем, чтобы использовать его, вы должны быть в состоянии сделать это:

var query =
    from t0 in db.Table0
    from t1 in db.Table1
    from t2 in db.Table2
    where t0.Field7 == 'something' && specialCondition(db, t1, t2)
    select t1
0 голосов
/ 15 декабря 2011

Перепишите запрос LINQ в синтаксис выражения LINQ и передайте выражение в Where(expression).

...