1

問題を正確に説明しようとします。

(コレクション)と1 対多の関係をA持つエンティティがあります。B

また、エンティティBはエンティティmany-to-manyと関係がありますC

タイプ の一時オブジェクトを最初に保存すると、と関連付けられた関連する一時エンティティ インスタンスAの両方がデータベースに正しく作成されますが、 に関連付けられた一時インスタンスは作成されません。ABACB

多対多の関連付けは、関連付けの両側で次のようにマッピングされます (コードによるマッピング アプローチ)。

// Mapping for collection of Entity C on Entity B
@class.Set
(
    entityB => entityB.EntityCList,
    map =>
    {
        map.Table("EntitiesBInEntitiesC");
        map.Cascade(Cascade.All);
        map.Key(key => key.Column("EntityBId"));
        map.Inverse(false);
    },
    map => map.ManyToMany(relMap => relMap.Column("EntityCId"))
);


// Mapping for collection of Entity B on Entity C
@class.Set
(
    entityB => entityB.EntityBList,
    map =>
    {
        map.Table("EntitiesBInEntitiesC");
        map.Cascade(Cascade.All);
        map.Key(key => key.Column("EntityCId"));
        map.Inverse(true);
    },
    map => map.ManyToMany(relMap => relMap.Column("EntityBId"))
);

また、両方ともまだ一時的なオブジェクトであるエンティティBとエンティティがインスタンス化されると、エンティティのコレクションにエンティティの 1 つを追加し、その逆も行います。CBC

最後に、トランザクションは正常に終了します。これは、エンティティAB、およびそれらの関連付けが期待どおりにデータベースに格納されていることを意味します。

エンティティのC関連付けがデータベースに保持されないのはなぜですか? 私は何を間違っていますか?

  • 注: NHibernate 3.x シリーズの最新バージョンを使用しています。

  • 注 2: SQL Server データベースのプロファイルを作成したところ、m:n テーブルへの挿入は実行されません。

4

2 に答える 2

1

問題を解決するのは簡単でしたが、問題の原因を理解するのがどれほど難しいかを共有するために、私自身の質問に答えたいと思います。

ある種の検証ロジックを追加するつもりだったので、フラッシュ エンティティ イベント リスナーを追加していました。

configuration.SetListener(ListenerType.FlushEntity, this);

モデル マッピングが正しかったため、Radim Köhler (別の回答者) と私は、多対多の関係がデータベースに格納されていない理由を突き止めようとしていました。

リスナーバインディング全体にコメントすると、問題が解決しました。

まあ、問題はリスナーバインディング全体ではなく、デフォルトのフラッシュ実装を呼び出していないか、そうです、本当に必要でない場合はリスナー全体を追加していないだけです(私の場合、私はそうではないある種のインターセプトを試みていましたもう必要です!)。

エンティティのフラッシュ方法を指定するか、デフォルトのものを使用する必要がありますが、空白 (空のイベント リスナー) のままにすると、一部のエンティティが正しくフラッシュされなくなります。

    // WRONG!
    public void OnFlushEntity(FlushEntityEvent @event)
    {
    }

この回答が他の人が同様の問題を解決するのに役立つことを願っています...

于 2013-08-19T17:18:51.387 に答える
0

私はあなたのシナリオを次のように再現しようとしました: 多くの債務者 (オブジェクト C) を参照するより多くの契約 (オブジェクト B) を持つクライアント (オブジェクト A)。andを使用<bag>しますIList<>が、同じように機能します<set>

public class Client
{
    public virtual int ID { get; set; }
    public virtual IList<Agreement> Agreements { get; set; }
    ...
}

public class Agreement
{
    public virtual int ID { get; set; }
    public virtual Client Client { get; set; }
    public virtual IList<Debtor> Debtors { get; set; }
    ...
}

public class Debtor
{
    public virtual int ID { get; set; }
    public virtual IList<Agreement> Agreements { get; set; }
    ...
}

簡素化されたクラス マッピングですが、完全な<bag>マッピング

クライアント:

<class name="Client" table="[dbo].[Client]" lazy="true" >
    <id name="ID" column="[ClientId]" generator="native" />
    ...

    <bag name="Agreements" inverse="true" cascade="all" >
      <key column="AgreementId"></key>
      <one-to-many class="Agreement"/>
    </bag>

合意:

<class name="Agreement" table="[dbo].[Agreement]" lazy="true" >
  <id name="ID" column="[AgreementId]" generator="native" />

  <many-to-one name="Client" column="ClientId" />

  <bag name="Debtors"
    table="[dbo].[AgreementDebtor]" 
    inverse="false" cascade="all" >
    <key column="AgreementId"></key>
    <many-to-many class="Debtor" column="DebtorId" />
  </bag>

債務者:

<class name="Debtor" table="[dbo].[Debtor]" lazy="true" >
  <id name="ID" column="[DebtorId]" generator="native" />

  <bag name="Agreements"
    table="[dbo].[AgreementDebtor]"
    inverse="true" cascade="all" >
    <key column="DebtorId"></key>
    <many-to-many class="Agreement" column="AgreementId" />
  </bag>

このマッピングがあれば、これを次のように呼び出すことができます。

var client = new Client();
var debtor = new Debtor();
var agreement = new Agreement();

agreement.Client = client;
client.Agreements.Add(agreement);

agreement.Debtors.Add(debtor);
debtor.Agreements.Add(agreement);

session.Save(client);
session.Flush();

プロファイラーによって発行された挿入物:

RPC:Completed  exec sp_executesql N'INSERT INTO [dbo].[Client] ...
RPC:Completed  exec sp_executesql N'INSERT INTO [dbo].[Agreement] ...
RPC:Completed  exec sp_executesql N'INSERT INTO [dbo].[Debtor] ...
RPC:Completed  exec sp_executesql N'INSERT INTO [dbo].[AgreementDebtor] (AgreementId, DebtorId) VALUES ...

このように、Client インスタンスを「挿入」するための 1 回の呼び出しだけで...他のすべてのサットフはカスケードでトリガーされ、動作するはずです。

于 2013-08-18T16:28:02.760 に答える