2011-11-25 3 views
6

私たちはNHを利用してデータアクセスを行うASP.NET MVCアプリケーションを構築しています。 NH Profilerを使用すると、「WARN:Domain.CaseTaskへのプロキシの絞り込み - この操作は==」のような警告が表示されます。 NHのLINQプロバイダを使用して、例えば、サブクラスごとのテーブルにマップされているクラスに対してクエリを実行するとき、私は非常に多くの場合、これらを取得する:NHibernateナロープロキシ警告

クラスCaseTaskタスクから継承
Query<ICaseTask>().Where(c => c.Assignee == Of || c.Operator == Of) 

は、警告をトリガします。

インターネット上の警告に関する情報はほとんどなく、ほとんど無視されることを示唆しています...この警告は正確に何について警告していますか?これが正しいものでなければならないのですか?

答えて

2

この警告は、サブクラスであるプロパティまたはフィールドを持つクラスに関するものです。 IE:

public class Animal 
{ 
    public int Id {get;set;} 
} 

public class Cat : Animal 
{ 
    public int Weight {get;set;} 
} 

public class Person 
{ 
    public Cat Pet {get;set;} 
} 

行動が予測不能になるので、それはあなたのためにキャストしたくないので、それは人のエンティティをロードするときにNHibernateは動揺を取得します。あなたがNHibernateに(他のロジックの中でも)Equalsを扱う方法を伝えない限り、それ自身でその比較を行う方法はわかりません。

これを訂正する基本的な考え方は、NHibernateが基本クラスオブジェクトをグラフに入れてからキャストを処理するようにすることです(この設定ではコードを単純化するためにこれを行っていますが、完全にゲッタ/セッタとしてプロパティを保持することによって明らかに行うことができます):

public class Animal 
    { 
     public int Id {get;set;} 
    } 

public class Cat : Animal 
{ 
    public int Weight {get;set;} 
} 

public class Person 
{ 
    private Animal _pet; 
    public Cat Pet { 
     get{return _pet as Cat;} 
    } 
} 
+0

これは大きな問題ですか?このWARNを無視するとどうなりますか? – Beatles1692

+1

これは大きな問題であり、受け入れるリスクのレベルによって異なります。あなたのコードとデータベースとの間には常に切り離しがあるので、いつでも確実にキャスティングが動作するとは限りません。これにより、診断が難しく、データベースやコードを変更することなく解決できないバグが発生します。 – Fourth

2

現実はもっと複雑です。 session.Loadを使用してエンティティをロードするか、遅延ロードされたプロパティにアクセスすると、NHibernateはプロキシオブジェクトを返します。そのプロキシオブジェクトは、そのプロパティのいずれかに初めてアクセスしたときに、水和(データはDBからロードされます)されます。これを実現するために、NHibernateはを拡張してエンティティクラスを継承し、すべてのプロパティゲッターとセッターをオーバーライドするプロキシクラスを生成します。プロキシとエンティティクラス(プロキシベースクラス)を区別する方法がないため、継承を使用しないと完全に機能します。単純なテストproxy is MyEntityは常に動作します。

class Person { 
    // lazy-loaded 
    public Animal Pet { get; set; } 
} 

そして、我々はまた、Animalクラス階層を持っている:あなたは人のためにNHibernateのを頼むとき

public abstract class Animal { ... } 
public class Cat { ... } 
public class Dog { ... } 

は今、Petプロパティは遅延ロードされていることを前提と

今、私たちはPersonエンティティを持っていることを想像しますあなたはプロキシオブジェクトを取得します:

var pet = somePerson.Pet; // pet will be a proxy 

Petは遅延読み込みプロパティなので、NHはCatまたはのインスタンスになるかどうかわからないので、最善を尽くしてAnimalを拡張するプロキシを作成します。プロキシはpet is Animalのテストに合格しますが、pet is Catまたはpet is Dogのいずれかのテストに失敗します。

petオブジェクトのいくつかのプロパティにアクセスし、NHが強制的にデータをDBからロードするとします。 NHはあなたのペットが、 Catですが、プロキシはすでに生成されており、変更することはできません。 これは、Animalを拡張するpetの元のプロキシがCatに絞り込まれるという警告をHibernateに出させます。これは今からからの代理オブジェクトpet.Idを使用して作成したもので、session.Load<Animal>(pet.Id)Catになります。これは、Catがセッションの一部として保存されているため、最初にcatを共有する第2の人物を読み込んだ場合、NHは既に使用可能なCatプロキシインスタンスを使用して遅延読み込みプロパティを設定します。

petへのオブジェクト参照がsession.Load<Animal>(pet.Id)object.ReferencesEqualの意味で)と異なることになります。これはあなたに害を引き起こす可能性が今

  1. あなたがSetのかDictionaryあなたのコード内で居住またはにあなたのエンティティを置くあなたは仕事にEquals/GetHashCodeペアを必要とする他の構造を使用している場合。これは、カスタムEquals/GetHashCodeの実装を提供することで簡単に修正できます(http://www.onjava.com/pub/a/onjava/2006/09/13/dont-let-hibernate-steal-your-identity.html?page=1参照)

  2. プロキシオブジェクトをターゲットタイプにキャストしようとすると、 (Cat)petが、再び

だから道徳的は、ドメインモデルで可能な限り継承を避けるためである(例えば Getting proxies of the correct type in NHibernate)ソリューションが知っています。