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

SO、ご覧のとおり、問題は、親が保存された後に nHib が子を複合 ID に更新せず、子を保存しようとして失敗することです。どうして??これらの ID を更新するように nHib を作成するにはどうすればよいですか? また、Merge() の代わりに SaveOrUpdate() を使用すると、正常に動作します!! しかし、マージを使用する必要があります。助けてください!

4

2 に答える 2

4

保存後に子IDを手動で更新することになりました-nHibernateのバグの別の回避策です。複合 ID を使用しないでください。または、さらに良い解決策として、nHibernate を使用しないでください。

于 2010-11-29T13:10:08.303 に答える
0

私はまったく同じ問題を抱えていました。挿入を行う前に、いくつかの投稿で更新を実行する必要がありました。次に、挿入しようとしたときに、オブジェクトが既に使用されているというエラーが発生しました。

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 が常にクラッシュする場所です)、子レコードの新しいインスタンスを作成するだけです (子レコードは 1 つしかないため、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 を実行したときのように)。したがって、Merge を使用する場合は、すべての子投稿を自分で更新する必要があり、親を再度指定する必要があります。

誰かがこれに対するより良い解決策を知っているなら。お知らせください。それ以外の場合は、この小さなコード例が何らかの形で誰かに役立つことを願っています:)

于 2011-12-15T15:37:10.787 に答える