2010-11-25 75 views
0

映射:NHibernate的:使用合并时不更新子复合-ID()

<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; } 
} 

单元测试:通过nHib产生

 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(); 

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在父节点保存后不会更新子节点,并且保存子节点的尝试失败。为什么??我如何让nHib更新这些ID?另外,如果我使用SaveOrUpdate()而不是Merge(),它可以正常工作!但我必须使用合并。请帮忙!

回答

3

我最终在保存后手动更新了child ID - 只是nHibernate错误的另一个解决方法。不要使用复合ID,或者更好的解决方案,不要使用nHibernate ..

0

我有完全相同的问题。在我做一个插入之前,我不得不对某些帖子进行更新。然后,当我正要做我的插入时,我得到了该对象已被使用的错误。

SaveOrUpdate给了我那个错误,而且还更新了。合并工作,但它只保存父对象,而不是子对象。

连接虽然是孩子的对象是一个负责执行保存(在MapObject的。

HasMany(x => x.Info) 
      .Cascade.SaveUpdate(); 

所以我猜是公平的,它作为预期还挺工作。

的令人讨厌的部分是,如果你在父对象上使用SaveOrUpdate,它实际上也会更新孩子,因为它理解连接。但是如果你使用合并,它根本不会理解连接!

这里有一段代码

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对象保存到数据库的第一次尝试(因为SaveOrUpdate仍然给我错误,因为前一个会话中使用的对象,并且是的,我尝试了session.Clear()和Flush并且什么不)。它工作桃色,但后来我注意到,我的孩子对象不再指向其父母。所以这个孩子对象现在是一个孤儿在数据库的街道上哭泣。所以我们需要做的是再次将父母ID指向子对象。

InfoEntity infoToSave = capMessage.Infos.FirstOrDefault(); 
infoToSave.AlertEntity_id = capMessage.Id; 
_session.Merge(infoToSave); 
_session.Merge(capMessage); 

为什么你问?因为nHibernate非常可爱,所以当它运行Merge时,它并不会让飞行的荷兰人记住孩子的记录(就像我之前提到的那样运行SaveOrUpdate时)。所以当你使用合并时,你必须自己更新所有的孩子,并且你必须再次指出父母。

如果有人知道更好的解决方案。请告诉我。否则,我希望这个小代码示例以任何方式帮助任何人:)