2014-10-20 61 views
1

我正在嘗試使用NHibernate進行批量更新,但它沒有執行批量更新,它爲所有行執行單獨寫入操作。我必須寫大約10k行到db。nhibernate:批量執行更新

 using (var session = GetSessionFactory().OpenStatelessSession()) 
     { 
      session.SetBatchSize(100); 
      using (var tx = session.BeginTransaction()) 
      { 
       foreach (var pincode in list) 
       { 
        session.Update(pincode); 
       } 
       tx.Commit(); 
      } 
     } 

我試着用session.SetBatchSize(100);批量大小設置爲100,但它不能幫助。還嘗試使用cfg.SetProperty("adonet.batch_size", "100");設置批量大小,但那也沒有幫助。

我使用GUID主鍵,因此我不明白批量更新失敗的原因。這正是解釋爲here的解決方案。但它不適合我。

注意我有樂觀併發版本字段映射到所有實體。這可能是沒有批量更新的罪魁禍首?

編輯

我試圖用國家FUL會議,但也沒有幫助

 //example 2 
     using (var session = GetSessionFactory().OpenSession()) 
     { 
      session.SetBatchSize(100); 
      session.FlushMode = FlushMode.Commit; 
      foreach (var pincode in list) 
      { 
       session.Update(pincode); 
      } 
      session.Flush(); 
     } 

     //example 3 
     using (var session = GetSessionFactory().OpenSession()) 
     { 
      session.SetBatchSize(100); 
      using (var tx = session.BeginTransaction()) 
      { 
       foreach (var pincode in list) 
       { 
        session.Update(pincode); 
       } 
       tx.Commit(); 
      } 
     } 

example 2由於某種原因導致雙往返。

編輯

經過進一步的研究,我發現,每個session.Update實際上是在更新數據庫

 using (var session = SessionManager.GetStatelessSession()) 
     { 
      session.SetBatchSize(100); 
      foreach (var record in list) 
      { 
       session.Update(record); 
      } 
     } 

我怎樣才能避免這種情況。

編輯

與洗淨模式嘗試爲好,但是那也沒有幫助

 using (var session = SessionManager.GetNewSession()) 
     { 
      session.FlushMode = FlushMode.Never; 
      session.SetBatchSize(100); 
      session.BeginTransaction(); 
      foreach (var pincode in list) 
      { 
       session.SaveOrUpdate(pincode); 
      } 
      session.Flush(); 
      session.Transaction.Commit(); 
     } 

EDIT 4

甚至低於一個不能正常工作,因爲我正在獲取所有實體在同一會話中,並且只在該會話中更新並保存它們...

 using (var session = SessionManager.GetSessionFactory().OpenSession()) 
     { 
      session.SetBatchSize(100); 
      session.FlushMode = FlushMode.Commit; 
      session.Transaction.Begin(); 
      var list = session.QueryOver<Pincode>().Take(1000).List(); 
      list.ForEach(x => x.Area = "Abcd" + DateTime.Now.ToString("HHmmssfff")); 
      foreach (var pincode in list) session.SaveOrUpdate(pincode); 
      session.Flush(); 
      session.Transaction.Commit(); 
     } 
+0

如果你的pincode是代理,你不需要調用'session.Update(pincode);如果是這樣,如果你改變實體並調用'session.Flush();'會發生什麼? – mxmissile 2014-10-20 20:08:27

+0

nopes這些​​不是代理,這些對象是從另一個無狀態會話中的數據庫中獲取的,應用了一些業務邏輯,然後批量保存... – harishr 2014-10-20 20:14:50

+0

在這種情況下,請參閱下面的Oskar的答案。 – mxmissile 2014-10-20 20:22:01

回答

2

nhibernate 沒有批量版本化實體這是我的情況問題。

有沒有辦法可以批量版本的實體,唯一做到這一點的是使實體無版本。

2

您正在使用無狀態會話。由於無狀態會話沒有狀態,它以後不能記住任何事情。因此更新立即執行。

+0

結帳更新/編輯 – harishr 2014-10-20 18:20:55

+0

檢查編輯4,即使在同一會話中取和更新沒有執行批量更新... – harishr 2014-10-21 07:08:20

+0

在我的情況下,NHibernate無狀態會話沒有刷新更新所有。解決的辦法是SetBatchSize(1)。 – neoscribe 2016-09-15 19:38:54

1

需要注意的是:

  • 批次是SQL Server Profiler中不可見。不要依賴那個。
  • 插入使用身份(或本機)ID生成器,NH關閉ado.net批量大小。

其他注意事項:

  • 確保您不必爲每個改變實體的查詢,因爲它查詢之前刷新。
  • 你可能不應該調用session.Update。在最好的情況下,它什麼都不做。在最壞的情況下,它確實會更新,從而打破配料。

當會話中有很多對象時,不要忘記關心刷新和刷新時間。有時沖洗比更新耗時更多。在提交之前,當您調用flush和查詢之前,NH會刷新,除非您關閉它或使用無狀態會話。確保你只刷新一次。

+0

1.我使用NHProf,2.我有GUID主鍵。另外檢查EDIT4,至少應該與會話刷新 – harishr 2014-10-21 08:24:23

+0

是否有任何其他條件,除了這兩個可以打破批量? – harishr 2014-10-21 08:39:22

+0

批處理由ado.net實現,因此必須使用ado.net訪問數據庫。 – 2014-10-21 09:11:43