【问题标题】:Batch Update in NHibernateNHibernate 中的批量更新
【发布时间】:2010-10-21 07:46:42
【问题描述】:

NHibernate 中是否存在批量更新命令?据我所知,它没有。那么处理这种情况的最佳方法是什么?我想做以下事情:

  1. 从数据库中获取对象列表(我们称它们为用户列表,List<User>
  2. 更改这些对象的属性,(Users.Foreach(User=>User.Country="Antartica")
  3. 单独更新每个项目 (Users.Foreach(User=>NHibernate.Session.Update(User))。
  4. 致电Session.Flush更新数据库。

这是一个好方法吗?这会导致我的代码和数据库之间进行大量往返吗?

你怎么看?还是有更优雅的解决方案?

【问题讨论】:

  • 3:我认为你的意思不是提交,而是更新。
  • 是的,你是对的;我的意思是更新。
  • 您应该删除第 3 步,因为 Session.Update 不会“更新每个项目”。相反,NHibernate 会监视对对象所做的所有更改,并自行将更改写入数据库,而无需您告诉它。
  • @Justice +1 表示该评论,但请记住它何时保存到数据库取决于会话的 FlushMode

标签: nhibernate


【解决方案1】:

你不需要更新,也不需要刷新:

IList<User> users = session.CreateQuery (...).List<User>;
users.Foreach(u=>u.Country="Antartica")
session.Transaction.Commit();

我认为 NHibernate 会为所有更改编写一个批处理。

问题是,您的用户需要加载到内存中。如果遇到问题,您仍然可以使用 NHibernate 使用本机 SQL。但是,除非您没有证明这是一个性能问题,否则请坚持使用不错的解决方案。

【讨论】:

  • 这取决于 FlushMode。 session.FlushMode = FlushMode.Never 不会在没有明确调用 Flush() 的情况下保存。但是,您的代码可以与 FlushMode.Commit 一起使用
  • @Stefan 我无法让批量更新工作...你能帮忙stackoverflow.com/questions/26471952/…
【解决方案2】:

您可以在 nhibernate 配置文件中设置更新的批量大小。

<property name="hibernate.adonet.batch_size">16</property>

而且您不需要在那里调用 Session.Update(User) - 只需刷新或提交事务,NHibernate 就会为您处理事情。

编辑:我打算发布一个指向 nhibernate 文档相关部分的链接,但该网站已关闭 - here's an old post from Ayende 关于该主题:

至于在这里使用 NHibernate(或任何 ORM)是否是一个好方法,这取决于上下文。如果您正在使用单个值对大表中的每一行进行一次性更新(例如将所有用户设置为国家“南极洲”(顺便说一下,这是一个大陆,而不是一个国家!),那么您可能应该使用 sql UPDATE 语句。如果您打算在应用程序的一般使用中将多个记录与一个国家/地区作为业务逻辑的一部分同时更新,那么使用 ORM 可能是一种更明智的方法。这取决于数量您每次更新的行数。

如果您不确定,也许这里最明智的选择是调整 NHibernate 中的 batch_size 选项,看看效果如何。如果系统的性能不可接受,那么您可以考虑在代码中实现直接的 sql UPDATE 语句。

【讨论】:

    【解决方案3】:

    不,这不是一个好方法!

    原生 SQL 对于这种更新来说要好很多倍。

    UPDATE USERS SET COUNTRY = 'Antartica';
    

    再简单不过了,数据库引擎将比一次一行的 Java 代码更高效地处理这一行。

    【讨论】:

    • 他使用的是 NHibernate,那是 .NET 而不是 Java :)
    • 我在这里很困惑:如果您的论点是有效的,那么就不应该使用 ORM,因为 db 引擎处理 SQL 代码的效率总是比 ORM 代码高很多倍......我说的对吗?跨度>
    • Ngu,我已经更新了我的答案以回复您的评论。
    • 看Martin的回答,你还是可以用你的ORM,不用偷你的雇主写ado.net代码。
    • @Graviton 天下没有免费的午餐;使用 ORM 可以用数据库相关任务的性能来换取编码的便利性。
    【解决方案4】:

    我知道我迟到了,但我想你可能想知道现在可以在 NHibernate 2.1+ 中使用 HQL

    session.CreateQuery(@"update Users set Country = 'Antarctica'")
    .ExecuteUpdate();
    

    【讨论】:

    • 会向任何使用 NH 3.2+ 的人推荐 marisks 的答案
    • 这仅适用于所有Users 的属性将设置为相同的值Antartica。但是,如果 List&lt;User&gt; 与所有不同的县一起批量更新,则此 HQL 将无法胜任。虽然它是对 OP 的特殊示例情况的解决方案。
    【解决方案5】:

    启动 NHibernate 3.2 批处理作业有一些改进,可以最大限度地减少数据库往返。更多信息请访问HunabKu blog。 以下是其中的示例 - 这些批量更新仅执行 6 次往返:

    using (ISession s = OpenSession())
    using (s.BeginTransaction())
    {
        for (int i = 0; i < 12; i++)
        {
            var user = new User {UserName = "user-" + i};
            var group = new Group {Name = "group-" + i};
            s.Save(user);
            s.Save(group);
            user.AddMembership(group);
        }
        s.Transaction.Commit();
    }
    

    【讨论】:

      【解决方案6】:

      从 NHibernate 5.0 开始,可以使用 LINQ 进行批量操作。

      session.Query<Cat>()
      .Where(c => c.BodyWeight > 20)
      .Update(c => new { BodyWeight = c.BodyWeight / 2 });
      

      NHibernate 将生成单个“更新”sql 查询。

      Updating entities

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-03-25
        • 2014-01-05
        • 2020-02-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多