2014-10-20 60 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