0

映射:

    <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(),它工作正常!!但我必须使用合并。请帮忙!

4

2 回答 2

4

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

于 2010-11-29T13:10:08.303 回答
0

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

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

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

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

你为什么问?因为 nHibernate 太可爱了,当它运行 Merge 时,它​​不会给出关于子记录的飞行荷兰语(就像我之前提到的运行 SaveOrUpdate 时那样)。因此,当您使用 Merge 时,您必须自己更新所有子帖子,并且必须再次指出父帖子。

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

于 2011-12-15T15:37:10.787 回答