I am clearly missing something (hopefully obvious), and I have had no luck with Google so far.
I have a Parent-Child relationship mapped as follows
Simplified Parent Map
public sealed class ParentMap : ClassMap<ParentEntity>
{
public ParentMap()
{
Table("Parent");
Component(x => x.Thumbprint);
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.ServeralNotNullableProperties).Not.Nullable();
HasMany(x => x.Children).KeyColumn("ChildId")
.Inverse()
.LazyLoad()
.Cascade
.AllDeleteOrphan();
References(x => x.SomeUnrelatedLookupColumn).Column("LookupColumnId").Not.Nullable();
}
}
Simplified Child Map
public sealed class ChildMap : ClassMap<ChildEntity>
{
public ChildMap()
{
Table("Child");
Component(x => x.Thumbprint);
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.MoreNotNullableProperties).Not.Nullable();
References(x => x.Parent).Column("ParentId").Not.Nullable();
}
}
Simplified Service Method Steps
I then have a service method that retrieves Parent and adds a new Child via some domain method. The underlying NHibernate code boils down to:
1) Session Opened on WCF AfterReceiveRequest (IDispatchMessageInspector)
_sessionFactory.OpenSession();
2) Retrieve existing instance of parent via .Query
_session.Query<ParentEntity>()
.Where(item => item.Id == parentId)
.Fetch(item => item.SomeLookupColumn)
.First();
3) Add new 'Child' entity to 'Parent' via domain object method such as...
public ChildEntity CreateChild()
{
var child = new ChildEntity{ Parent = this };
Children.Add(child);
return child;
}
4) Ultimately calls SaveOrUpdate on 'Parent' entity.
// ChildEntity Id is 0
_session.SaveOrUpdate(parentEntity)
// Expect ChildEntity Id to NOT be 0
Note: Use of SaveOrUpdate Does persist changes to database; use of Merge results in TransientObjectException mentioned below.
5) Finally, transaction committed on WCF BeforeSendReply (IDispatchMessageInspector)
_session.Commit();
The Problem
Typically when an entity is saved, after the call to SaveOrUpdate, the Id of said entity refects the Identity generated by the INSERT statement. However, when I add a new child entity to an existing parent, the associated entity in Children
does not get assigned an Id. I need to pass this Id back to the caller so subsequent calls result in UPDATES and not additional INSERTS.
Why is NHibernate not updating the underlying entity? Do I explicitly have to call SaveOrUpdate on the child (that sucks if that is the case)?
Any thoughts on the matter greatly appreciated. Thanks!
EDIT I should note, that the new child entity IS being saved as expected; I just don't get back the Id assigned.
UPDATE Tried switching to .Merge(~) as suggested by Michael Buen below; resulting in a TransientObjectException telling me to explicitly save my modified child entity before calling merge. I also experimented with .Persist(~) to no avail. Any additional insight greatly appreciated.
object is an unsaved transient instance - save the transient instance before merging: My.NameSpace.ChildEntity