关于.net:NHibernate ISession Flush:何时何地使用它,为什么?

关于.net:NHibernate ISession Flush:何时何地使用它,为什么?

NHibernate ISession Flush: Where and when to use it, and why?

让我彻底困惑的一件事是将session.Flushsession.Commitsession.Close结合使用。

有时session.Close可以工作,例如,它会提交我需要的所有更改。 我知道我在有事务或具有多个创建/更新/删除的工作单元时需要使用提交,以便在发生错误时可以选择回滚。

但是有时候我真的被session.Flush背后的逻辑所困扰。 我看过一些示例,其中有一个session.SaveOrUpdate()后跟一个刷新,但是当我删除"刷新"时,它仍然可以正常工作。 有时,我在Flush语句上遇到错误,说会话超时,然后删除它以确保我没有遇到该错误。

是否有人在哪里或何时使用冲洗有很好的指导? 我已经检查了NHibernate文档,但是仍然找不到简单的答案。


简要地:

  • 一律使用交易
  • 不要使用Close(),而是将调用包装在using语句内的ISession上,或在其他地方管理ISession的生命周期。
  • 从文档中:

    From time to time the ISession will execute the SQL statements needed to synchronize the ADO.NET connection's state with the state of objects held in memory. This process, flush, occurs by default at the following points

    • from some invocations of Find() or Enumerable()
    • from NHibernate.ITransaction.Commit()
    • from ISession.Flush()

    The SQL statements are issued in the following order

  • all entity insertions, in the same order the corresponding objects were saved using ISession.Save()
  • all entity updates
  • all collection deletions
  • all collection element deletions, updates and insertions
  • all collection insertions
  • all entity deletions, in the same order the corresponding objects were deleted using ISession.Delete()
  • (An exception is that objects using native ID generation are inserted when they are saved.)

    Except when you explicity Flush(), there are absolutely no guarantees about when the Session executes the ADO.NET calls, only the order in which they are executed. However, NHibernate does guarantee that the ISession.Find(..) methods will never return stale data; nor will they return the wrong data.

    It is possible to change the default behavior so that flush occurs less frequently. The FlushMode class defines three different modes: only flush at commit time (and only when the NHibernate ITransaction API is used), flush automatically using the explained routine, or never flush unless Flush() is called explicitly. The last mode is useful for long running units of work, where an ISession is kept open and disconnected for a long time.

    ...

    另请参阅本节:

    Ending a session involves four distinct phases:

    • flush the session
    • commit the transaction
    • close the session
    • handle exceptions

    Flushing the Session

    If you happen to be using the ITransaction API, you don't need to worry about this step. It will be performed implicitly when the transaction is committed. Otherwise you should call ISession.Flush() to ensure that all changes are synchronized with the database.

    Committing the database transaction

    If you are using the NHibernate ITransaction API, this looks like:

    1
    tx.Commit(); // flush the session and commit the transaction

    If you are managing ADO.NET transactions yourself you should manually Commit() the ADO.NET transaction.

    1
    2
    sess.Flush();
    currentTransaction.Commit();

    If you decide not to commit your changes:

    1
    tx.Rollback();  // rollback the transaction

    or:

    1
    currentTransaction.Rollback();

    If you rollback the transaction you should immediately close and discard the current session to ensure that NHibernate's internal state is consistent.

    Closing the ISession

    A call to ISession.Close() marks the end of a session. The main implication of Close() is that the ADO.NET connection will be relinquished by the session.

    1
    2
    3
    4
    5
    6
    tx.Commit();
    sess.Close();

    sess.Flush();
    currentTransaction.Commit();
    sess.Close();

    If you provided your own connection, Close() returns a reference to it, so you can manually close it or return it to the pool. Otherwise Close() returns it to the pool.


    从NHibernate 2.0开始,数据库操作需要事务。因此,ITransaction.Commit()调用将处理所有必要的刷新。如果由于某种原因您没有使用NHibernate事务,那么会话将不会自动刷新。


    ISession会不时执行将ADO.NET连接状态与内存中保存的对象状态同步所需的SQL语句。

    并始终使用

    1
    2
    3
    4
     using (var transaction = session.BeginTransaction())
     {
         transaction.Commit();
     }

    提交更改之后,会将更改保存到数据库中,然后使用transaction.Commit();。


    这是我的代码的两个示例,这些示例如果没有session.Flush()就会失败:

    http://www.lucidcoding.blogspot.co.uk/2012/05/changing-type-of-entity-persistence.html

    最后,您可以看到一段代码,其中我设置了身份插入,保存实体然后刷新,然后将身份插入设置为关闭。没有这种冲洗,似乎是在打开和关闭标识插入,然后保存实体。

    Flush()的使用使我对发生的事情有了更多的控制。

    这是另一个示例:

    在TransactionScope内发送NServiceBus消息

    我不完全理解为什么要这样做,但是Flush()阻止了我的错误的发生。


    推荐阅读