[英]Many-to-many association not stored in NHibernate
我将尝试精确地解释问题。
有一个实体A
与B
(集合)具有一对多关系。
另外,实体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
的集合上,反之亦然。
最后,事务成功结束:我的意思是,实体A
和B
以及它们的关联按预期存储在数据库中。
为什么实体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.