我显然遗漏了一些东西(希望很明显),到目前为止我在 Google 上运气不好。
我有一个父子关系映射如下
简化的父 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();
}
}
简化子图
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();
}
}
简化的服务方法步骤
然后我有一个服务方法,它检索 Parent 并通过一些域方法添加一个新的 Child。底层的 NHibernate 代码归结为:
1) 在 WCF AfterReceiveRequest (IDispatchMessageInspector) 上打开 session
_sessionFactory.OpenSession();
2) 通过 .Query 检索现有的 parent 实例
_session.Query<ParentEntity>()
.Where(item => item.Id == parentId)
.Fetch(item => item.SomeLookupColumn)
.First();
3) 通过域对象方法将新的“子”实体添加到“父”,例如...
public ChildEntity CreateChild()
{
var child = new ChildEntity{ Parent = this };
Children.Add(child);
return child;
}
4) 最终调用“父”实体上的 SaveOrUpdate。
// ChildEntity Id is 0
_session.SaveOrUpdate(parentEntity)
// Expect ChildEntity Id to NOT be 0
注意:使用 SaveOrUpdate Does 将更改保存到数据库;使用 Merge 会导致下面提到的 TransientObjectException。
5) 最后,事务在 WCF BeforeSendReply (IDispatchMessageInspector) 上提交
_session.Commit();
问题
通常在保存实体时,在调用 SaveOrUpdate 之后,所述实体的 Id 反射(reflect)由 INSERT 语句生成的身份。但是,当我将新的子实体添加到现有父实体时,Children
中的关联实体未分配 ID。我需要将此 ID 传递回调用方,以便后续调用导致更新而不是额外的插入。
为什么 NHibernate 不更新底层实体? 我是否明确必须对 child 调用 SaveOrUpdate(如果是这种情况,那很糟糕)?
对此事的任何想法都非常感谢。谢谢!
编辑 我应该注意,新的子实体正在按预期保存;我只是没有取回分配的 ID。
更新 尝试按照下面 Michael Buen 的建议切换到 .Merge(~) ;导致 TransientObjectException 告诉我在调用合并之前显式保存修改后的子实体。我也尝试过 .Persist(~) 无济于事。非常感谢任何额外的见解。
object is an unsaved transient instance - save the transient instance before merging: My.NameSpace.ChildEntity
最佳答案
我终于抽出时间来研究 NHibernate 代码……发生这种情况的原因是有道理的……简短的回答——级联操作是在 Session.Commit() 上处理的;在上述服务操作完成后。因此,在服务方法返回更新后的子实体时,我的子对象尚未刷新以反射(reflect)分配的 ID。
事实证明,如果我需要立即知道 Id,我必须直接在子实体上调用 SaveOrUpdate。
关于c# - NHibernate SaveOrUpdate 子集合未使用标识 ID 更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5629358/