问题
我正在重构我们 Web 应用程序中几个报表的一些 LINQ
查询,并尝试将一些重复的查询谓词移动到它们自己的 IQueryable
扩展方法中,以便我们可以在这些报表和未来的报表中重用它们。正如您可能推断的那样,我已经重构了组的谓词,但代码的谓词给我带来了问题。这是我目前拥有的一个报告方法的示例:
DAL 方法:
public List<Entities.QueryView> GetQueryView(Filter filter)
{
using (var context = CreateObjectContext())
{
return (from o in context.QueryViews
where (!filter.FromDate.HasValue || o.RepairDate >= EntityFunctions.TruncateTime(filter.FromDate))
&& (!filter.ToDate.HasValue || o.RepairDate <= EntityFunctions.TruncateTime(filter.ToDate))
select o)
.WithCode(filter)
.InGroup(filter)
.ToList();
}
}
IQueryable
扩展:
public static IQueryable<T> WithCode<T>(this IQueryable<T> query, Filter filter)
{
List<string> codes = DAL.GetCodesByCategory(filter.CodeCategories);
if (codes.Count > 0)
return query.Where(Predicates.FilterByCode<T>(codes));
return query;
}
谓词:
public static Expression<Func<T, List<string>, bool>> FilterByCode<T>(List<string> codes)
{
// Method info for List<string>.Contains(code).
var methodInfo = typeof(List<string>).GetMethod("Contains", new Type[] { typeof(string) });
// List of codes to call .Contains() against.
var instance = Expression.Variable(typeof(List<string>), "codes");
var param = Expression.Parameter(typeof(T), "j");
var left = Expression.Property(param, "Code");
var expr = Expression.Call(instance, methodInfo, Expression.Property(param, "Code"));
// j => codes.Contains(j.Code)
return Expression.Lambda<Func<T, List<string>, bool>>(expr, new ParameterExpression[] { param, instance });
}
我遇到的问题是
Queryable.Where
不接受类型为Expression<Func<T,List<string>, bool>
的参数。我能想到的动态创建这个谓词的唯一方法是使用两个参数,而这正是困扰我的部分。我没有理解的是以下方法的工作原理。我可以传递我正在尝试动态创建的精确lambda表达式,并且它可以正确地过滤我的数据。
public List<Entities.QueryView> GetQueryView(Filter filter)
{
// Get the codes here.
List<string> codes = DAL.GetCodesByCategory(filter.CodeCategories);
using (var context = CreateObjectContext())
{
return (from o in context.QueryViews
where (!filter.FromDate.HasValue || o.RepairDate >= EntityFunctions.TruncateTime(filter.FromDate))
&& (!filter.ToDate.HasValue || o.RepairDate <= EntityFunctions.TruncateTime(filter.ToDate))
select o)
.Where(p => codes.Contains(p.Code)) // This works fine.
//.WithCode(filter)
.InGroup(filter)
.ToList();
}
}
问题
- 我能否实现自己的
Queryable.Where
重载?如果可以,是否可行? - 如果不可行,则有没有一种方法可以动态构造谓词
p => codes.Contains(p.Code)
而不使用两个参数? - 有更简单的方法吗?我感觉我漏掉了什么。