繁体   English   中英

NHibernate中未存储多对多关联

[英]Many-to-many association not stored in NHibernate

我将尝试精确地解释问题。

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

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

当我第一存储类型的暂时对象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都是瞬时对象时都被实例化时,我将实体B之一添加到实体C的集合上,反之亦然。

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

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

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

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

我想回答我自己的问题,以分享解决问题的难易程度,但是很难理解导致问题的根源。

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

configuration.SetListener(ListenerType.FlushEntity, this);

由于模型映射是正确的,因此RadimKöhler(另一个回答者)和我都试图弄清楚为什么未将多对多关系存储到数据库中。

评论整个侦听器绑定可解决此问题。

好吧,问题不在于整个侦听器绑定,而是不调用默认的flush实现,或者,是的,如果不是真的不需要,则不添加整个侦听器(我的情况是,我只是在尝试某种不是我想要的拦截)不再需要!)。

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

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

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

我试图重现您的情况,如下所示:客户端(对象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();

探查器发布和处理的插入内容:

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实例即可...所有其他sutff都是级联触发的,它应该可以工作

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM