I want to make a dynamic check for a null value. I want to make a where clause which will compare only the date part of the date field.
It will work for non nullable date fields, but for nullable date fields we need to check for value as using .Date on null data will throw an error
let us say
p => (p.Date.Value == null ? null : p.Date.Value.Date) == SelectedDate.Date
or
p => ( p.Date.Value == null ? p.Date.Value : p.Date.Value.Date) == SelectedDate.Date
or
p => (p.Date.Value == null ? p.Date : p.Date.Value.Date) == SelectedDate.Date
basically a null checking ternary operator which selects only the date part of
I already tried
ConstantExpression argument = Expression.Constant(MyDateField, typeof(DateTime));
ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
string field = "Date";
BinaryExpression condition = Expression.Equal(Expression.Property(parameter, field), Expression.Constant(null, typeof(DateTime?)));
ConditionalExpression ternary = Expression.Condition(condition, property, Expression.Property(property, "Date"));
Expression equalExp = Expression.Equal(ternary, argument);
lambda = Expression.Lambda<Func<T, bool>>(equalExp, parameter);
Which gives me
p => (IIF((p.EventDate == null), p.EventDate.Value, p.EventDate.Value.Date) == 21-Jun-18 12:00:00 AM)
but this is not working. Issue I'm facing is
If I use p.Date.Value in the BinaryExpression then it doesnot allow as .Value makes it DateTime and null is only available in DateTime?
IIF
condition is generated and not ?:
ternary operator
Any and all help is appreciated.
The DateTime?
and DateTime
are different types. While the C# compiler does some implicit conversions sometimes (for example when you compare them with ==
), with Lambda Expressions you have to make explicit casts. And to get the value of a DateTime?
you have to use the .Value
property.
public static Expression<Func<T, bool>> MakeExpression<T>(DateTime myDateField)
{
ConstantExpression argument = Expression.Constant(myDateField, typeof(DateTime));
ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
string propertyName = "Date";
Expression property = Expression.Property(parameter, propertyName);
BinaryExpression condition = Expression.Equal(property, Expression.Constant(null, typeof(DateTime?)));
Expression propertyValue = Expression.Property(property, nameof(Nullable<DateTime>.Value));
Expression propertyValueDate = Expression.Property(propertyValue, nameof(DateTime.Date));
ConditionalExpression ternary = Expression.Condition(condition, Expression.Constant(null, typeof(DateTime?)), Expression.Convert(propertyValueDate, typeof(DateTime?)));
Expression argumentDate = Expression.Property(argument, nameof(DateTime.Date));
Expression equalExp = Expression.Equal(ternary, Expression.Convert(argumentDate, typeof(DateTime?)));
var lambda = Expression.Lambda<Func<T, bool>>(equalExp, parameter);
return lambda;
}
Note that Nullable<>
defines a HasValue
property, instead of comparing the value with null
... So you could:
public static Expression<Func<T, bool>> MakeExpression<T>(DateTime myDateField)
{
ConstantExpression argument = Expression.Constant(myDateField, typeof(DateTime));
ParameterExpression parameter = Expression.Parameter(typeof(T), "p");
string propertyName = "Date";
Expression property = Expression.Property(parameter, propertyName);
Expression propertyHasvalue = Expression.Property(property, nameof(Nullable<DateTime>.HasValue));
Expression propertyValue = Expression.Property(property, nameof(Nullable<DateTime>.Value));
Expression propertyValueDate = Expression.Property(propertyValue, nameof(DateTime.Date));
ConditionalExpression ternary = Expression.Condition(Expression.Not(propertyHasvalue), Expression.Constant(null, typeof(DateTime?)), Expression.Convert(propertyValueDate, typeof(DateTime?)));
Expression argumentDate = Expression.Property(argument, nameof(DateTime.Date));
Expression equalExp = Expression.Equal(ternary, Expression.Convert(argumentDate, typeof(DateTime?)));
var lambda = Expression.Lambda<Func<T, bool>>(equalExp, parameter);
return lambda;
}