I am building an Expression
which should represent an Equals
comparison of a property and a constant of type Nullable<long>
. In other words, compiling the expression should return a lambda similar to x => (x.Id == value)
, where both Id
and value
are of type long?
.
This is the code:
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);
}
But when used in a query, it fails with an InvalidOperationException
:
System.InvalidOperationException: variable 'x'
of type 'SomeEntity'
referenced from scope ''
, but it is not defined.
What am I doing wrong?
[Edit]
Thanks to @MarcGravell's answer, I've fixed the code. I am presuming that something was broken in the NHibernate's LINQ provider, but right now I don't have the time to investigate further.
If anyone needs a generic version which will (well, should) work for any property type, here it is:
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 (for the lambda-compiled version only):
[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 }));
}
}