2010-12-15 58 views
0

我的域名是一個機場,它包含多個終端,每個終端包含區域等。
由於機場/終端/區域實體的數量非常小,我想:
1.檢索機場時急切地裝載所有的水印。
(使用以下流利的配置:
nHibernate渴望加載 - 奇怪的更新行爲

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


2.使二級高速緩存,從而使機場對象的所有檢索都打不到的DB。

急切的加載和緩存工作正常,但下面的測試會產生一些奇怪的行爲。
(以下代碼檢索一個機場實體兩次(未擊中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的:SELECT airport0_.Id如Id36_0_,airport0_.Name如Name36_0_,airport0_.IsDeleted如IsDeleted36_0_ FROM DBO [機場] airport0_ WHERE [email protected]; @ P0 = 1

NHibernate的:SE LECT terminals0_.Airport_id爲Airport4_1_,terminals0_.Id爲Id1_,terminals0_.Id爲Id50_0_,terminals0_.Name爲Name50_0_,terminals0_.IsDeleted爲IsDeleted50_0_,terminals0_.Airport_id爲Airport4_50_0_ FROM dbo。[Terminal] terminals0_ WHERE [email protected] ; @ P0 = 1

NHibernate的:SELECT zones0_.Terminal_id如Terminal4_1_,zones0_.Id如Id1_,zones0_.Id如Id51_0_,zones0_.Name如Name51_0_,zones0_.IsDeleted如IsDeleted51_0_,zones0_.Terminal_id如Terminal4_51_0_ FROM DBO [區] zones0_ WHERE [email protected]; @ P0 = 2


第二選擇
是那些同一機場的實例嗎?假

現在添加終端
NHibernate的:從dbo._uniqueKey選擇next_hi與(UPDLOCK,ROWLOCK)
NHibernate的:更新dbo._uniqueKey設置next_hi = @ P0其中next_hi = @ P1; @ P0 = 17,@ INSERT INTO dbo。[終端](Name,IsDeleted,Airport_id,Id)VALUES(@ p0,@ p1,@ p2,@ p3); @ p0 ='終端被添加到第二機場',p1 = 16

NHibernate:INSERT INTO dbo。 @ p1 = False,@ p2 = NULL,@ p3 = 16
NHibernate:UPDATE dbo。[Airport] SET Name = @ p0,IsDeleted = @ p1 WHERE Id = @ p2; @ p0 ='test airport',@ p1 = False,@ p2 = 1

NHibernate:UPDATE dbo。[T erminal] SET Name = @ p0,IsDeleted = @ p1,Airport_id = @ p2 WHERE Id = @ p3; @ p0 ='test terminal',@ p1 = False,@ p2 = 1,@ p3 = 2

NHibernate: UPDATE dbo。[Zone] SET Name = @ p0,IsDeleted = @ p1,Terminal_id = @ p2 WHERE Id = @ p3; @ p0 ='test zone',@ p1 = False,@ p2 = 2,@ p3 = 3

NHibernate:UPDATE dbo。[碼頭] SET Airport_id = @ P0其中id = @ P1; @ P0 = 1,@ P1 = 16



我的問題是:
1.哪些更新一切奇怪的更新行爲.. 。
2.事實firstAirport和secondAirport是不是同一個對象(也許我失去了一些東西約2級緩存?)

由於事先
的Jhonny

回答

1

事實上,第一機場和第二機場不是同一個對象,這是由於默認情況下引用類型比較引用相等這一事實。

由於您使用單獨的NHibernate ISession加載第一個和第二個機構,所以緩存沒有被使用,因爲session1對session2一無所知,反之亦然。
由NHibernate的會話實現的'Identity'模式被限制在那個session的offcourse中。

您可以通過正確地重寫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())。我現在看到這是一個相當愚蠢的假設。顯然,如果我想查看不同會話對對象所做的更改,我必須再次加載該對象。 – 2010-12-15 14:25:44

+0

也可以使用Merge()查看Ayende的解決方案 - http://ayende.com/Blog/archive/2009/11/08/nhibernate-ndash-cross-session-operations.aspx – 2010-12-15 14:45:21