【问题标题】:Parsing Date portion of a DateTime with a BinaryExpression使用 BinaryExpression 解析 DateTime 的日期部分
【发布时间】:2015-06-12 09:20:25
【问题描述】:

我找到了类似概念的答案,但似乎没有一个适合我的情况。

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

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

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

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

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

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 参数不在范围内。”;

我错过了什么?

提前谢谢你。

更新

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

【问题讨论】:

    标签: c# datetime lambda expression expression-trees


    【解决方案1】:

    所以,这就是我处理这种情况的方式。非常感谢 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);
        }
    
        ...
    }
    

    这似乎可以解决问题。

    【讨论】:

      【解决方案2】:

      有个小错误:必须使用

      Expression.Equal(property, constant)
      

      而不是

      Expression.Equals(property, constant)
      

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

      请注意,如果您使用的是实体框架,DateTime.Date 可能不受支持。见https://stackoverflow.com/a/21186498/613130。一种可能的解决方案是使用EntityFunctions.TruncateTime

      【讨论】:

      • 是的,对不起,Expression.Equals 是一个错字,我实际上使用的是 Expression.Equal。我没有使用 EntityFramework 而是使用 ServiceStack.OrmLite。表达式合并适用于字符串和数字等简单类型。我强调这个概念只是为了指定我不能直接访问该属性。 (就像在 query.Where(q => q.StartDate.Date == parsedDate.Date)
      • @RobertoMauro 尝试检查是否可以在不使用表达式的情况下使用 Date 执行查询(因此构建真正的查询,如 query.Where(q =&gt; q.StartDate.Date == someDate.Date),只是为了检查 Orm 是否支持它。
      • 是的,你是对的,它不支持访问 Date 属性。我不明白为什么我认为这是理所当然的。我想我搞砸了。 :\
      • @RobertoMauro 通常 Orm 有“扩展点”来连接 SQL 函数......但我不使用 OrmLite,所以我不知道它是如何完成的。你最好问一个带有ormlite-ServiceStack标签的全新问题,或者任何关于这个论点的标签,这样也许该领域的专家可以帮助你。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多