4

我正在使用 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() 之前,我希望不会向数据库中插入任何内容。不幸的是,到目前为止,这两个建议的答案都没有帮助。

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

4

6 回答 6

7

尝试:

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();
}
于 2011-06-26T16:37:25.347 回答
6

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

NHibernate POID Generators Revealed :

顾名思义,后插入生成器在实体存储在数据库中之后分配 id。对数据库执行选择语句。它们有很多缺点,在我看来,它们只能用于棕地项目。这些发电机是我们不建议作为 NH 团队的。

一些缺点如下

  1. 使用这些策略会破坏工作单元。无论您是否使用 FlushMode.Commit,每个 Save 都会导致针对 DB 的插入语句。作为最佳实践,我们应该将插入推迟到提交,但使用后插入生成器使其在保存时提交(这是 UoW 不做的)。
  2. 这些策略使批处理器无效,您不能利用一次发送多个查询的优势(因为它必须在保存时进入数据库)
于 2011-06-26T19:52:10.717 回答
2

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

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

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

于 2011-06-26T20:12:43.843 回答
1

尝试将 FlushMode 设置为 Commit:

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

同行的设置批量大小的建议也很好。

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

于 2011-06-26T21:00:39.060 回答
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();

}
于 2011-06-26T16:39:20.133 回答
0

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