NHibernate:使用merge()时未更新子复合id

NHibernate:使用merge()时未更新子复合id,nhibernate,merge,save,parent-child,composite-id,Nhibernate,Merge,Save,Parent Child,Composite 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" tab

映射:

    <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>
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 bug的另一个解决方法。不要使用复合ID,或者更好的解决方案是不要使用nHibernate..

我在保存后手动更新了子ID-这只是nHibernate bug的另一个解决方法。不要使用复合ID,或者更好的解决方案是不要使用nHibernate。

我遇到了完全相同的问题。在插入之前,我必须对一些帖子进行更新。然后,当我准备插入时,我得到一个错误,该对象已经在使用中

SaveOrUpdate给了我这个错误,ofc Update也给了我这个错误。合并工作正常,但它只保存父对象,而不保存子对象

不过,连接是子对象是负责执行保存(在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将子对象保存到数据库中(因为SaveOrUpdate仍然会由于对象在上一个会话中使用而给我错误,是的,我尝试了session.Clear()和Flush等等)。效果很好,但后来我注意到我的childobject不再指向它的父对象。因此,childobject现在是一个孤儿,在数据库的街道上哭泣。因此,我们需要做的是将父对象ID再次指向子对象

InfoEntity infoToSave = capMessage.Infos.FirstOrDefault();
infoToSave.AlertEntity_id = capMessage.Id;
_session.Merge(infoToSave);
_session.Merge(capMessage);
你为什么要问?因为nHibernate非常可爱,当它运行Merge时,它不会对childrecords(正如我前面提到的,当你运行SaveOrUpdate时)一语道破。所以当你使用Merge时,你必须自己更新所有childpost,并且你必须再次指出父项


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

我也遇到了同样的问题。在插入之前,我必须对一些帖子进行更新。然后,当我准备插入时,我得到一个错误,该对象已经在使用中

SaveOrUpdate给了我这个错误,ofc Update也给了我这个错误。合并工作正常,但它只保存父对象,而不保存子对象

不过,连接是子对象是负责执行保存(在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将子对象保存到数据库中(因为SaveOrUpdate仍然会由于对象在上一个会话中使用而给我错误,是的,我尝试了session.Clear()和Flush等等)。效果很好,但后来我注意到我的childobject不再指向它的父对象。因此,childobject现在是一个孤儿,在数据库的街道上哭泣。因此,我们需要做的是将父对象ID再次指向子对象

InfoEntity infoToSave = capMessage.Infos.FirstOrDefault();
infoToSave.AlertEntity_id = capMessage.Id;
_session.Merge(infoToSave);
_session.Merge(capMessage);
你为什么要问?因为nHibernate非常可爱,当它运行Merge时,它不会对childrecords(正如我前面提到的,当你运行SaveOrUpdate时)一语道破。所以当你使用Merge时,你必须自己更新所有childpost,并且你必须再次指出父项

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