2012-01-23 16 views
13

フィルタリングのためにかなり大きな式ツリーに他のものと組み合わされるラムダ式を作成しようとしています。これは、サブコレクションプロパティでフィルタリングする必要があるまでうまく動作します。コレクションプロパティをフィルタリングするための動的式ツリーの構築

ルートオブジェクトのプロパティであるコレクションのプロパティでAny()を使用してフィルタリングするラムダ式を作成するにはどうすればよいですか?

例:

CurrentDataSource.Offices.Where(o => o.base_Trades.Any(t => t.Name == "test")) 

これは私が静的表現を建設する方法ですが、私はそれを動的に構築する必要があります。混乱させて申し訳ありません。

編集:ここで私はあまり複雑な式の処理方法の抜粋です:

IQueryable<Office> officeQuery = CurrentDataSource.Offices.AsQueryable<Office>(); 
ParameterExpression pe = Expression.Parameter(typeof(Office), "Office"); 
ParameterExpression tpe = Expression.Parameter(typeof(Trades), "Trades"); 

Expression SimpleWhere = null; 
Expression ComplexWhere = null; 
foreach (ServerSideFilterObject fo in ssfo) 
{ 
    SimpleWhere = null; 
    foreach (String value in fo.FilterValues) 
    { 
     if (!CollectionProperties.Contains(fo.PropertyName)) 
     { 
      //Handle singleton lambda logic here. 
      Expression left = Expression.Property(pe, typeof(Office).GetProperty(fo.PropertyName)); 
      Expression right = Expression.Constant(value); 
      if (SimpleWhere == null) 
      { 
       SimpleWhere = Expression.Equal(left, right); 
      } 
      else 
      { 
       Expression e1 = Expression.Equal(left, right); 
       SimpleWhere = Expression.Or(SimpleWhere, e1); 
      } 
     } 
     else 
     { 
      //handle inner Collection lambda logic here. 
      Expression left = Expression.Property(tpe, typeof(Trades).GetProperty("Name")); 
      Expression right = Expression.Constant(value); 
      Expression InnerLambda = Expression.Equal(left, right); 

      //Problem area. 
      Expression OfficeAndProperty = Expression.Property(pe, typeof(Office).GetProperty(fo.PropertyName)); 
      Expression OuterLambda = Expression.Call(OfficeAndProperty, typeof(Trades).GetMethod("Any", new Type[] { typeof(Expression) }),InnerLambda); 

      if (SimpleWhere == null) 
       SimpleWhere = OuterLambda; 
      else 
       SimpleWhere = Expression.Or(SimpleWhere, OuterLambda); 
     } 
    } 
    if (ComplexWhere == null) 
     ComplexWhere = SimpleWhere; 
    else 
     ComplexWhere = Expression.And(ComplexWhere, SimpleWhere); 
} 
MethodCallExpression whereCallExpression = Expression.Call(typeof(Queryable), "Where", new Type[] { officeQuery.ElementType }, officeQuery.Expression, Expression.Lambda<Func<Office, bool>>(ComplexWhere, new ParameterExpression[] { pe })); 
results = officeQuery.Provider.CreateQuery<Office>(whereCallExpression); 
+0

表現ツリーを構築する方法を尋ねていますか? – SLaks

+0

あなたの例で階層がどのように機能するかわかりません。あなたはもう少し詳しく説明できますか?オフィスはルートになっており、各オフィスには一連の取引がありますか?そして、あなたはトレードの名前をフィルタリングしたいですか?フィルターは、私が少し失った場所です。ごめんなさい。 –

+0

いいえ、私は、内部メソッド呼び出しとパラメータ用の式で式を構築するために使用される構文が不明です。この場合、パラメータが定義と一致しないため、Any()が見つからないというエラーが表示されます。このケースでは、構文に賛同していないか、Any()がそれを使用している方法ではサポートされていないため、そのことがわかりません。 – George

答えて

9

解決策を見つけました。私は前に正しい場所にある方法を探していませんでした。

Expression left = Expression.Property(tpe, typeof(Trades).GetProperty("Name")); 
Expression right = Expression.Constant(value); 
Expression InnerLambda = Expression.Equal(left, right); 
Expression<Func<Trades, bool>> innerFunction = Expression.Lambda<Func<Trades, bool>>(InnerLambda, tpe); 

method = typeof(Enumerable).GetMethods().Where(m => m.Name == "Any" && m.GetParameters().Length == 2).Single().MakeGenericMethod(typeof(Trades)); 
OuterLambda = Expression.Call(method, Expression.Property(pe, typeof(Office).GetProperty(fo.PropertyName)),innerFunction); 
0

あなたはあなたの例のように記載されていることはあなたのコメントに基づいて動作します。私たちは、フィールドの特定のコレクションを持っているテンプレートがあり、それらのフィールドが要求される可能性

Templates.Where(t => t.TemplateFields.Any(f => f.Required == 'Y')) 

:ここで私はで動作するものの一例です。だから私は上記のステートメントで必要なフィールドがあるテンプレートを得ることができます。

うまくいけば、これは役立ちます...少なくともあなたがしようとしていることを確認してください。あなたがこれについてもっと疑問を持っているなら私に教えてください。私は詳しく説明します。

幸運を祈る!

+0

これは私が作業しているのと似ていますが、lamda式をリフレクションで動的に構築して、フィルタが他のフィルタをセットに確実に組み込むようにする必要があります。 – George

0

設けコード

CurrentDataSource.Offices.Where(o => o.base_Trades.Any(t => t.Name == "test")) 

は限りo.base_TradesIEnumerable<Trade>を実装するように動作するはずです。 o.base_TradesにはIEnumerableしか実装されていない場合は、o.base_Tradesのすべての要素がTradeタイプまたはOfType<Trade>()の要素であることが確認できる場合は、Cast<Trade>()を使用する必要があります(互換性のないタイプの要素がある場合)。そして、このようになります

は:

CurrentDataSource.Offices 
    .Where(o => o.base_Trades.Cast<Trade>.Any(t => t.Name == "test")) 
1

ダイナミックlinqというライブラリを実際に使用したい場合は、この作業を行わないでください。 http://nuget.org/packages/DynamicLINQ

クエリを文字列として保存するだけで、非常に複雑なクエリがサポートされます。表現木は悪夢です。

+0

これは素晴らしいライブラリですが、私もそれを使用しますが、 'myIQueryable.OrderBy(x => x.MyCollection.Select(y => y.Myproperty))のようなコレクションプロパティのプロパティのソート例はサポートしていません。 '、少なくとも私はそれを働かせることができません –

関連する問題