我找到了類似概念的答案,但似乎沒有一個適合我的情況。
我正在構建一個對象,它通過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一樣。所以現在的問題是,我該如何解決這種情況?
所以,這就是我管理這種情況的方式。我非常感謝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);
}
...
}
這似乎可以解決問題。
有一個小錯誤:你必須使用
Expression.Equal(property, constant)
代替
Expression.Equals(property, constant)
然後也許你有一個問題因為我可以有多個屬性來過濾,我首先抓住我需要比較任何對象屬性的所有BinaryExpression 並將它們合併到一個表達式中 ,並傳遞給查詢Where子句部分
請注意,如果您使用的是Entity Framework,則可能不支持DateTime.Date
。請參閱https://stackoverflow.com/a/21186498/613130 。一種可能的解決方案是使用EntityFunctions.TruncateTime
。