Problem description:
In my parent class, I have a list of child objects which I want NHibernate to load when I load the parent.
However, I never want NHibernate update the children when I save the parent, I'll do that myself.
Unfortunately however, NHibernate does try to delete the reference to the parent when I save a parent that doesn't reference any children.
This causes and exception to be thrown as the parent reference is a non-null column in my database.
How can this be solved?
NHibernate version:
1.0.3.0
Mapping documents:
Code:
<class name="Parent" table="PARENT">
<id name="ID" column="PARENT_ID" type="Int32" unsaved-value="-1">
<generator class="MyGenerator" />
</id>
<property name="Foo" column="FOO" type="DateTime" />
<bag name="Children" cascade="none">
<key column="PARENT_ID"/>
<one-to-many class="Child"/>
</bag>
</class>
<class name="Child" table="CHILD">
<id name="ID" column="CHILD_ID" type="Int32" unsaved-value="-1">
<generator class="MyGenerator" />
</id>
<property name="Bar" column="BAR" type="Int32" />
<many-to-one name="Parent"
column="PARENT_ID"
class="Parent"
cascade="none" />
</class>
Code between sessionFactory.openSession() and session.close():Roughly something like this:
Code:
public void SaveParentAndChildren( Parent p, IList<Child> children )
{
Debug.Assert( p.ID == -1 );
Debug.Assert( p.Children == null );
// open session and transaction (stripped)
// save the parent
session.Save( p );
// save the children
foreach ( Child c in children )
{
Debug.Assert( c.ID == -1 );
Debug.Assert( c.Parent == p );
session.Save( c );
}
// commit transaction, close session (stripped)
}
public void UpdateSavedParentOnly( Parent p )
{
Debug.Assert( p.ID > 0 );
Debug.Assert( p.Children == null );
// open session and transaction
// update the parent
p.Foo = DateTime.Now;
session.Update( p );
// commit transaction, close session (stripped)
// --> upon committing the transaction, an exception is raised
// because NHibernate tries to update the children as well
}
public void Foobar( )
{
Parent p = new Parent( );
List<Child> children = new List<Child>( );
for ( int i = 0; i < 3; i++ )
children.Add( new Child( ) );
SaveParentAndChildren( p, children ); // works ok
UpdateSavedParentOnly( p ); // throws an exception
}
Full stack trace of any exception that occurs:Quote:
NHibernate.ADOException : could not delete collection: [Parent.Children#3]
at NHibernate.Collection.AbstractCollectionPersister.Remove(Object id, ISessionImplementor session)
at NHibernate.Impl.ScheduledCollectionRemove.Execute()
at NHibernate.Impl.SessionImpl.Execute(IExecutable executable)
at NHibernate.Impl.SessionImpl.ExecuteAll(IList list)
at NHibernate.Impl.SessionImpl.Execute()
at NHibernate.Impl.SessionImpl.Flush()
at NHibernate.Transaction.AdoTransaction.Commit()
Name and version of the database you are using:Gupta SQLBase 9.0.1
The generated SQL (show_sql=true):Code:
UPDATE CHILD SET PARENT_ID = NULL WHERE PARENT_ID = :1
As PARENT_ID is a non-null column, this leads to the above the exception.