我找到了类似概念的答案,但似乎没有一个符合我的理由。
我正构建一个对象,该对象通过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一样。所以现在的问题是,我该如何解决这种情况?
答案 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
。