views:

70

answers:

2

I have a scenario in a windows service type app where I need to load up to several thousand entities, perform some business logic and then save them. In regards to session management, this kind of falls outside of the usual session per call that is often discussed. Basically, in my case I certainly don't want one session for (x) thousand entities. The most obvious issue with this would be the memory usage.

In this case, the class that coordinates the work (loading entities and then sending them off to specific classes for processing) needs to be able to have fine grained control over the session. I am contemplating destroying and creating a new session for each entity that needs to be processed. Or, perhaps there is something like calling session.Clear() each time to wipe everything out? The other thing I need is the ability to destroy and re-create a session if an exception occurs. Each entity represents a transaction in that all business logic for that entity needs to succeed or fail. If it fails, I need to rollback, destroy the session, create a new one and then move on to the next entity.

I am even contemplating ignoring the whole repository/dao concept here and just work with the isession directly to keep it simple. However, it would be great to use my existing daos. Perhaps there is another approach where in my coordinating class I can periodically clear or flush the session to release memory and somehow get the new session into the dao?

A: 

One ISession instance per entity would fit the model here. Sessions are designed for a unit of work, which is what you have here in the case of each entity - not session "per call" as you say.

If an exception occurs, simply start the process again for that entity with a new ISession instance.

You should be able to use your existing code I would have thought.

David M
Well, I may need to break my class into two classes. That way I can control the session creation in the main class, and work with the entities in another class that would get a session passed to it. hmmmm......
John
+1  A: 

It's fine to have multiple transactions (one at a time) inside an ISession, so there's no need to create a new session if you have to rollback a transaction. An ISession is usually best used to represent a single unit of work but I think this is a special case.

Have you measured the memory usage? It's not all that unusual for an ISession to track tens of thousands of objects if the object graph is fully loaded for a set of business objects. Think of loading all the sales orders and associated data for multiple customers.

The best possible performance with NHibernate would be using an IStatelessSession in a bulk operation. According to this article, a stateless session reduced execution time by ~50% on an operation on 500,000 objects. This leads me to guess that you shouldn't optimize until you have ~100,000 objects.

I think either solution -- single or multiple ISessions -- will work fine and I wouldn't try to optimize it unless I had a measurable performance problem.

Jamie Ide
I concurr with what you have stated and reflected that in my comments in the questions comments.
David
@Jamie/David - OK that makes sense. Perhaps I should not get too carried away with premature optimizations. Regarding exceptions, I thought I read that if you encounter an exception when working with a session that you should dispose of it right away and create a new one? So wouldn't I still need a way to create a new session in my case?
John
You are correct in saying that if an exception (NHibernate one) is encountered you should dispose the ISession as NH state may be inconsistent. I would just get another ISesson from your SessionFactory.
David
If you get a database exception in a transaction then you should handle the exception, rollback the transaction, and carry on. In most cases where the exception is thrown by the database provider, you will be able to continue working with the same ISession.
Jamie Ide