我需要减少表达式
Expression<Func<TQueryResult, TParam, bool>>
到
Expression<Func<TQueryResult, bool>>
将TParam value
作为常量注入表达式
具体例子:
protected IQueryable<TQueryResult> AddQueryFilter<TQueryResult, TParam>(IQueryable<TQueryResult> query, Expression<Func<TQueryResult, TParam, bool>> exp, TParam param)
{
object obj = param;
if (obj is string)
{
if (!string.IsNullOrWhiteSpace((string) obj))
{
var reducedExp = new Expression<Func<TQueryResult, bool>>()
// ...
// the magic that I need to inject param value
//..
return query.Where(reducedExp);
}
}
else if (obj is DateTime)
{
//... return query.Where(reducedExp);
}
else
throw new InvalidOperationException("Param type not supported");
return query;
}
//usage
var qr = Manager.Invoices.Query;
qr = AddQueryFilter(qr, (invoice, value) => value == invoice.Number, numberEdit.Text);
qr = AddQueryFilter(qr, (invoice, value) => value == invoice.Date, dateEdit.Date);
qr = AddQueryFilter(qr, (invoice, value) => invoice.Description.Contains(value), descEdit.Text);
答案 0 :(得分:2)
尝试:
protected static IQueryable<TQueryResult> AddQueryFilter<TQueryResult, TParam>(
IQueryable<TQueryResult> query, Expression<Func<TQueryResult, TParam, bool>> exp, TParam param)
{
var rewriter = new ExpressionRewriter();
rewriter.Subst(exp.Parameters[1], Expression.Constant(param, typeof(TParam)));
var body = rewriter.Apply(exp.Body);
var lambda = Expression.Lambda<Func<TQueryResult, bool>>(body, exp.Parameters[0]);
return query.Where(lambda);
}
使用this answer中的ExpressionRewriter
。
答案 1 :(得分:0)
我希望有人仍然可以像我一样搜索这个话题,所以我想提出以下可能性。
自.NET 4.0发布以来,您可以使用内置的expression tree visitors。
这是一个实现所需功能的例子:
private class ExpressionConstantInjector<T, TConstant> : ExpressionVisitor
{
private readonly TConstant toInject;
private readonly ParameterExpression targetParam;
public EntityExpressionListInjector(TConstant toInject)
{
this.toInject = toInject;
targetParam = Expression.Parameter(typeof(T), "a");
}
public Expression<Func<T, bool>> Inject(Expression<Func<T, TConstant, bool>> source)
{
return (Expression<Func<T, bool>>) VisitLambda(source);
}
protected override Expression VisitLambda<T1>(Expression<T1> node)
{
return Expression.Lambda(Visit(node.Body), targetParam);
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == typeof (TConstant))
return Expression.Constant(toInject);
return targetParam;
}
}
用法:
Expression<Func<Entity, List<int>, bool>> expression = (e, ids) => ids.Contains(e.Id);
var filterExpression
= new ExpressionConstantInjector<Entity, List<int>>(new List<int>{1, 2, 3})
.Inject(expression);
// filterExpression is like a => (1, 2, 3).Contains(a.Id)
// filterExpression can be passed to EF IQueryables.
这个解决方案非常本地化,不是真正可重复使用,而是安静简单(不是)。
说实话,[].Contains(id)
是我测试过的唯一案例。但我认为它有效。