我们已经实现了一个使用反射和其他方法动态创建Lambda过滤器的方法。我想要的大部分东西都很漂亮。问题在于DateTime值和等于/大于/小于过滤器。
我们的SQL服务器将项目存储为DateTime对象,有时为特定项目指定时间。然而,当在网络上显示列表时,我们只显示日期。因此,当用户(使用Kendo Grid)试图将数据过滤为大于或类似的日期时,它使用的是当天的午夜作为参数。这意味着当天午夜之后发生的所有事情都包含在不应该包含的内容中。这也意味着当我们使用等号语句时,什么都不返回,因为在午夜发生的事情很少。
我的研究(使用堆栈溢出)使我使用EntityFunctions.TruncateTime
作为一种方法。我不确定我是否要对字段和过滤值都这样做,但我现在甚至无法通过值。
我的第一次尝试是将比较的右侧(值部分)设置为对EntityFunctions.TruncateTime(filter.Value)
的调用。这给了我一个This function can only be invoked by linq to entities
错误。进一步的研究让我使用了这个表达。调用方法,但目前我得到No method 'TruncateTime' on type 'System.Data.Objects.EntityFunctions' is compatible with the supplied arguments.
下面是我尝试调用的代码。我为上下文提供了整个函数。我创建了一个GetPropertyType函数,让我知道我是否在DateTime字段上过滤。我还向我的Filter对象添加了一个属性来告诉我是否应该忽略时间。如果两者都为真,那么我才尝试应用TruncateTime函数。
我还尝试将DateTime的类型指定为表达式的类型参数。在方法中调用常量,以防需要键入,但这也没有帮助。
public static Expression GetLambdaFilters(ICollection<Filter> filters)
{
if (filters.Count > 0)
{
Type entityType = filters.ElementAt(0).EntityType;
var item = Expression.Parameter(entityType, entityType.Name);
Expression leftSide = null;
Expression rightSide = null;
Expression filterExpression = null;
foreach (var filter in filters)
{
Expression left = GetPropertyExpression(filter, item);
Expression comparison = null;
if (left is MethodCallExpression)
{
comparison = left;
}
else
{
Expression right = null;
if (!filter.IsCollectionQuery)
{
if (GetPropertyType(filter) == typeof (DateTime) && filter.IgnoreTime)
{
right = Expression.Call(typeof (EntityFunctions), "TruncateTime", null,
Expression.Constant(filter.Value));
}
else
{
right = Expression.Constant(filter.Value);
}
}
else
{
Filter innerFilter = new Filter();
innerFilter.IsCollectionQuery = false;
innerFilter.Operator = filter.Operator;
innerFilter.PropertyName = GetCollectionPropertyName(filter, item);
innerFilter.Type = filter.CollectionType;
innerFilter.Value = filter.Value;
List<Filter> innerfilters = new List<Filter>(){
innerFilter
};
right = GetLambdaFilters(innerfilters);
filter.Operator = FilterOperator.Any;
}
comparison = GetExpression(left, right, filter);
}
if (leftSide == null)
{
leftSide = comparison;
filterExpression = leftSide;
continue;
}
if (rightSide == null)
{
rightSide = comparison;
filterExpression = Expression.AndAlso(leftSide, rightSide);
continue;
}
filterExpression = Expression.AndAlso(filterExpression, comparison);
}
var func = typeof(Func<,>);
func.MakeGenericType(entityType, typeof(bool));
return Expression.Lambda(func.MakeGenericType(entityType, typeof(bool)), filterExpression, item);
}
else
{
return GetLambdaFilter(filters.First());
}
}
如果你改变行:
right = Expression.Call(typeof (EntityFunctions), "TruncateTime", null,
Expression.Constant(filter.Value));
right = Expression.Call(typeof (EntityFunctions), "TruncateTime", null,
Expression.Convert(Expression.Constant(DateTime.Parse(filter.Value)), typeof(DateTime?)));
这个应该可以工作。如果没有导致错误的convert调用,就不会发生装箱转换部分。