多对多关联未存储在NHibernate中

时间:2013-08-18 11:18:30

标签: c# .net nhibernate .net-4.5 nhibernate-3

我会试着准确地解释这个问题。

有一个实体AB(一个集合)有一对多关系。

此外,实体B与实体many-to-many具有C关系。

当我第一次存储A类型的临时对象时,在A中与B相关联的瞬态A实体实例都在数据库中正确创建,但是瞬态与C相关联的B个实例未创建。

多对多关联映射到关联的两端,如下所示(按代码映射方法):

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

最后,事务成功结束:我的意思是实体CA及其关联按预期存储在数据库中。

为什么实体B关联不会保留在数据库中?我做错了什么?

  • 注意:我使用的是最新版本的NHibernate 3.x系列

  • 注意2:我刚刚分析了SQL Server数据库,并且永远不会执行m:n表中的插入!

2 个答案:

答案 0 :(得分:1)

我想回答我自己的问题,以便分享解决问题的难易程度,但是如何理解导致问题的原因。

因为我要添加某种验证逻辑,所以我添加了一个 flush实体事件监听器

configuration.SetListener(ListenerType.FlushEntity, this);

由于模型映射是正确的,RadimKöhler(另一个回答者)和我都想弄清楚为什么多对多关系没有存储到数据库中。< / p>

评论整个侦听器绑定解决了这个问题。

嗯,问题不是整个侦听器绑定而是没有调用默认的flush实现,或者是的,如果不是真的需要它就不添加整个侦听器(我的情况下,我只是尝试某种拦截,我“我不再需要了!”。

您需要提供实体刷新或使用默认实体的方式,但将其留空(空事件侦听器)将阻止某些实体正确刷新:

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

希望这个答案可以帮助其他人解决类似的问题......

答案 1 :(得分:0)

我试图像这样重现你的场景:一个客户端(对象A)有更多的Identmnts(对象B)引用许多Debtors(对象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();

由探查者发布和插入的插入内容:

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都是级联触发的,它应该可以正常工作