NHibernate ISession.Save() - 为什么这会立即持续存在于我的实体中?

时间:2011-06-26 16:12:31

标签: nhibernate transactions isession

我正在使用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()行刷新会话之前,没有任何更改持久存储到数据库。 / p>

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

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

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

可以找到有关身份生成器的一些有用信息here

6 个答案:

答案 0 :(得分:6)

尝试:

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();
}

答案 1 :(得分:6)

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

来自NHibernate POID Generators Revealed

  

发布插入生成器,作为名称   建议,在之后分配id   实体存储在数据库中。一个   执行select语句   数据库。它们有许多缺点,   在我看来,他们必须被使用   仅限棕地项目。那些   发电机是什么我们不建议   作为NH团队

     

一些缺点是   以下

     
      
  1. 工作单位被打破了   那些策略。无论如何   你正在使用FlushMode.Commit   将结果保存在insert语句中   反对DB。作为最佳实践,我们   应该将插入推迟到提交,   但使用后插入生成器   让它在保存时提交(这是什么   UoW不这样做)。
  2.   
  3. 那些策略   取消batcher,你不能采取   发送多个查询的优点   立刻(因为它必须到数据库)   保存的时间)
  4.   

答案 2 :(得分:2)

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

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

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

答案 3 :(得分:1)

尝试将FlushMode设置为Commit:

ISession _context = SessionProvider.OpenSession();
context.FlushMode = FlushMode.Commit;
同行建议设置批量大小也是好的。

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

答案 4 :(得分:0)

怎么样:

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();

}

答案 5 :(得分:0)

好吧

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