2010-12-15 7 views
0

私のドメインはいくつかの端末を含む空港であり、各端末にはゾーンなどが含まれています。
空港/端末/ゾーンエンティティの数は非常に少ないので、
1.空港を検索するときに、すべての階層を熱心に読み込みます。
:空港オブジェクトのすべての回収のは、DBヒットないように(以下流暢構成を使用
nHibernate eager load-strange updateの動作

//eagerly load terminals 
mapping.HasMany(x => x.Terminals).Not.LazyLoad() 
      .Cache.ReadWrite(); 


2は、第2レベルのキャッシュを有効にします。

熱心な読み込みとキャッシュがうまくいきますが、次のテストでは奇妙な動作が発生します。
(。次のコードは、空港エンティティそれらの二倍(DBをもう一度叩いていない)、及びアップデートいずれかを取得)

 [TestMethod] 
    public void TestSecondLevelCache() 
    { 
     Airport firstAirport = null, secondAirport = null; 

     Console.WriteLine("first select"); 
     using (ISession session = this.SessionFactory.OpenSession()) 
     { 
      using (ITransaction transaction = session.BeginTransaction()) 
      { 
       //the idea here is to see whether there are two calls to DB here. check the sql output 
       AirportDAO dao = new AirportDAO(session); 
       firstAirport = dao.GetAirport(); 
       transaction.Commit(); 
      } 
     } 

     Console.WriteLine("second select"); 
     using (ISession session = this.SessionFactory.OpenSession()) 
     { 
      using (ITransaction transaction = session.BeginTransaction()) 
      { 
       //the idea here is to see whether there are two calls to DB here. check the sql output 
       AirportDAO dao = new AirportDAO(session); 
       secondAirport = dao.GetAirport(); 
       transaction.Commit(); 
      } 
     } 

     Console.WriteLine("Are those the same airport instance? " + firstAirport.Equals(secondAirport)); 

     Console.WriteLine("now adding a terminal"); 
     using (ISession session = this.SessionFactory.OpenSession()) 
     { 
      using (ITransaction transaction = session.BeginTransaction()) 
      { 
       secondAirport.Terminals.Add(new Terminal() { Name = "terminal added to second airport", Zones = new List<Zone>() }); 
       session.Update(secondAirport); 
       transaction.Commit(); 
      } 
     } 
     //this Assert fails, since firstAirport != secondAirport 
     Assert.IsNotNull(firstAirport.Terminals.FirstOrDefault(t => t.Name.Contains("second airport"))); 
    } 

は、結果の出力を参照してください

第一選択します。
NHibernateは:DBO FROM IsDeleted36_0_としてId36_0_、Name36_0_としてairport0_.Name、airport0_.IsDeletedとしてairport0_.Idを[空港] airport0_ [email protected]; @ P0 = 1

NHibernateは:SEターミナル0_.Airport_idとしてAirport4_1_、ターミナル0_.IdとしてId1_、ターミナル0_.IdとしてId50_0_、ターミナル0_.NameとしてName50_0_、ターミナル0_.IsDeleted50_0_、ターミナル0_.Airport_idとしてAirport4_50_0_からdbo。[ターミナル] terminals0_ WHERE [email protected] ; @ P0 = 1

NHibernateは:DBO FROM Terminal4_51_0_としてTerminal4_1_、Id1_としてzones0_.Id、Id51_0_としてzones0_.Id、Name51_0_としてzones0_.Name、IsDeleted51_0_としてzones0_.IsDeleted、zones0_.Terminal_idとしてzones0_.Terminal_idを[ゾーン] zones0_ [email protected];それらは同じ空港インスタンス@ P0 = 2



を選択していますか?偽

今端末
NHibernateの追加:(UPDLOCK、ROWLOCK)でdbo._uniqueKeyからnext_hi選択
NHibernateは:更新dbo._uniqueKey設定next_hi = @ P0ここnext_hi = @ P1; @ P0 = 17、@ @ p0 = 16

[Terminal](名前、IsDeleted、Airport_id、Id)VALUES(@ p0、@ p1、@ p2、@ p3); @ p0 = '第2の空港に端末が追加されました' @ p1 = False、@ p2 = NULL、@ p3 = 16
NHibernate:UPDATE dbo。[Airport] SET名= @ p0、IsDeleted = @ p1 WHERE Id = @ p2; @ p0 = 'テスト空港'、@ p1 = False、@ p2 = 1

NHibernate:UPDATE dbo。[T @ p1 = False、@ p2 = 1、@ p3 = 2

NHibernate:@ p1 = False、@ p0 = UPDATE dbo。[ゾーン] SET Name = @ p0、IsDeleted = @ p1、Terminal_id = @ p2 WHERE Id = @ p3; @ p0 = 'テストゾーン'、@ p1 = False、@ p2 = 2、@ p3 = 3

NHibernate:UPDATE dbo。[ターミナル] SET Airport_id = @ P0 ID = @ P1; @ P0 = 1、@ P1 = 16



私の問題は、次のとおりです。
1.すべてを更新奇妙な更新動作.. 。
2. firstAirportとsecondAirportが同じオブジェクトではないという事実(多分私は第二レベルのキャッシュについての何かが欠けてるの?)事前に

おかげで、
ジョニー

答えて

1

firstAirportとsecondAirportが同じオブジェクトではないという事実は、参照型が既定で参照等価性のために比較されるためです。

別のNHibernate ISessionを使ってfirstとsecondAirportをロードしているので、session1はsession2について何も知らないし、その逆もありませんのでキャッシュは使用されていません。
NHibernateのSessionによって実装されている 'Identity'パターンは、そのセッションにオフスコープでスコープされています。

この動作を無効にするには、EqualsメソッドとGetHashcodeメソッドを適切にオーバーライドします。 Equalsメソッドをオーバーライドして、空港の「Id」に基づいて等価性が決定されるようにすることができます。

奇妙な更新の動作は、別のセッションでオブジェクトを更新してから、そのセッションを取得したためです。 ISEssionはUnitOfWorkとして表示されます。そのため、それぞれのセッションでこれらの操作を行うのではなく、オブジェクトをロードして同じセッションでオブジェクトを保存することをお勧めします。 (これは、既存の空港オブジェクトを更新を実行するために使用しているセッションに「ロック」することによっても同様に解決できます)。

using (ISession session = this.SessionFactory.OpenSession()) 
     { 
      using (ITransaction transaction = session.BeginTransaction()) 
      { 

       session.Lock (secondAirport, LockMode.None); 

       secondAirport.Terminals.Add(new Terminal() { Name = "terminal added to second airport", Zones = new List<Zone>() }); 
       session.Update(secondAirport); 
       transaction.Commit(); 
      } 
     } 
+0

ありがとうございます!それはうまくいくようです。 また、firstAirport!= secondAirportについて、私の目的は、あるセッションが空港を更新したときに、他のセッションが直ちに(Get()を呼び出さずに)それを見るかどうかを確認することでした。私は今これがかなりばかげた仮定であることを知っています。明らかに、別のセッションによってオブジェクトに加えられた変更を見たい場合は、そのオブジェクトを再度ロードする必要があります。 –

+0

また、Merge()を使用してAyendeのソリューションをチェックしてください - http://ayende.com/Blog/archive/2009/11/08/nhibernate-ndash-cross-session-operations.aspx –

関連する問題