NHibernate cascading problems

442 Views Asked by At

I have this mapping in one class:

<class name="Parent">
<set name="Activity" table="ChangeLogs" order-by="ChangeDate desc" cascade="all-delete-orphan">
  <key column="RequestID" />
  <one-to-many class="ChangeLog" />
</set>

And this in the other:

<class Name="Child">
<many-to-one name="Request" class="Request" column="RequestID" />

In the parent, loaded in the current transaction I add to the collection:

parent.Activity.Add(new Child(){/* properties, etc */});

And then I commit the transaction. Any changes to the parent get saved to the database with an update call, but I can't get those children to insert, regardless of cascade values or inverse=true/false/just-save-already. I've been bashing my head against it for a while, reading examples / documentation / etc, and I can't see why it wouldn't work. Am I missing something simple? I've been killing off the server and re-building after every change to make sure things are updating, but nada.

To make matters worse, occasionally it has worked, with various values for inverse, sometimes by adding the Request=parent to the child, sometimes by saving the child separately before adding... and then it quits working later on. I'm boggling o_O

edit: Things tried explicitly since this was posted, rebuild + server restart between every one, none of which generate an insert call or errors:

<set inverse=true>
parent.Activity.Add(new Child(){Request=parent})
<set inverse=true>
parent.Activity.Add(new Child(){})
<set>
parent.Activity.Add(new Child(){Request=parent})
<set>
parent.Activity.Add(new Child(){})
<set inverse=false>
parent.Activity.Add(new Child(){Request=parent})
<set inverse=false>
parent.Activity.Add(new Child(){})

This did work:

<set>
Child c = new Child() {Request = parent};
parent.Activity.Add(c);
Session.Save(c);

But then what's the point of setting a cascade if it's ignored?

edit: after reading a bit of this: http://nhibernate.info/doc/nh/en/index.html#example-parentchild-bidir I tried:

<class Name="Child">
<many-to-one name="Request" class="Request" column="RequestID" not-null=true />

with all 6 of the main ones above, with no luck.

2

There are 2 best solutions below

1
On

This is the correct mapping:

<class name="Parent">
  ...
  <set cascade="all-delete-orphan" inverse="true" ...>
  ...
  </set>
</class>
<class name="Child">
  ...
  <many-to-one .../>
</class>

And the correct usage (assumes an already existing parent):

using (var tx = session.BeginTransaction())
{
    var parent = GetParent();
    parent.Collection.Add(new Child { Parent = parent });
    tx.Commit();
}
3
On

For me it's always a problem to set it properly at one go. At first everything looks good in your code, but I'm actually wondering on which side you are setting the inverse property?

This code works for me:

<class name="Parent" table="Parent">

<bag name="Languages" inverse="true" cascade="all-delete-orphan" lazy="false" fetch="join">
  <key column="parentId" />
  <one-to-many class="Language" />
</bag>

<class name="Language" table="Language">

<many-to-one column="parentId" name="Parent" class="Parent" not-null="true" />

I hope this helps.