我会试着准确地解释这个问题。
有一个实体A
与B
(一个集合)有一对多关系。
此外,实体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
之一和反之亦然。
最后,事务成功结束:我的意思是实体C
和A
及其关联按预期存储在数据库中。
为什么实体B
关联不会保留在数据库中?我做错了什么?
注意:我使用的是最新版本的NHibernate 3.x系列。
注意2:我刚刚分析了SQL Server数据库,并且永远不会执行m:n表中的插入!
答案 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都是级联触发的,它应该可以正常工作