Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NHibernate: Cascading saves to children does not insert

I have a bidirectional association like this:

public class Parent
{
  public int ParentId {get; set;}
  ...other properties
  public IEnumerable<Child> Children {get; set;}
}

public class Child
{
  public int ChildId {get; set;}
  ...other properties
  public Parent Parent {get; set;}
}

The fluent mappings are as follows:

Parent mapping

Id(x => x.ParentId, "PARENT_ID").GeneratedBy.Identity();
.. other mappings
HasMany(x => x.Children).Cascade.All().KeyColumn("PARENT_ID");

Child mapping

Id(x => x.ChildId, "CHILD_ID").GeneratedBy.Identity();
.. other mappings
References(x => x.Parent).Column("PARENT_ID").Cascade.None();

When I execute code like this:

Parent parent = new Parent{ ..set some properties... };
parent.Children = new[] { new Child{ ..set some properties.. };
session.Save(parent);

I get a foreign key constraint violation because NHibernate is not setting the PARENT_ID column of the child record to the new ID when it attempts to insert the child.

Clearly I have requested cascading in the mapping for Parent. NHibernate is trying to save the child, but why is the ID not being set?

like image 445
David Avatar asked Mar 22 '23 16:03

David


1 Answers

You need to make two changes.

  1. You need .Inverse() on the HasMany(x => x.Children). See my answer explaining inverse for more information.
  2. You also need to add child.Parent = parent; to the code that saves the entities.

In your case, the two relationships are conflicting with one another. parent.Children contains child, which means that NHibernate should persist Child.PARENT_ID as the parent's Id, but child.Parent is null, meaning that NHibernate should persist Child.PARENT_ID as null. Apparently child.Parent won. Actually, what's more likely is that they both won. NHibernate was probably executing two queries similar to these...

/* This is what child.Parent says we should save.
   This query will fail because PARENT_ID is NOT NULL. */
insert into Child (CHILD_ID, PARENT_ID) values (@childId, null);

/* This is what parent.Children says we should save. */
update Child set PARENT_ID = @parentId where CHILD_ID = @childId;

If you make the two changes I recommend above, NHibernate will be able to save this correctly, like so:

insert into Child (CHILD_ID, PARENT_ID) values (@childId, @parentId);
like image 77
Daniel Schilling Avatar answered Mar 31 '23 21:03

Daniel Schilling