Reputation: 2246
(This was initially title, Expression Tree Compare DateTime with Nullable DateTime, but as the accepted answer shows, that was not the issue at all.)
I am attempting to build an Expression Tree to compare dates in an Entity Framework query. In the sample below, 'result' is an IQueryable that has been passed in to the method, and DateFilter is an object from a UI that has the nullable DateTime fields, FirstDate, SecondDate, and enums, DateType and DateMode.
I have seen many similar questions, and the common thread seems to be to use Expression.Convert to make sure the dates are of the correct type. However, I'm still doing something wrong, because when I get to the end, instead of (System.Nullable'1[System.DateTime]$x.EffectiveDate >=
... my expression has .Invoke(.Constant<TheClassIAmIn i.e., 'this'+<>c__DisplayClass47_0>('this'+<>c__DisplayClass47_0).resultFunc)(
$x,
...
Here is the complete snippet:
var changeInfo = Expression.Parameter(typeof(MyEntity), "x");
var targetDate = Expression.Property(changeInfo, DateFilter.DateType.ToString());
var dateFilter = Expression.Parameter(typeof(MyDateFilter), "DateFilter");
var firstDate = Expression.Property(dateFilter, "FirstDate");
var secondDate = Expression.Property(dateFilter, "SecondDate");
// Note that FirstDate, SecondDate, and ActionDate are nullable,
// SubmittedDate and EffectiveDate are not.
var ge = Expression.GreaterThanOrEqual(Expression.Convert(targetDate, firstDate.Type), firstDate);
var tree =
Expression.Lambda<Func<MyEntity, MyDateFilter, bool>>
(ge, changeInfo, dateFilter);
var resultFunc = tree.Compile();
result = result.Where(x => resultFunc(x, MyDateFilter));
Upvotes: 0
Views: 55
Reputation: 205629
The problem has nothing in common with DateTime
and Nullable<DateTime>
comparison.
The expression you see is this:
Expression<Func<MyEntity, bool>> expr = x => resultFunc(x, MyDateFilter);
which is lambda expression with parameter x
invoking resultFunc
variable containing delegate of type Func<MyEntity, MyDateFilter, bool>
.
You shouldn't introduce the MyDateFilter
parameter, which produces incompatible lambda expression, shouldn't compile delegates and emit the invocation call expressions at all. Instead, you should build directly a lambda expression of type Expression<Func<MyEntity, bool>>
. The MyDateFilter
value will be passed as Expression.Constant
:
var changeInfo = Expression.Parameter(typeof(MyEntity), "x");
var targetDate = Expression.Property(changeInfo, DateFilter.DateType.ToString());
// Assuming DateFilter is a field/property/variable of type MyDateFilter
var dateFilter = Expression.Constant(DateFilter);
var firstDate = Expression.Property(dateFilter, "FirstDate");
var secondDate = Expression.Property(dateFilter, "SecondDate");
var ge = Expression.GreaterThanOrEqual(
Expression.Convert(targetDate, firstDate.Type),
firstDate);
var predicate = Expression.Lambda<Func<MyEntity, bool>>(
ge, changeInfo);
result = result.Where(predicate);
Upvotes: 4