【问题标题】:NHibernate ISession.Save() - Why is this persisting my entities immediately?NHibernate ISession.Save() - 为什么这会立即持久化我的实体?
【发布时间】:2011-06-26 16:12:30
【问题描述】:

我正在使用 NHibernate 创建大量实体,将它们附加到我的 ISession,然后使用事务将我的更改提交到数据库。代码示例如下:

ISession _context = SessionProvider.OpenSession();

//Create new entities
for(int i=0; i<100; i++)
{
    MyEntity entity = new MyEntity(i);

    //Attach new entity to the context
    _context.Save(entity);
}

//Persist all changes to the database
using(var tx = _context.BeginTransaction())
{
    //Flush the session
    tx.Commit();
}

我的印象是 _context.Save() 行只是让 ISession 知道新实体,但是在我通过 tx.Commit() 行刷新会话之前,不会对数据库进行任何更改。

不过,我观察到的是,每次我调用 _context.Save() 时,数据库都会获得一个新实体。结果,我最终对数据库进行了太多单独的调用。

有谁知道为什么 ISession.Save() 会自动持久化更改?我是否误解了 NHibernate 的行为方式?谢谢。

***编辑 - 只是为了澄清(根据两个建议的答案) - 我的问题是,一旦我调用 _context.Save(),数据库就会更新。我不希望发生这种情况。在调用 tx.Commit() 之前,我希望不会向数据库中插入任何内容。不幸的是,到目前为止,这两个建议的答案都没有帮助。

可以在here找到一些关于身份生成器的好信息

【问题讨论】:

  • 这是预期的行为,SaveTransaction 之外执行。正确答案应该是下面的@StuffHappens。
  • @THBBFT,在事务之外不会导致保存被发送到数据库。 StuffHappens 没有给出正确答案,为什么它会在Save 电话中插入。这个答案只是确保插入将得到回滚,但这不是 OP 关心的问题。它的编辑进一步证实了这一点。

标签: nhibernate transactions isession


【解决方案1】:

试试:

using(Session _context = SessionProvider.OpenSession())
using(var tx = _context.BeginTransaction())
{
    //Create new entities
    for(int i=0; i<100; i++)
    {
        MyEntity entity = new MyEntity(i);

        //Attach new entity to the context
        _context.Save(entity);
    }

    //Flush the session
    tx.Commit();
}

【讨论】:

  • 试图把它推到顶端。
【解决方案2】:

您使用的是哪个身份生成器?如果您使用 MSSQL/MySQL 的 Identity 或 Oracle 的 sequence 等后插入生成器来生成 Id 字段的值,那是您的问题。

来自NHibernate POID Generators Revealed

后插入生成器,作为名称 建议,在 实体存储在数据库中。一种 选择语句是针对 数据库。它们有很多缺点, 在我看来,它们必须被使用 仅适用于棕地项目。那些 我们不建议使用发电机 作为 NH 团队

一些缺点是 关注

  1. 工作单元因使用 那些策略。没关系 您正在使用 FlushMode.Commit,每个 在插入语句中保存结果 反对数据库。作为最佳实践,我们 应该推迟对提交的插入, 但使用后插入生成器 使它在保存时提交(这就是 UoW 没有)。
  2. 那些策略 使批处理程序无效,您不能使用 发送多个查询的优势 一次(因为它必须在 保存时间)

【讨论】:

  • 我认为这实际上可能是问题所在。我目前有: 在我的配置文件中设置。我将在今晚测试并标记为答案,如果那是问题。谢谢!
  • 我一直使用身份作为 ID 生成器,这似乎是我的问题的原因。我现在正在寻找工作单元/存储库模式的合适替代方案,我想在首先将许多实体与 ISession 关联之后自己显式刷新会话。谢谢。
【解决方案3】:

您可以在配置中设置批量大小:

<add key="hibernate.batch_size" value="10" /> 

或者您可以在代码中设置它。并确保您在事务范围内进行保存。

【讨论】:

    【解决方案4】:

    尝试将 FlushMode 设置为 Commit:

    ISession _context = SessionProvider.OpenSession();
    context.FlushMode = FlushMode.Commit;
    

    同行建议设置batch size也不错。

    我的理解是,当使用数据库标识列时,NHibernate 将推迟插入,直到会话刷新,除非它需要执行插入以检索外键或确保查询返回预期结果。

    【讨论】:

      【解决方案5】:

      1. rebelliard 的答案可能取决于您的映射
      2. 您没有使用显式事务(StuffHappens 的回答)
      3. 默认刷新模式为自动,这会使事情复杂化(Jamie Ide 的回答)
      4. 如果您通过任何更改使用 nhibernate api 进行任何查询,默认行为是首先将缓存刷新到数据库,以便这些查询的结果与会话实体表示相匹配。

      【讨论】:

        【解决方案6】:

        怎么样:

        ISession _context = SessionProvider.OpenSession();
        
        //Persist all changes to the database
        using(var tx = _context.BeginTransaction())
        {
            //Create new entities
            for(int i=0; i<100; i++)
            {
                MyEntity entity = new MyEntity(i);
        
                //Attach new entity to the context
                _context.Save(entity);
            }
        
            //Flush the session
            tx.Commit();
        
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-03-24
          • 1970-01-01
          • 2012-11-15
          • 1970-01-01
          • 2013-10-29
          • 1970-01-01
          相关资源
          最近更新 更多