2011-01-17 7 views
4

式ツリー(Expression<Func<PlainAddress, bool>> predicate)を構築して、HNibernateがクエリを実行するためのIQueryable.Where関数に渡しています。私が渡すとき:式ツリーを構築すると、InvalidPathExceptionが発生する

predicate = y => y.Address.City == geoObject.Name; 

すべてがうまくいきます。私が合格した場合:

var x = Expression.Parameter(typeof(PlainAddress)); 

Expression<Func<PlainAddress, string>> expression = y => y.Address.City; 

predicate = Expression.Lambda<Func<PlainAddress, bool>>(
    Expression.Equal(
     Expression.Invoke(expression, x), 
     Expression.Constant(geoObject.Name)), 
     x); 

を私が間違って何をやっている、次の例外

Invalid path: 'y.Address.City' 
[.Where(NHibernate.Linq.NhQueryable`1[BPPDicsManager.Domain.Entities.PlainAddress], 
Quote((60ee8287-3f42-426a-8c15-41f62f58623c,) => (String.op_Equality((y,) => 
(y.Address.City)60ee8287-3f42-426a-8c15-41f62f58623c, p1))),)] 

を取得しますか?これら2つのオプションの違いは何ですか?

答えて

5

私はNHibernateに精通していませんが、私は2つの式の違いを説明しようとすることができます。

1.大きな違いは、サンプル番号2のExpression.Invokeの使用で、InvocatonExpressionが作成されます。これは、デリゲート式またはラムダ式を引数式のリストに適用する式を表します。 #2のような何かある

y => y.Address.City == geoObject.Name; 

サンプルに対し:

x => new Func<PlainAddress, string>(y => y.Address.City).Invoke(x) 
    == geoObject.Name 

あなたが近い第二のサンプルを得ることができている緩く言えば、

サンプル#1 - これは、間接の種類を紹介しますExpression.Propertyを使用して最初に適切なMemberExpressionを作成することによって:

var predicate = Expression.Lambda<Func<PlainAddress, bool>>(
     Expression.Equal(
      Expression.Property(Expression.Property(x, "Address"), "City"), 
      Expression.Constant(geoObject.Name)), 
      x); 

これは今に近い:(。私はこれがNHibernateはで動作するように述語を取得するのに十分であろう推測している)

x => x.Address.City == AsStringLiteral(geoObject.Name) 


2.コースの他の違い、サンプル#2でExpression.Constantを使用しています。これはとなります。geoObject.Nameの値を評価し、それをリテラルの式ツリーに変換します。サンプル#1のようにgeoObject変数(または恐らくthis?)の巻き上げを「エミュレート」する場合は、さらに多くの作業が必要になります。

+1

悲しいことに、この回答には4年間で4つのアップノートがありましたが、このような厳しい質問にどのように答えなければならないかという美しい例です。 –

関連する問題