Я строию Expression
, который должен представлять собой сравнение свойств и констант Nullable<long>
. Другими словами, компиляция выражения должна возвращать лямбда, подобную x => (x.Id == value)
, где оба Id
и value
имеют тип long?
.Linq Expression throws InvalidOperationException
Это код:
private static Expression<Func<T, bool>> GetNullableIdEqualsQuery(long? value)
{
var type = typeof(T);
var idProperty = type.GetProperty("Id");
var xParam = Expression.Parameter(type, "x");
var block = Expression.Block(
typeof(bool),
Expression.Equal(
Expression.Property(xParam, idProperty),
Expression.Constant(value, typeof(long?)))
);
return Expression.Lambda<Func<T, bool>>(block, xParam);
}
Но при использовании в запросе, он не с InvalidOperationException
:
System.InvalidOperationException: переменная
'x'
типа'SomeEntity'
ссылочного из сферы''
, но он не определен.
Что я делаю неправильно?
[Редактировать]
Благодаря @ MarcGravell Ответим, я исправил код. Я предполагаю, что что-то было нарушено в LINQ-провайдере NHibernate, но сейчас у меня нет времени для дальнейшего расследования.
Если кому-то нужен универсальный вариант, который будет (ну, должен) работать на любой тип недвижимости, здесь:
public static Expression<Func<Tobj, bool>> GetEqualsQuery<Tobj, Tprop>(Tprop value, string propertyName)
{
var type = typeof(Tobj);
var property = type.GetProperty(propertyName);
var propertyType = property.PropertyType;
if (propertyType != typeof(Tprop))
throw new InvalidOperationException("Property type ({0}) does not match the value type ({1})"
.FormatWith(propertyType, typeof(Tprop)));
var xParam = Expression.Parameter(type, "x");
var body = Expression.Equal(
Expression.Property(xParam, property),
Expression.Constant(value, propertyType)
);
return Expression.Lambda<Func<Tobj, bool>>(body, xParam);
}
Test (для лямбды скомпилированных версий):
[TestClass]
public class ExpressionHelperTest
{
class Test
{
public long Id { get; set; }
}
[TestMethod]
public void GetEqualsQueryWorksForSimpleTypes()
{
// create a query for the lambda x => x.Id == 5
var lambda = ExpressionHelper
.GetEqualsQuery<Test, long>(5, "Id")
.Compile();
Assert.IsTrue(lambda(new Test() { Id = 5 }));
Assert.IsFalse(lambda(new Test() { Id = 8 }));
}
}
Я думаю, что код в вашем примере работает нормально; возможно ли, что в коде * real * вы не подаете параметр в выражение (в вызове 'Lambda'), или, возможно, вы переписываете выражение без подстановки параметров? –
@Marc: на самом деле, я передавал его NHibernate (не совсем последняя сборка), поэтому возможно, что проверка «null» не реализована должным образом в их поставщике (как вы упомянули ниже). – Groo