Try fast search NHibernate

15 December 2008

Identity: The never ending story

How many times you heard us saying “don’t use identity POID generator!” ?
To understand it better you must move your mind to an application, or a use-case, where the pattern open-session-in-view (aka session-per-request) is not applicable.

The Unit of Work

The Unit of Work (UoW) is a pattern described by Martin Fowler. When you work with NHibernate the real implementation of the pattern is the NH-Session (more exactly in PersistentContext inside de session). The commit and rollback, described in the pattern, are respectively the session.Flush() and the session.Close() (the close mean when close the session without Flush it). As usual the pattern described by Fowler is short and very clear so an explication is unneeded; here I want put more emphasis in two phrases:
“You can change the database with each change to your object model, but this can lead to lots of very small database calls, which ends up being very slow.”
“A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you're done, it figures out everything that needs to be done to alter the database as a result of your work.”
In addition, note, Fowler are talking about business transaction (repeat business-transaction).
In NHibernate, setting the FlushMode to FlushMode.Never (MANUAL in Hibernate), if you begin a NH-Transaction and commit it, but without a session.Flush, nothing happen in DB.

Analyze Session-per-conversation

SessionPerConversation
The session-per-conversation pattern is an example of a business transaction that spans multiple requests. As described by Fowler the nh-session (the real UoW) spans the whole business-transaction and in each request we are begin-commit a NH-Transaction. At the end of the conversation, inside a NH-Transaction, we will chose to Flush or Close the NH-session (mean commit or rollback the UoW).
In session-per-conversation we don’t want have a NH-Transaction (that, in this moment, mean a ADO.NET transaction) open for the whole conversation because not only is “impractical”, as said Fowler, but, in my opinion, it break the concept of ACID.

How to break all ?

If you want break the UoW pattern, and session-per-conversation pattern, you have a very easy way:use identity as your POID strategy.
The identity strategy mean :
  • change the database with each change to your object model (see the phrase above)
  • if you run a session.Save in the first request you will have a new record in the DB, and you can’t rollback this change without run an explicit Delete.
In addition I want say that using identity you are “disabling” the ADO-batcher NH’s feature for inserts.
You can continue using identity but you must know what you are loosing, and only you know what you are winning (I don’t know what you are winning using identity when you are working with a spectacular persistence layer as NHibernate is).

8 comments:

  1. "Identity POID generator" es el nativo de la base de datos? el autonumérico de SQL Server? Si no uso eso que uso?
    Los identificadores con significado de negocio no son recomendados, los uuid tampoco, entonces?

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. Creo que con POID se refiere a "Persistent Object Identifier", lo que intenta demostrar es que es inapropiado utilizar como POID un atributo que en la base de datos es Identity, cuando se utiliza el patrón Session-Per-Conversation como Unit of Work.

    Creo que el problema fundamental es que el patrón Session-Per-Conversation requiere "interacciones con el usuario" durante su ejecución, por lo tanto meter todo dentro de una transacción ADO no es posible (ver ACID). A diferencia de Session-Per-View que la sesión es abierta al comenzar el "request" y termina con él, el Session-Per-Conversation inicia la unit of work al comenzar el caso de uso, y esto puede involucrar multiples request, diferentes vistas (pantallas), e interacciones del usuario..

    ReplyDelete
  4. @Andres
    You can choose one of the others POID generators provided by NH.
    sequence (when your RDBMS allow it), guid.comb, or the better IMO HighLow (hilo or seqhilo in NH)

    ReplyDelete
  5. @Jo
    More then "an intent" that is nothing more than a fact.

    ReplyDelete
  6. If I understand, one should also not use native, because it picks identity for sqlserver? Because there is no sequence on sqlserver, there is only hilo left. Am I right?

    ReplyDelete
  7. First of all: there are a lot of articles about NHibernate which are not worth to read and this really is an exception!
    We need to support an exisiting db which is using identity fields all over the place. We solved it by keeping a list of transient object along wiht the session and attach them before the session is flushed but in a transaction

    ReplyDelete
  8. Unfortunately, this post fails to show alternatives. If you tell people to don't do something, it is a MUST to show up alternatives. Please update the post accordingly.

    ReplyDelete