2017-01-09 2 views
1

作業単位の開始時にセッションを開始し、作業単位の最後に閉じます。作業単位は、複数の方法にまたがっています。NHibernate:セッションキャッシュからエンティティインスタンスを取得するには?

1つの方法では、Getメソッドを使用してエンティティをロードします。これはセッションキャッシュに置かれます。エンティティインスタンスはメソッドに対してローカルです。したがって、メソッドスコープが終了すると、エンティティインスタンスにアクセスできなくなります。しかし、エンティティはまだセッションキャッシュにあります。

ここで2番目の方法は、エンティティの新しいインスタンスを作成し、それを削除しようとします。これにより、期待どおりNonUniqueObjectExceptionがスローされます。

後、私は想像することができるソリューションですが、実装することができません:私は何とかセッションキャッシュからエンティティインスタンスを取得することができる場合、私はそれをEvictことができ、うまくいけば、問題が解決されます

public void Delete<T>(T instance) where T : BaseEntity 
{ 
    try 
    { 
     nhSession.Delete(instance); 
    } 
    catch(NonUniqueObjectException) 
    { 
     T instanceFromCache = GetInstanceFromCache<T>(instance); 
     nhSession.Evict(instanceFromCache); 
     nhSession.Delete(instance); 
    } 
} 

。しかし、私は想像上のGetInstanceFromCacheメソッドを実装することができません。

私はnhSession.Getを使ってみましたが、それは私のシナリオでは役に立たないです。私のデータベースの主キー列名は "id"ではなく、テーブル間で同じではありません。 1つの表では、それは「Field1」であり、他の表では「Field2」である。だから私はnhSession.Get(instance.Id)のようなものを使うことはできません。私のDelete<T>(T instance)メソッドは、削除するエンティティインスタンスをパラメータとして受け取ります。削除する主キーの値は受け取りません。

詳細については、私のotherの質問を参照してください。この質問では、UPDATEの問題とその修正方法について説明します。シナリオも同様です。 「@Ricardoペレス」によって

編集1

回答はそのまま動作しませんが、私は彼のコードを少し変更しました。

public static TEntity GetInstanceFromCache<TEntity>(this ISession nhSession, object instance) where TEntity : BaseEntity 
{ 
    var sessionImpl = nhSession.GetSessionImplementation(); 
    foreach(BaseEntity baseEntity in sessionImpl.PersistenceContext.EntityEntries.Keys) 
    { 
     if(baseEntity is TEntity) 
     { 
      TEntity instanceFromCache = (TEntity)baseEntity; 
      if(nhSession.GetIdentifier(instanceFromCache) == nhSession.GetIdentifier(instance)) 
       return baseEntity as TEntity; 
     } 
    } 
    return null; 
} 

コールnhSession.GetIdentifier(instance)が予想される(「インスタンスがこのセッションに関連していなかった」)例外TransientObjectExceptionをスロー。これはnhSessionにはinstanceが不明であるためです。セッションに関連付けられていないエンティティの識別子を取得する方法はありますか?あなたがのPersistenceContextのホールドを取得する必要があり

+0

プロキシの場合:http://stackoverflow.com/a/10328489/1486443 – Najera

答えて

1

は、次のように:「@Ricardoペレス」により投稿されたコードで

using System.Linq; 
using NHibernate; 

public static T GetInstanceFromCache<T>(this ISession session, object key) where T : class 
{ 
    var entity = session.GetSessionImplementation().PersistenceContext.EntitiesByKey.SingleOrDefault(x => x.Value is T && x.Key.Identifier == key); 
    return entity as T; 
} 
+0

はい、System.Linq名前空間への参照を追加するとします。これは拡張メソッドです。 –

+0

ありがとうございます。はい、そうです。しかし、それでもキャッシュ内のエンティティは返されません。私の推測: 'x.Key.Identifier == key'は失敗します。私はキーとしてエンティティインスタンスを渡しており、コードは 'Identifier'を期待しています。私は識別子の価値を持っていません。私はエンティティインスタンスしか持っていません。これは私が上記**編集1 **で述べた同様の問題です。セッションに関連付けられていないエンティティの識別子を取得する方法はありますか? –

+0

あなたはそれをデバッグする必要があります、私は常にこのアプローチ(同じメソッドGetInstanceFromCache、異なる名前のみ)を使用しています。エンティティのIDを取得するには、次のようにします。var entityName =(sessionFactory as isSessionFactoryImplementor)TryGetGuessEntityName(entityType);\t \t \t AbstractEntityPersisterとしてのPersister =(SessionFactoryとしてのSessionFactoryImplementor).TryGetEntityPersister(entityName); \t \t \t { \t \t \t \tリターン(entityType.GetProperty(persister.IdentifierPropertyName))\t \t \t (!存続= NULL)場合、 \t \t \t} –

1

、私はそれを解決することができました。しかし、正確なコードは私の仕事ではありません。私は次のように少し修正する必要がありました:

関連する問題