我想对空值进行动态检查。 我想创建一个where子句,该子句将仅比较date字段中的日期部分。
它适用于不可为空的日期字段,但对于可为空的日期字段,我们需要检查值,因为使用.Date来处理无效数据会引发错误
让我们说
p => (p.Date.Value == null ? null : p.Date.Value.Date) == SelectedDate.Date
或
p => ( p.Date.Value == null ? p.Date.Value : p.Date.Value.Date) == SelectedDate.Date
或
p => (p.Date.Value == null ? p.Date : p.Date.Value.Date) == SelectedDate.Date
基本上是一个空值检查三元运算符,它仅选择
的日期部分我已经尝试过
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);
哪个给我
p => (IIF((p.EventDate == null), p.EventDate.Value, p.EventDate.Value.Date) == 21-Jun-18 12:00:00 AM)
但是这不起作用。 我面临的问题是
如果我在BinaryExpression中使用p.Date.Value,那么它将不允许使用,因为.Value将其设置为DateTime,而null仅在DateTime中可用?
IIF
条件会生成,而不是?:
三元运算符
感谢您的帮助。
答案 0 :(得分:3)
DateTime?
和DateTime
是不同的类型。尽管C#编译器有时会进行一些隐式转换(例如,将它们与==
进行比较),但是对于Lambda表达式,您必须进行显式转换。要获得DateTime?
的值,您必须使用.Value
属性。
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;
}
请注意,Nullable<>
定义了HasValue
属性,而不是将值与null
进行比较...因此,您可以:
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;
}
答案 1 :(得分:3)
假设我们有两个表达式left
和right
,其中right
类型是DateTime
,我们想比较它们是否相等。
当left
类型为DateTime
时,比较很简单
left == right
并且当left
类型为DateTime?
时,则
(left == (DateTime?)null ? (DateTime?)null : (DateTime?)left.Value.Date) == (DateTime?)right
我专门添加了必需的演员表。 C#编译器隐式地执行其中的一些操作(如(DateTime?)null
),但重要的是三元运算符的结果类型应为DateTime?
,因此三元运算符的操作数类型分别为和操作数类型也必须为DateTime?
。
话虽如此,让我们将上述规则翻译为代码:
static Expression<Func<T, bool>> DateEquals<T>(string memberName, DateTime value)
{
var parameter = Expression.Parameter(typeof(T), "p");
Expression left = Expression.PropertyOrField(parameter, memberName);
Expression right = Expression.Constant(value.Date);
if (left.Type == typeof(DateTime?))
{
var leftValue = Expression.Property(left, "Value");
var nullValue = Expression.Constant(null, typeof(DateTime?));
left = Expression.Condition(
Expression.Equal(left, nullValue),
nullValue,
Expression.Convert(Expression.Property(leftValue, "Date"), typeof(DateTime?))
);
right = Expression.Convert(right, typeof(DateTime?));
}
var condition = Expression.Equal(left, right);
return Expression.Lambda<Func<T, bool>>(condition, parameter);
}
(不必担心在调试显示中看到IIF
。显示为Conditional
的{{1}}表达式确实等同于C#IIF
运算符)
答案 2 :(得分:0)
我想您的p.Date
是DateTime?
(或Nullable<DateTime>
)
p => p.Date?.Date == SelectedDate.Date
答案 3 :(得分:0)
最终起作用的是
public static Expression<Func<T, bool>> MakeExpression<T>(DateTime myDateField, string fieldName)
{
var parameter = Expression.Parameter(typeof(T), "p");
var property = Expression.Property(parameter, fieldName);
var fieldType = property.Type;
Expression<Func<T, bool>> lambda = null;
if (fieldType == typeof(DateTime?))
{
var truncateTimeMethod = typeof(DbFunctions).GetMethod("TruncateTime", new[] { fieldType });
if (truncateTimeMethod != null)
{
var propertyHasvalue = Expression.Property(property, nameof(Nullable<DateTime>.HasValue));
var truncateTimeMethodCall = Expression.Call(truncateTimeMethod, property);
var ternary = Expression.Condition(Expression.Not(propertyHasvalue), property, truncateTimeMethodCall);
var argument = Expression.Constant(myDateField.Date, typeof(DateTime?));
var equalExp = Expression.Equal(ternary, argument);
lambda = Expression.Lambda<Func<T, bool>>(equalExp, parameter);
}
}
return lambda;
}
感谢@xanatos
用于.Date功能
var truncateTimeMethod = typeof(DbFunctions).GetMethod("TruncateTime", new[] { fieldType });
var truncateTimeMethodCall = Expression.Call(truncateTimeMethod, property);
用于三元操作
var ternary = Expression.Condition(Expression.Not(propertyHasvalue), property, truncateTimeMethodCall);