2017-01-12 12 views
1

私は式ツリーに慣れようとしています。私は壁に当たっています。 LINQ to XMLクエリを動的に作成できるようにするため、Expression Treesに慣れようとしています。私は動的に生成することができるようにしたいXML文の簡単なLINQを開始しました:式ツリーを使用したLINQ動的クエリ

 // sample data 
     var sampleData = new XElement("Items", 
      new XElement("Item", new XAttribute("ID", 1)), 
      new XElement("Item", new XAttribute("ID", 2)), 
      new XElement("Item", new XAttribute("ID", 3)) 
      ); 

     // simple example using LINQ to XML (hard-coded) 
     var resultsStatic = from item in sampleData.Elements("Item") 
          where item.Attribute("ID").Value == "2" 
          select item; 

     // trying to recreate the above dynamically using expression trees 
     IQueryable<XElement> queryableData = sampleData.Elements("Item").AsQueryable<XElement>(); 
     ParameterExpression alias = Expression.Parameter(typeof(XElement), "item"); 
     MethodInfo attributeMethod = typeof(XElement).GetMethod("Attribute", new Type[] { typeof(XName) }); 
     PropertyInfo valueProperty = typeof(XAttribute).GetProperty("Value"); 
     ParameterExpression attributeParam = Expression.Parameter(typeof(XName), "ID"); 
     Expression methodCall = Expression.Call(alias, attributeMethod, new Expression[] { attributeParam }); 
     Expression propertyAccessor = Expression.Property(methodCall, valueProperty); 
     Expression right = Expression.Constant("2"); 
     Expression equalityComparison = Expression.Equal(propertyAccessor, right); 
     var resultsDynamic = queryableData.Provider.CreateQuery(equalityComparison); 

からCreateQueryを呼び出すときに私が手にエラーが「引数の式が有効ではありません」です。 equalityComparisonのデバッグビューには、 '(.Call $ item.Attribute($ ID))。Value == "2"'が表示されます。誰かが私が間違ってやっていることを特定できますか?

答えて

1

何が起きているのかをよりよく理解するには、まずメソッドの構文から始めてください。

IQueryable<XElement> queryableData = sampleData.Elements("Item").AsQueryable(); 
IQueryable<XElement> queryStatic = queryableData 
    .Where((XElement item) => item.Attribute("ID").Value == "2"); 

は今、あなたが持っているものを見てみましょう:あなたのケースでは、(通常、私は varを使用しますが、私は、具体的なタイプを含めています)は次のようです。

まず、attributeParam変数

ParameterExpression attributeParam = Expression.Parameter(typeof(XName), "ID"); 

あなたは、静的なクエリからもわかるように、属性名には、ラムダパラメータがありません - サポートされている唯一の(と必須)パラメータがitem(あなたのコードであります変数aliasで表されます)。だから、これは値 "ID" とタイプXNameConstantExpression次のようになります。

var attributeParam = Expression.Constant((XName)"ID"); 

第二に、equalityComparison変数。それに含まれるのは、item.Attribute("ID").Value == "2"の式です。あなたは、パラメータとして、本体とaliasとしてequalityComparisonを使用してこのようなを作成する必要がありますので、しかし、Where方法は、Expression<Func<XElement, bool>>が必要です。

var predicate = Expression.Lambda<Func<XElement, bool>>(equalityComparison, alias); 

最後に、あなたはWhereメソッドを呼び出す必要があります。あなたは、直接それを行うことができます。

var queryDynamic = queryableData.Where(predicate); 

または動的に:

var whereCall = Expression.Call(
    typeof(Queryable), "Where", new Type[] { queryableData.ElementType }, 
    queryableData.Expression, Expression.Quote(predicate)); 
var queryDynamic = queryableData.Provider.CreateQuery(whereCall); 

あなたは、彼らが何をすべきかをさらに詳細に使用Expression方法のドキュメントを見てみることができます。

+0

ありがとうございました!これは完全に動作します! – DMC

0

Linq to XMLはメモリ内で動作します。つまり、式ツリーを除外しないで、Enumerable拡張メソッドを使用します。あなたのコードはもっと簡単で読みやすくなります!

+0

フィードバックに感謝しますが、私はこのアプローチの理由があります。実行時に動的にLINQ文を生成する機能が必要です。 – DMC

関連する問題