使用BinaryExpression

时间:2015-06-12 09:20:25

标签: c# datetime lambda expression expression-trees

我找到了类似概念的答案,但似乎没有一个符合我的理由。

我正构建一个对象,该对象通过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”的过滤器&#39;属性,当我将表达式传递给查询的where子句时,它失败,异常&#34; Lambda参数不在范围内。&#34 ;;

我失踪了什么?

提前谢谢。

更新

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

2 个答案:

答案 0 :(得分: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);
    }

    ...
}

这似乎可以解决问题。

答案 1 :(得分:0)

有一个小错误:您必须使用

Expression.Equal(property, constant)

而不是

Expression.Equals(property, constant)

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

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

相关问题