Some development I was working on threw an exception moments ago that I had never seen before: Illegal attempt to associate a collection with two open sessions.
The 'session' word tipped me off that this was an nHibernate exception. Debugging confirmed that it was indeed being thrown on the following line:
The scenario was a 1:M relationship between Parent and Child. Here, I was trying to save a new record to the Child table. The problem turned out to be the cascade options I had in my mapping document. Here is now I laid out the relationship previously:
- <many-to-one name="Contest" class="Contest" column="Contest" cascade="all" />
What this does is when the child object is saved/updated/deleted, the parent object would also be saved/updated/deleted. In other words, inserting a child record into the database would result in the parent record being updated, even if no modification was done to the object.
Aside from needlessly running update queries against the database which is bad enough in itself, you might not think this would cause any harm, but in fact it does. In my creation of the instance of the child class, I opened an nHibernate session in order to get an instance of the parent class to set as a property on the child. When I went to persist this child object to the database, I had to open a new session.
This is where the problem is. The parent object was retrieved in one session, and because of the cascade settings, the application needlessly attempted to persist it in another session. After examining the situation, I determined that there was no real business case for any type of cascade in this scenario. So I updated that line in the mapping document as follows:
- <many-to-one name="Contest" class="Contest" column="Contest" cascade="none" />
This makes it my responsibility to perform any cascading changes I would like to be performed. Which, in this case, will never happen. The code was then able to persist the data without throwing the exception, and I had the added benefit of correcting a problematic business rule that shouldn't have existed.