使用 BinaryExpression 解析 DateTime 的日期部分

Parsing Date portion of a DateTime with a BinaryExpression

我找到了类似概念的答案,但 none 似乎符合我的情况。

我正在构建一个对象,该对象通过 Where 子句和运行时已知类型的 Lambda 过滤结果。

过滤器数组可以包含一个或多个具有 属性 名称、相等运算符(即 gte、eq、neq 等)和要比较的值的过滤器。

因为我可以有多个 属性 来过滤,所以我首先获取我需要比较任何对象的所有 BinaryExpression 属性 并将它们合并到一个表达式中,该表达式传递给查询 Where 子句。

如果过滤器的 属性 类型是 DateTime,我只想使用 BinaryExpression 比较 属性 的日期部分。

我有一个方法可以接收过滤器的参数名称及其值。

public static Expression<Func<T, bool>> GetEqualExpression<T>(string parameterName,
            string comparisonValue) {

    var param = Expression.Parameter(typeof(T), parameterName);
    var property = Expression.Property(param, parameterName);

    var propInfo = (PropertyInfo) property.Member;
    var propType = propInfo.PropertyType;

    if (propType == typeof(DateTime)) {

        // Parse the string to a DateTime.
        const string dateFormat = "ddd MMM d yyyy HH:mm:ss 'GMT'K";
        var parsedDate = DateTime.ParseExact(comparisonValue, dateFormat, CultureInfo.InvariantCulture); 

        // Trying to access the 'Date' child property.
        property = Expression.Property(property, "Date");
        var constant = Expression.Constant(parsedDate.Date);


        return Expression.Lambda<Func<T, bool>>(Expression.Equal(property, constant), param);
    }

    ...
}

例如考虑一个对象:

public class Ticket {
    public DateTime StartDate {get; set;}
    public DateTime DueDate {get; set;}
}

和 'StartDate' 属性 的过滤器,当我将表达式传递给查询的 where 子句时,它失败并出现异常 "Lambda parameter not in scope.";

我错过了什么?

提前致谢。

更新

所以,多亏了 xanatos,我发现 ServiceStack.OrmLite(我正在使用的 ORM)不支持访问日期 属性,就像 EF 一样。那么现在的问题是,我该如何解决这种情况?

有个小错误:必须使用

Expression.Equal(property, constant)

而不是

Expression.Equals(property, constant)

然后也许你在 中遇到问题,因为我可以有多个 属性 来过滤,我首先获取我需要比较任何对象的所有 BinaryExpression 属性 并将它们合并到一个表达式中,该表达式被传递给查询 Where 子句部分

请注意,如果您使用的是 Entity Framework,则可能不支持 DateTime.Date。参见 。一种可能的解决方案是使用 EntityFunctions.TruncateTime.

所以,这就是我处理这种情况的方式。非常感谢 xanatos 指出 ORM 的 DateTime.Date 问题。

我决定按以下方式按时间范围比较日期是否相等:

public static Expression<Func<T, bool>> GetEqualExpression(string parameterName, 
    string comparisonValue)
{
    var param = Expression.Parameter(typeof (T), parameterName);
    var prop = Expression.Property(param, parameterName);

    var propInfo = (PropertyInfo) Property.Member;
    var propType = propInfo.PropertyType;

    if (propType == typeof(DateTime))
    {
        const string dateFormat = "ddd MMM d yyyy HH:mm:ss 'GMT'K";
        var parsedDate = DateTime.ParseExact(comparisonValue, dateFormat, CultureInfo.InvariantCulture);

        var dayStart = new DateTime(parsedDate.Year, parsedDate.Month, parsedDate.Day, 0, 0, 0, 0);
        var dayEnd = new DateTime(parsedDate.Year, parsedDate.Month, parsedDate.Day, 23, 59, 59, 999);

        var left = Expression.Lambda<Func<T, bool>>(Expression.GreaterThanOrEqual(prop, Expression.Constant(dayStart)), param);
        var right = Expression.Lambda<Func<T, bool>>(Expression.LessThanOrEqual(prop, Expression.Constant(dayEnd)), param);

        return left.Compose(right, Expression.And);
    }

    ...
}

这似乎可以解决问题。