Linq Expression for DateTime Equality Nullable Issue

时间:2017-03-01 14:30:37

标签: c# entity-framework linq

我正在尝试使用以下代码片段从SQL Server搜索DateTime数据字段:

DateTime toDate = DateTime.Parse("14-11-2016");

如您所见,toDate字段不为空。

var maxComparisonExpression = Expression.Equal(Expression.Call(
                Expression.Invoke(searchColumnName, row),
                typeof(DateTime).GetMethod("CompareTo", new[] { typeof(DateTime) }),
                Expression.Constant(toDate, typeof(DateTime))),
                Expression.Constant(0, typeof(DateTime)));

当此代码粗鲁时,执行maxComparisonExpression时会显示以下错误。

Method 'Int32 CompareTo(System.DateTime)' declared on type 'System.DateTime' cannot be called with instance of type 'System.Nullable`1[System.DateTime]'

到目前为止,我已将typeof(DateTime)更改为typeof(DateTime?),这没有效果。

我认为它与第二个参数

有关
Expression.Constant(0, typeof(DateTime))

但我看不出如何解决这个问题。任何人都可以向我展示一些解决这个问题的方法吗?

更新:

我有一个用于高级搜索的页面。在这个页面上有超过20个搜索字段,每个搜索字段都有一个选择下拉列表,提供比较运算符,如:equals,less than,greater then等。

所以我正在编写一些表达式来处理特定的数据类型。这个时间将使用通用模式转换为库。

使用以下代码定义[field] == fromInt在Linqpad中执行正常

int fromInt = 101462975;

Expression<Func<Table_Name, int>> searchColumnName = x => x.Id;

IQueryable<Table_Name> retval = Entities.Table_Name.AsQueryable();

var row = Expression.Parameter(typeof(Table_Name), "Table_Name");

var ComparisonExpression = Expression.Equal(Expression.Call(
                           Expression.Invoke(searchColumnName, row),
                           typeof(int).GetMethod("CompareTo", new[] { typeof(int) }),
                           Expression.Constant(fromInt)),
                           Expression.Constant(0, typeof(int)));

因此,假设将int的数据类型更改为DateTime的假设是前进的方法。

LinqPad的完整代码是:

DateTime? toDate = DateTime.Parse("14-11-2016");

Expression<Func<Table_Name, DateTime?>> searchColumnName = x => x.Created_date;

IQueryable<Table_Name> retval = Entities.Table_Name.AsQueryable();

var row = Expression.Parameter(typeof(Table_Name), "Table_Name");

var ComparisonExpression = Expression.Equal(Expression.Call(
                           Expression.Invoke(searchColumnName, row),
                           typeof(DateTime).GetMethod("CompareTo", new[] { typeof(DateTime) }),
                           Expression.Constant(toDate, typeof(DateTime))),
                           Expression.Constant(0, typeof(DateTime)));

我尝试将上面的行更改为

Expression.Constant(0));

但是这只会抛出同样的错误,然后我将常量替换为null值给我:

var ComparisonExpression = Expression.Equal(Expression.Call(
                           Expression.Invoke(searchColumnName, row),
                           typeof(DateTime).GetMethod("CompareTo", new[] { typeof(DateTime) }),
                           Expression.Constant(toDate, typeof(DateTime))),
                           null);

虽然这不起作用,但提供的错误表明它不喜欢null值参数。

我遇到了以下链接How to compare only date part with linq expression?

我已经尝试了这里建议的内容,它表明需要在操作之间进行操作。也没用。

1 个答案:

答案 0 :(得分:1)

CompareTo的结果是整数,但您希望将结果与DateTime进行比较:

Expression.Constant(0, typeof(DateTime /* oops */))

这没有意义,是吗?与int

比较
Expression.Constant(0, typeof(int))

在这种情况下,您可以简单地省略类型:

Expression.Constant(0)

另一个问题是Expression.Invoke(searchColumnName, row)会返回DateTime?,而不是DateTime。你必须以这种或那种方式进行转换。您可以添加GetDateTimeValue方法:

var ComparisonExpression = Expression.Equal(Expression.Call(
                           GetDateTimeValue(Expression.Invoke(searchColumnName, row)),
                           typeof(DateTime).GetMethod("CompareTo", new[] { typeof(DateTime) }),
                           Expression.Constant(toDate, typeof(DateTime))),
                           null);

GetDateTimeValue的位置:

private readonly static MethodInfo nullableDateTimeGetValueOrDefaultMethodInfo = typeof(DateTime?).GetMethod(nameof(Nullable<DateTime>.GetValueOrDefault), new Type[] { });

private static Expression GetDateTimeValue(Expression expr)
{
    return Expression.Call(expr, nullableDateTimeGetValueOrDefaultMethodInfo);
}