I have an identifying relationship between two tables in the database.
The parent table has a primary key that is generated via an Identity. The child table has a primary key that is the identity-generated primary key from the parent table. It’s a true one-to-one.
I’ve tried several mapping strategies, with all sorts of results, none of them perfect.
The parent mapping file has this (notice the Cascade.All() – I expect the parent to manage the relationship):
HasOne(x => x.ChildObject).Cascade.All();
The child mapping has this:
Id(Reveal.Member<ChildObject>("ID"))
.GeneratedBy.Foreign("ParentObject");
HasOne(Reveal.Member<ChildObject, ParentObject>("ParentObject"))
.Constrained()
.ForeignKey();
I changed the object names to protect the innocent.
So here’s what happens. I create an instance of the parent, I create an instance of the child and set the relationships (add the Child to the Parent, and the Parent to the Child).
I run this code:
session.SaveOrUpdate(_Parent);
session.Clear();
transaction.Commit();
What I expect to happen is the Parent gets saved, with the ID being updated in the parent from the database. Then the ID should be set in the Child, and the Child saved.
Instead, the Parent gets saved, but not the Child (I can see the insert statements nHibernate is executing, and the Child object never appears in the database).
The Child has the ID from the parent (it’s being propagated from Parent to Child correctly), but nHibernate doesn’t recognize the Child as dirty (a guess on my part). Even if I explicitly try a SaveOrUpdate on the Child object, it doesn’t get saved.
But it gets a bit weirder. If I attach a collection of dirty objects to the Child, and I call SaveOrUpdate explicitly on the Child, nHhiberante will persist the Child, and the collection – the expected behaviour. But I still have to call it explicitly.
What mistake have I made mapping the Parent-Child relationship?
My guess is that parent.Id is generated by identity.
the line
session.SaveOrUpdate(_Parent);will save the parent to get its id and cache the Insert of the Child to flush on commit.session.Clear();will then remove the cached Insert andtransaction.Commit();wont find anything to do.