NHibernate中的批更新

NHibernate中的批更新,nhibernate,Nhibernate,NHibernate中是否存在批处理更新命令?就我所知,它没有。那么,处理这种情况的最佳方法是什么?我想做以下工作: 从数据库中获取对象列表(我们称之为用户列表,list) 更改这些对象的属性(Users.Foreach(User=>User.Country=“Antartica”) 单独更新每个项目(Users.Foreach(User=>NHibernate.Session.Update(User)) 调用Session.Flush更新数据库 这是一个好方法吗?这会导致我的代码和数据库之间的

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

  • 从数据库中获取对象列表(我们称之为用户列表,
    list
  • 更改这些对象的属性(
    Users.Foreach(User=>User.Country=“Antartica”
  • 单独更新每个项目(
    Users.Foreach(User=>NHibernate.Session.Update(User)
  • 调用
    Session.Flush
    更新数据库
  • 这是一个好方法吗?这会导致我的代码和数据库之间的大量往返吗


    您认为呢?或者有更优雅的解决方案吗?

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

    IList<User> users = session.CreateQuery (...).List<User>;
    users.Foreach(u=>u.Country="Antartica")
    session.Transaction.Commit();
    
    IList users=session.CreateQuery(…).List;
    users.Foreach(u=>u.Country=“Antartica”)
    Commit();
    
    我认为NHibernate会为所有更改编写一个批处理


    问题是,您的用户需要加载到内存中。如果出现问题,您仍然可以使用NHibernate使用本机SQL。但是,在您没有证明这是一个性能问题之前,请坚持使用好的解决方案。

    您可以在NHibernate配置文件中设置更新的批处理大小

    <property name="hibernate.adonet.batch_size">16</property>
    
    16
    
    您不需要在那里调用Session.Update(User)——只需刷新或提交事务,NHibernate就会为您处理事务

    编辑:我本来打算发布一个链接到nhibernate文档的相关部分,但是网站已经关闭了,主题是:

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


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

    不,这不是一个好方法

    对于这种更新,本机SQL要好很多倍

    UPDATE USERS SET COUNTRY = 'Antartica';
    

    这是再简单不过了,数据库引擎一次处理这一行的效率将是Java代码的一百倍。

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

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

    启动NHibernate 3.2批处理作业有一些改进,可以最大限度地减少数据库往返。有关更多信息,请访问。 以下是it的示例-这些批处理更新仅执行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();
    }
    
    使用(ISession s=OpenSession())
    使用(s.BeginTransaction())
    {
    对于(int i=0;i<12;i++)
    {
    var user=新用户{UserName=“user-”+i};
    var group=新组{Name=“group-”+i};
    s、 保存(用户);
    s、 保存(组);
    user.AddMembership(组);
    }
    s、 Commit();
    }
    
    从NHibernate 5.0开始,可以使用LINQ进行批量操作

    session.Query<Cat>()
    .Where(c => c.BodyWeight > 20)
    .Update(c => new { BodyWeight = c.BodyWeight / 2 });
    
    session.Query()
    .式中(c=>c.体重>20)
    .Update(c=>new{BodyWeight=c.BodyWeight/2});
    
    NHibernate将生成一个“更新”sql查询


    参见

    3:我想你不是指提交,而是指更新。是的,你是对的;我指的是更新。你应该删除步骤3,因为
    Session.update
    不会“将每个项目更新回来”相反,NHibernate监视对对象所做的所有更改,并自行将更改写入数据库,而无需您告诉它。@Justice+1用于该注释,但请记住,它保存到db的确切时间取决于会话的刷新模式。他使用的是NHibernate,即.NET而不是Java:)我在这里感到困惑:如果你的论点是有效的,那么就不应该使用ORM,因为db引擎处理SQL代码的效率总是比ORM代码高出许多倍……对吗?Ngu,我已经更新了我的答案,以回应你在那里的评论。参见Martin的答案,你仍然可以使用ORM,不需要从你的雇主那里窃取并编写ado.net代码。@Graviton没有免费的午餐;数据库相关任务的性能通过使用ORM来换取编码的方便。这取决于FlushMode。session.FlushMode=FlushMode。如果不显式调用Flush(),永远不会保存。您的代码将使用FlushMode。提交however@Stefan我无法使批量更新生效…请您帮忙,我会向使用NH 3.2+的任何人推荐marisks的答案。只有当所有
    用户的属性设置为相同的值
    Antartica
    时,这才有效。但是如果
    列表
    使用所有不同的国家,这个
    HQL
    不适用于这项工作。尽管它是针对OP的特定示例情况的解决方案。