2011-02-01 6 views
4

を減らす私は式に定数としてTParam valueを注入することによりジェクトのparam値と表現

Expression<Func<TQueryResult, bool>>

Expression<Func<TQueryResult, TParam, bool>>

発現を減少する必要があります。


具体例:

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

はAddQueryFilter === ConstructSearchExpressionですか? –

+0

はい、申し訳ありません。私は今それを修正しました。 –

+0

どのLINQ実装を使用していますか? LINQ-to-SQL? EFに?何? –

答えて

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を使用。

+0

これは 'invoice.Number == value'で動作します。 'invoice.Number.ToLower()== value.ToLower()'のためにも動作します。 "Invoice.Number.Contains(value)'では動作しません.ExpressionRewriter.Walk {case ExpressionType.Call:} - "静的メソッドはnullインスタンスを必要とし、非静的メソッドはnull以外のインスタンスを必要とします。 パラメータ名:メソッド " –

+0

@Boris - odd;それは静的な方法ではありません - 私は再学習することができます少し後に調査します –

+0

@ボリス - 発見され、修正されました。 'ExpressionType.Parameter'の周りの' Walk'への変更を参照してください –

0

私は実際にこのトピックを探している人がいることを願っていますので、以下の可能性を提案したいと思います。

.NET 4.0がリリースされて以来、組み込みのexpression tree visitorsを使用できます。

は、ここで必要な機能を実装しexapmple、です:

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)は私がテストした唯一のケースです。しかし、私はそれが動作すると思います。

関連する問題