[英]NHibernate: child composite-id is not updated when using merge()
制圖:
<class name="PhoneTypeTest" lazy="false" table="PhoneType">
<cache usage="read-write"/>
<id name ="Id" type="Int32" unsaved-value="0">
<generator class="identity"/>
</id>
<bag name="Resources" table="PhoneTypeResource" lazy="false" cascade="all" inverse="true">
<key column="PhoneTypeId" />
<one-to-many class="PhoneTypeTestResource" not-found="ignore"/>
</bag>
</class>
<class name="PhoneTypeTestResource" lazy="false" table="PhoneTypeResource">
<composite-id class="CCCC.ResourcesCompositeKey, DDDD" name="Id">
<key-property name="OwnerId" column="PhoneTypeId"/>
<key-property name="CultureId"/>
</composite-id>
<property name="Name"/>
</class>
實體:
public class PhoneTypeTest
{
public PhoneTypeTest()
{
Resources = new List<PhoneTypeTestResource>();
}
public virtual int Id { get; set; }
public virtual IList<PhoneTypeTestResource> Resources { get; set; }
}
public class PhoneTypeTestResource
{
public virtual ResourcesCompositeKey Id { get; set; }
public virtual string Name { get; set; }
}
單元測試:
var ent = new PhoneTypeTest();
ent.Resources.Add(new PhoneTypeTestResource { Id = new ResourcesCompositeKey { CultureId = En, OwnerId = 0 }, Name = "Name" });
Session.Merge(ent);
Session.Flush();
Session.Clear();
由nHib生成的SQL:
-- statement #1
INSERT INTO PhoneType
DEFAULT VALUES
select SCOPE_IDENTITY()
-- statement #2
SELECT phonetypet0_.PhoneTypeId as PhoneTyp1_61_0_,
phonetypet0_.CultureId as CultureId61_0_,
phonetypet0_.Name as Name61_0_
FROM PhoneTypeResource phonetypet0_
WHERE phonetypet0_.PhoneTypeId = 0 /* @p0 */
and phonetypet0_.CultureId = 'en' /* @p1 */
-- statement #3
INSERT INTO PhoneTypeResource
(Name,
PhoneTypeId,
CultureId)
VALUES ('Name' /* @p0 */,
0 /* @p1 */,
'en' /* @p2 */)
-- statement #4
ERROR:
Could not synchronize database state with session
因此,如您所見,問題在於nHib在保存其父代后不更新子代的復合ID,並且保存子代的嘗試失敗。 為什么?? 如何使nHib更新這些ID? 另外,如果我使用SaveOrUpdate()而不是Merge(),則效果很好! 但是我必須使用合並。 請幫忙!
保存后,我最終手動更新了子ID-這只是nHibernate錯誤的另一種解決方法。 不要使用復合ID,或者甚至是更好的解決方案,也不要使用nHibernate。
我有同樣的問題。 在插入之前,我必須對某些帖子進行更新。 然后,當我要插入時,我得到了該對象已在使用中的錯誤。
SaveOrUpdate給了我這個錯誤,並且也提供了更新。 合並工作但它僅保存父對象,而不保存子對象。
不過,連接是子對象是負責執行保存操作的對象(在mapobject中)。
HasMany(x => x.Info)
.Cascade.SaveUpdate();
因此,我想公平地說,它確實按預期工作。
令人討厭的部分是,如果您在父對象上使用SaveOrUpdate,它實際上也會更新子對象,因為它了解連接。 但是,如果您使用Merge,它將根本無法理解連接!
這是一些代碼
public AlertEntity InsertCapAlerts(AlertEntity capMessage)
{
using (var transaction = _session.BeginTransaction(IsolationLevel.ReadCommitted))
{
var getCap = GetCapAlert(capMessage.Id);
if (getCap != null)
{
InfoEntity infoToSave = capMessage.Infos.FirstOrDefault();
_session.Merge(infoToSave);
_session.Merge(capMessage);
}
else
_session.Save(capMessage);
transaction.Commit();
return capMessage;
}
}
基本上,我所做的是,當我獲取要保存的新capMessage時,我首先檢查它是否已存在於數據庫中。 如果沒有,那就很好,只需執行Save()即可。 但是,如果確實存在(這是SaveOrUpdate總是崩潰的地方),那么我只是創建一個子記錄的新實例(因此,我們只有一個孩子,因此是FirstOrDefault())。
我第一次嘗試使用Merge將Child對象保存到db中(因為由於該對象在上一個會話中使用,因此SaveOrUpdate仍然會給我錯誤,是的,我確實嘗試了session.Clear()和Flush等等)。 它工作得像桃子,但后來我注意到我的子對象不再指向其父對象。 因此,子對象現在是在數據庫街道上哭泣的孤兒。 因此,我們需要做的是再次將父ID指向子對象。
InfoEntity infoToSave = capMessage.Infos.FirstOrDefault();
infoToSave.AlertEntity_id = capMessage.Id;
_session.Merge(infoToSave);
_session.Merge(capMessage);
你為什么問? 因為nHibernate非常可愛,所以當它運行Merge時,它不會給子記錄帶來麻煩(就像我前面提到的那樣運行SaveOrUpdate時)。 因此,當您使用“合並”時,必須自己更新所有子帖子,並且必須再次指出“父”。
如果有人知道更好的解決方案。 請告訴我。 否則,我希望這個小代碼示例可以以任何方式幫助任何人:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.