C# Fluent NHibernate:与自定义中间表的多对多关系问题
(更新见底部) 所以,我有两个对象(我们称它们为ClassA和ClassB),它们展示了多对多关系(ClassA可以有多个ClassB对象,反之亦然) 但是,与传统的多对多不同,实际的“关系”本身是一个对象,具有关于其他两个类之间链接的不同信息(关系开始日期、关系名称等) 因此,我没有将其定义为类a和类B之间的多对多关系,而是定义了两个一对多关系(一个在类a和类B上),指向第三个中间类(我们称之为“关系”)。从结构上看,我希望这些表如下所示:C# Fluent NHibernate:与自定义中间表的多对多关系问题,c#,nhibernate,fluent-nhibernate,nhibernate-mapping,fluent-nhibernate-mapping,C#,Nhibernate,Fluent Nhibernate,Nhibernate Mapping,Fluent Nhibernate Mapping,(更新见底部) 所以,我有两个对象(我们称它们为ClassA和ClassB),它们展示了多对多关系(ClassA可以有多个ClassB对象,反之亦然) 但是,与传统的多对多不同,实际的“关系”本身是一个对象,具有关于其他两个类之间链接的不同信息(关系开始日期、关系名称等) 因此,我没有将其定义为类a和类B之间的多对多关系,而是定义了两个一对多关系(一个在类a和类B上),指向第三个中间类(我们称之为“关系”)。从结构上看,我希望这些表如下所示: ClassA
ClassA Relationship
---------------- ----------------
Id (PK) Id (PK)
Name Name
Description StartDate
ClassA_Id (FK)
ClassB ClassB_Id (FK)
----------------
Id (PK)
Name
Description
为了实现这一点,我已经这样设置了映射(经过大量的尝试和错误):
现在,对于添加/删除父对象,his完全按照预期工作。例如,如果我创建了一个新的ClassA和ClassB,通过关系将它们链接起来,然后保存ClassA,那么所有关联的记录都会添加到这三个表中。类似地,如果我删除了相同的ClassA,那么ClassA记录和关系记录将被删除,但ClassB记录将保留(预期行为)
但是,如果我只是尝试从父对象之一(例如classA.Relationships.remove(relationshipObject);classARepository.Update(classA);
)中删除关系,则会出现类似以下错误:
NHibernate.StaleObjectStateException:行被另一个事务更新或删除(或未保存的值映射不正确):[ClassB]
NHibernate.ObjectDeletedException:删除的对象将通过级联重新保存(从关联中删除删除的对象)[Relationship#9]
此外,如果我完全从数据库中重新加载ClassA对象,并如上所述删除成员资格,那么它将无误地执行,但我的关系不会从数据库中删除
我如何改变映射以实现我想要的行为
以下概述了必须通过的场景,以供参考:
- 已添加或更新类别A/B/关系的记录
- 已删除ClassA和关系的记录
- ClassB记录保留在表中
- 从关系表中删除关系
- A类和B类记录保留
- 在关系上取消对ClassA和ClassB的引用:
- 将ClassA/ClassB上的
更改为.Cascade.All()
。这可以防止NHibernate在清空关系对象上的引用后将空白记录插入ClassA和ClassB表中Cascade.AllDeleteOrphan()
您不需要更改映射,您需要将对关系对象中一侧的引用设为null
classA.Relationships.Remove(relationshipObject);
relationshipObject.ClassAObject = null;
session.Flush();
基本上,您需要小心维护关系的两侧,以便内存中的对象图是正确的,并且可以由NHibernate持久化。通常的做法是封装以下内容:
void RemoveRelationship(RelationshipObject relationshipObject)
{
Relationships.Remove(relationshipObject);
relationshipObject.ClassAObject = null;
}
此外,您不太可能需要调用
Update
,只刷新会话或(更好的是)提交事务。+1,这无疑让我走上了正确的轨道(我必须将父对象上的Cascade.All()
更改为Cascade.AllDeleteOrphan()
,因为仅将父对象置零就导致NHibernate在ClassA/ClassB表中插入了空记录。此外,我没有意识到在不显式调用update的情况下会获取对象更改(我对NHibernate非常陌生)。我将用工作代码更新我的问题。
public ClassAMap()
{
Id(x => x.Id);
Map(x => x.Name);
HasMany(x => x.Relationship)
.KeyColumn("ClassA_Id")
.ForeignKeyConstraintName("FK_Relationship_ClassA")
.LazyLoad()
.Cascade.AllDeleteOrphan() // here's the key line
.Inverse();
}
classA.Relationships.Remove(relationshipObject);
relationshipObject.ClassAObject = null;
session.Flush();
void RemoveRelationship(RelationshipObject relationshipObject)
{
Relationships.Remove(relationshipObject);
relationshipObject.ClassAObject = null;
}