Build an expression tree for LINQ using the List <T> .Contains method
Problem
I'm working on refactoring some queries LINQfor multiple reports in our web application, and I'm trying to transfer some recurring query predicates to my own extension methods IQueryableso that we can reuse them for these reports and reports in the future. As you can probably conclude, I have already reformatted the predicate for groups, but the predicate for codes gives me problems. This is an example of one of the reporting methods that I still have:
DAL Method:
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 Expansion:
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;
}
predicate:
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>. , , - , , .
, , - . , , .
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)? - ? , - .
,
Where,IQueryable<T>,IQueryable<T>LINQ. LINQ, . , , , ; , , LINQ, . , , , ,Where.Where, ., :
public static Expression<Func<T, bool>> FilterByCode<T>(List<string> codes) where T : ICoded //some interface with a `Code` field { return p => codes.Contains(p.Code); }, (: ), , , , , :
public static Expression<Func<T, bool>> FilterByCode<T>(List<string> codes) { var methodInfo = typeof(List<string>).GetMethod("Contains", new Type[] { typeof(string) }); var list = Expression.Constant(codes); var param = Expression.Parameter(typeof(T), "j"); var value = Expression.Property(param, "Code"); var body = Expression.Call(list, methodInfo, value); // j => codes.Contains(j.Code) return Expression.Lambda<Func<T, bool>>(body, param); }; .
: , :
// j => codes.Contains(j.Code). :(j, codes) => codes.Contains(j.Code);, .. # 2.