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
You could call session.Flush()
, which performs the inserts on the database. This is not ideal because of the impact to performance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With