1

我会尽量准确地解释这个问题。

有一个实体与(集合)A具有一对多关系。B

此外, entity与 entityBmany-to-many关系C

当我第一次存储类型的瞬态对象时AA与相关的瞬态B实体实例A都在数据库中正确创建,但CB不会创建

多对多关联在关联的两边映射如下(mapping-by-code方式):

// 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和实体C都是瞬态对象时被实例化时,我在实体B集合上添加实体之一C,反之亦然。

最后,事务成功结束:我的意思是实体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

我试图像这样重现你的场景:一个客户(对象 A)有更多的协议(对象 B)引用许多债务人(对象 C)。我将使用<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();

Profiler 发布和发布的插入内容:

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 ...

这样,只需一次调用“插入”客户端实例......所有其他 sutff 都在级联中触发,它应该可以工作

于 2013-08-18T16:28:02.760 回答