2
votes

I'm trying to develop a web forms application using NHibernate and the Session Per Request model. All the examples I've seen have an HTTPModule that create a session and transaction at the beging of each request and then commits the transaction and closes the session at the end of the request. I've got this working but I have some concerns.

The main concern is that objects are automatically saved to the database when the web request is finished. I'm not particularly pleased with this and would much prefer some way to take a more active approach to deciding what is actually saved when the request is finished. Is this possible with the Session Per Request approach?

Ideally I'd like for the interaction with the database to go something like this:

  1. Retreive object from the database or create a new one
  2. Modify it in some way
  3. Call a save method on the object which validates that it's indeed ready to be commited to the database
  4. Object gets saved to the database

I'm able to accomplish this if I do not use the Sessions Per Request model and wrap the interactions in a using session / using transaction blocks. The problem I ran into in taking this approach is that after the object is loaded from the database the session is closed an I am not able to utilize lazy loading. Most of the time that's okay but there are a few objects which have lists of other objects that then cannot be modified because, as stated, the session has been closed. I know I could eagerly load those objects but they don't always get used and I feel that in doing so I'm failing at utilizing NHibernate.

Is there some way to use the Session Per Request (or any other model, it seems like that one is the most common) which will allow me to utilize lazy loading AND provide me with a way to manually decide when an object is saved back to the database? Any code, tutorials, or feedback is greatly appreciated.

1

1 Answers

3
votes

Yes, this is possible and you should be able to find examples of it. This is how I do it:

  • Use session-per-request but do not start a transaction at the start of the request.
  • Set ISession.FlushMode to Commit.
  • Use individual transactions (occasionally multiple per session) as needed.
  • At the end of the session, throw an exception if there's an active uncommitted transaction. If the session is dirty, flush it and log a warning.

With this approach, the session is open during the request lifetime so lazy loading works, but the transaction scope is limited as you see fit. In my opinion, using a transaction-per-request is a bad practice. Transactions should be compact and surround the data access code.

Be aware that if you use database assigned identifiers (identity columns in SQL Server), NHibernate may perform inserts outside of your transaction boundaries. And lazy loads can of course occur outside of transactions (you should use transactions for reads also).