Я пытаюсь создать дерево выражений, чтобы создать лямбду, которую можно использовать в предложении EntityFramework Where. Мне нужно проверить значение null, и я пытаюсь использовать is null. Что-то вроде этого:
var param = Expression.Parameter(typeof(Customer), "data");
var fieldExpression = Expression.Property(param, "Address");
var nullTest = Expression.IsNull(fieldExpression);
var lambda = Expression.Lambda(nullTest, param);
var compiled = lambda.Compile() as Func<Customer, bool>;
using dbContext = new TestDbContext();
var customersWithNullAddress = dbContext.Customers.Where(compiled);
Здесь предполагается, что у dbContext есть DbSet<Customer>, а у Customer есть свойство, называемое Address. Цель состоит в том, чтобы иметь это:
var customersWithNullAddress = dbContext.Customers.Where(c => c.Address is null);
Но мне нужно динамически генерировать предикат, поскольку он исходит из пользовательского интерфейса, который позволяет пользователю динамически создавать условие фильтра.
Конечно, это не работает, потому что Expression.IsNull не существует. Кажется, я не могу найти какой-либо механизм для этого в деревьях выражений. Я думаю, я могу сделать
Expression.Equal(fieldExpression, Expression.Constant(null, typeof(Address))
Но это больше не похоже на рекомендуемый способ проверки нуля, и я хочу быть уверен, что он преобразуется в правильный SQL как SELECT * FROM Customer WHERE Address is null
Кто-нибудь может выполнить это сопоставление с образцом в деревьях выражений?
Кроме того, «Но это больше не похоже на рекомендуемый способ проверки нуля» довольно спорно.
Операция is null в C# — это синтаксический сахар, который был добавлен задолго до того, как были созданы деревья выражений LINQ. В обычном коде он компилируется в тот же код IL (по крайней мере, в большинстве случаев), что и == null, поэтому на данный момент нет особого смысла добавлять синтаксис в деревья выражений.
Что касается того, как он преобразуется в SQL, == null всегда преобразовывался в IS NULL в SQL со старых добрых дней LinqToSQL. Может быть еще несколько способов заставить некоторые преобразования SQL привести к = NULL — что, конечно, всегда ложно — но вам нужно действительно попытаться вызвать один из них.
Поэтому, если вы просто ищете гарантии того, что литерал something == null всегда будет переводиться в something IS NULL в SQL для EF (или LinqToSQL, или NHibernate, или Linq2DB, или...), вы его получили. Слишком много кода могло бы сильно сломаться, если бы не работало таким образом.
== null
уже преобразуется в правильныйis null
в SQL, поэтому просто используйтеExpression.Equal
, как вы показали в вопросе.