NHibernate Common Exceptions

Description
Table of Contents
Summary

Description of NHibernate frequent exceptions.

Operations
NHibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: XXX

It occurs when the session is flushed to the database, i.e. data changes are written to the database.

This exception is telling that an object is being saved but it references another object that isn’t saved.

Remarks

A flush can occur when/before:

- some invocations of Find() or Enumerable()
- explicitly invocation of NHibernate.ITransaction.Commit()
- explicitly invocationfrom ISession.Flush()

How to do it

In order to handle this exception the following scenarios must be equated:

Scenario 1: No cascade options were configured.
In this case the child or referenced objects must be saved first.

Scenario 2: Cascade options were not configured for all INPUT; UPDATE or DELETE operations.
In this case the configuration must be changed or  child or referenced objects must be saved first.

Scenario3: Related transient objects where instantiated and associated to the persitent object but no save operation is to be performed on those objects.
In this case the trainsient objects must be detached from the current session through the command:
ISession.Evict(obj) 

NHibernate.AdoNet.TooManyRowsAffectedException: Uxpected row count: XX; expected: YY

This exception is caused by the existence of triggers for INSERT, UPDATE or DELETE operations on the table corresponding to one of the mapped entities.

This exception occurs when a flush operation is performed on the current session.

How to do it

In order to avoid this situation the SET NOCOUNT ON statement must be introduced on each of the triggers associated activated during the INSERT, UPDATE or DELETE operation.

NHibernate.StaleStateException: Uxpected row count: 0; expected: 1

Nhibernate is trying to remove an object that was already removed.

How to do it

In order to handle this exception the following scenarios must be equated:

Scenario 1: A trigger exists on the table of the maped object that interferes with cascadings, especially during the DELETE operation - NHibernate is trying to delete an entiity that was already deleted during the execution of the trigger.

In this case the trigger must be changed (to avoid remotion of certain objects) or the cascading options should be changed namelly the option must be used  ”save-update”.

Scenario 2: When there are two mappings for the same relationship (for: example many-to-many and many-to-one) or when the same relationship can be updated by different entities.

To avoid this exception, at least one of the relations should have the inverse attribute set to “true” on one of the mappinged relationship sides.

ADOException: Could not delete collection

During the remotion of a collection (and the relation is not marked as inverse = “true”) , and due to cascade options, NHibernate executes an UPDATE statement to set to NULL the foreign-key column in the child table. The error occurs because the column can no be set to NULL.

How to do it

In order to avoid this error one of the following options must be applied:

Option 1: Active attribute inverse=true on the mapping file; or

Option 2: Alter table definition in order to  allow the foreign-key column to be set to NULL

NonUniqueObjectException: a different object with the same identifier value was already associated with the session

The object being saved already exists in the session.

How to do it

The exception occurs when calling “ISession::SaveOrUpdate”.

In this case the method “ISession::Merge()” can me called on the object being saved. The merge will copy the value(s) of the transient object to the persistent object.

NHibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): nn, of class: XXX

It occurs when an entity object is being explicitly deleted through the ISession::Delete() method and when saving the parent entity object is trying to re-save it because it still has a reference to it.

How to do it

Scenario 1: One-to-Many relationship and cascade option “all-delete-orphan” is not configured in the mapping file of the parent entity

In this case the child object reference must be removed from the parent collection before delete the child object:

lvParent.ChildCollection.Remove(child);
lvSession.Delete(child);

Scenario 2: One-to-One relationship and cascade option “all-delete-orphan” is not configured in the mapping file of the parent entity

In this case the child object reference must be removed from the parent  before delete the child object:

lvParent.child = null;
lvSession.Delete(child);

Scenario 3: One-to-Many relationship and cascade option “all-delete-orphan” is configured in the mapping file of the parent entity

In this case the child object reference must be removed from the parent collection. When saving the parent object the cascade option will implicitly delete on the database the child object if it is no longer referenced for any other object

lvParent.ChildCollection.Remove(child);
...
lvSession.SaveOrUpdate(parent/aggregate root object);

Scenario 4: One-to-One relationship and cascade option “all-delete-orphan” is configured in the mapping file of the parent entity

In this case the child object reference must be removed from the parent. When saving the parent object the cascade option will implicitly delete on the database the child object if it is no longer referenced for any other object:

lvParent.Child = null;
...
lvSession.SaveOrUpdate(parent/aggregate root object);

 

NHibernate.HibernateException: identifier of an instance of XXX altered from nn to mm

This ocurrs when an attempt to change the Id of a status instance was done, which is illegal.

How to do it
lvItem = lvSession.Load<Status>(12);
...

// illegal
lvItem.status.id = 10;

// Instead this should be done:
lvItem.status = lvSession.Load<Status>(10);
Message System.Data.SqlClient.SqlException: Cannot insert the value NULL into column

It occurs when a relationship is being cleared, a foreign key exists, and NHibernate is trying to set the foreign key column on the child row to null. Since SQL Server does not allow nulls in that column the error is thrown.

How to do it

Example of code in errror:

lvParent.Children.Clear()

One solution is to set cascade option to “all-delete-orphan”. This informs NHibernate that it should delete the newly orphaned rows instead of setting the foreign key column.