Хорошо, вот сделка: dataContext.Table1s
имеет тип IQueryable<T>
. IQueryable<T>
определяет Where
и Any
методы, которые принимают предикат типа Expression<Func<T, bool>>
. Оболочка Expression<>
имеет решающее значение, поскольку именно она позволяет LINQ to SQL преобразовывать лямбда-выражение в SQL и выполнять его на сервере базы данных.
Однако IQueryable<T>
также включает IEnumerable<T>
. IEnumerable<T>
также определяет методы Where
и Any
, но версия IEnumerable принимает предикат типа Func<T, bool>
. Поскольку это скомпилированная функция, а не выражение, ее нельзя преобразовать в SQL. В результате этот код ...
Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table1s.Where(lambda);
... извлечет КАЖДУЮ запись из Table1s
в память, а затем отфильтрует записи в памяти. Это работает, но это действительно плохие новости, если ваш стол большой.
Func<Table1, bool> lambda = x => x.Id > 1000;
var result = dataContext.Table2s.Where(x => x.Table1s.Any(lambda));
Эта версия имеет два лямбда-выражения. Второй, передаваемый непосредственно в Where
, это Expression
, который включает ссылку на Func
. Вы не можете смешать два, и полученное сообщение об ошибке говорит о том, что вызов Any
ожидает Expression
, но вы передаете Func
.
var result = dataContext.Table2s.Where(x => x.Table1s.Any(y => y.Id > 1000));
В этой версии ваша внутренняя лямбда автоматически преобразуется в Expression
, потому что это единственный выбор, если вы хотите, чтобы ваш код был преобразован в SQL с помощью LINQ to SQL. В других случаях вы заставляете лямбду быть Func
вместо Expression
- в этом случае это не так, поэтому она работает.
Какое решение? На самом деле все довольно просто:
Expression<Func<Table1, bool>> lambda = x => x.Id > 1000;