web-dev-qa-db-ja.com

NHibernateプロキシクラスの識別

私はNHibernateユーザーではありません。シリアル化ユーティリティライブラリを作成します。ユーザーは、NHibernateプロキシクラスを実際のタイプと同じように扱い、処理する必要があるという機能要求を記録しました。現時点では、私のコードはそれらを予期しない継承として扱い、例外をスローしています。

コードはNHibernateについて事前に知りません(参照がないことを含みますが、私はリフレクションは好きではありません;-p)

そのようなプロキシタイプを検出するための堅牢で保証された方法はありますか?どうやらDataContractSerializerはこれをうまく処理するので、それがかなり単純なものであることを望んでいます。おそらくいくつかのインターフェイスまたは[attribute]装飾。

また、逆シリアル化中。現時点では、NHibernateタイプではなく、元のタイプを作成します。永続化の目的でこれは問題ありませんか?または、プロキシタイプが必要ですか?後者の場合;プロキシタイプのインスタンスを作成するには何が必要ですか?

37
Marc Gravell

クラスを(当然のことながら)INHibernateProxyにキャストすることで、NHibernateプロキシであるかどうかを検出できます。

基礎となる「実際の」オブジェクトを取得する必要がある場合は、以下を使用します。

Session.GetSessionImplementation().PersistenceContext.Unproxy(proxiedObject)

Unproxyを呼び出すためにプロキシをテストする必要はありません。プロキシでない場合は、元のパラメータを返します。

編集:基になるオブジェクトを取得するために別のアプローチを使用します。主に遅延読み込みと継承を回避するためです。 http:// sessionfactory .blogspot.com/2010/08/hacking-lazy-loaded-inheritance.html

49
Diego Mijelshon

実際のNhibernateセッションにアクセスしたくないと思うのですが。このコードはあなたのニーズによりよく合うかもしれません:

/// <summary>
/// Returns the real type of the given proxy. If the object is not a proxy, it's normal type is returned.
/// </summary>
internal static Type GetRealType(this object proxy)
{
    if (proxy is INHibernateProxy)
    {
        var lazyInitialiser = ((INHibernateProxy)proxy).HibernateLazyInitializer;
        return lazyInitialiser.PersistentClass;
    }
    else
    {
        return proxy.GetType();
    }
}

お役に立てば幸いです。

16
Vijay Patel

NHibernateから、型(プロキシかどうか)を指定して実際の型を返すツールがあります。 (私はNHibernate 3を使用しています)

これはあなたがそれを使う方法です:

var realType = NHibernate.NHibernateUtil.GetClass(proxyInstance);

これが役に立てば幸い:D

8
Samuel Poirier

Diegoのメソッドは、オブジェクトのタイプを決定する前にオブジェクトを完全にロードします。これは間違いなく最も一般的なアプローチですが、具体的なタイプがプロキシに既知の場合は、オブジェクトをロードする必要がない場合があります。

具体的なタイプが事前にわかっている場合、Vijayの方法はより高速ですが、Diegoによって指摘されているように、正確なタイプを判別するために必要な情報がまだロードされていないため、その情報が利用できない場合があります。

両方のシナリオを考慮して、次のことを思いつきました。

https://Gist.github.com/1089489

興味深い部分はこれです:

        if (entity is INHibernateProxy)
        {
            var lazyInitialiser = ((INHibernateProxy)entity).HibernateLazyInitializer;
            var type = lazyInitialiser.PersistentClass;

            if (type.IsAbstract || type.GetNestedTypes().Length > 0)
                return Service.Session.GetSessionImplementation().PersistenceContext.Unproxy(entity).GetType();
            else // we don't need to "unbox" the Proxy-object to get the type
                return lazyInitialiser.PersistentClass;
        }

        return entity.GetType();

これはまず、プロキシの背後にある型が抽象かどうかを確認し、具象型が既知であるかどうかに応じて、VijayまたはDiegoのメソッドを使用します。

つまり、プロキシの背後にある型が具象型ではないか、サブタイプである可能性がある場合にのみ、オブジェクトをロードします。

私はこれが機能することを実証するために簡単な単体テストを行いましたが、考えられるすべてのケースをテストしたとは思いません。アイデアは確かだと思いますが、DiegoやVijayなどからのコメントを聞きたいです。

ありがとう!

編集:上記の要旨にアップデートを投稿しました。エンティティをUnproxy()するために使用できる追加のジェネリックメソッドを使用します-これを行う必要がある場合があります...

1
mindplay.dk

汎用のシリアル化ユーティリティライブラリを作成している場合、その特定のケースを処理する必要はまったくないと思います。コードはNHibernateに依存しないようにする必要があります。あなたがすべきことは、クライアントコードがライブラリの操作に影響を与えるために使用できるフックを提供することです。

1
Jordão

NHibernateは、実行時に元のエンティティの(プロキシ)サブクラスを作成して、遅延読み込みを実行できるようにします。すべてのプロパティを「仮想」としてマークする必要があるため、これを行うことができます。他の種類のサブクラス化とは対照的に、オブジェクトがプロキシであることをどのように検出できるか考えられません-確かに一般的な方法ではありません。 (非)シリアル化されている実際のクラスがシリアル化可能としてマークされていないため、この場合は、コードが例外をスローしていると推測できます。ベースクラスのすべてのプロパティをオーバーライドする場合は、検証を緩めるか、サブクラスのシリアル化を許可することだけができると思います。

元の型への逆シリアル化は問題ありません。

1
s1mm0t

NHibernate 2.1+では、動的プロキシプロバイダーを構成を通じて設定できます。私が知っている実装は、Castle(デフォルト)、LinFu、Springです。 NHibernateはインターフェースや属性を必要としません。これにより、オブジェクトがプロキシであるかどうかを確実に検出することはかなり不可能になると思います。

S1mm0tが答えたように、逆シリアル化で実際の型を作成することは問題ありません。

1
Jamie Ide