流畅的nhibernate - 在同一实体上的多对多关系映射

时间:2011-04-19 14:27:18

标签: c# nhibernate fluent-nhibernate many-to-many entity-relationship

我在尝试绘制多对多关系时遇到问题,关系的两边都引用了同一个实体。我正在使用Fluent NHibernate和NH3.1。

基本上,情景是这样的 - 我有一个类别,可以有多个父母。因此,一个类别有多个其他类别作为父母,以及多个其他类别作为其子女。

HasManyToMany(x => x.ParentCategories).AsBag().Table("parentcategorychildren").ParentKeyColumn("ChildID").ChildKeyColumn("ParentID").Cascade.SaveUpdate();
HasManyToMany(x => x.ChildrenCategories).AsBag().Table("parentcategorychildren").ParentKeyColumn("ParentID").ChildKeyColumn("ChildID").Inverse();

但是,当我尝试构建工厂时,出现以下错误:

  

Category.ChildrenCategories与Category.ChildrenCategories的关系在双方都指定了Inverse。从关系的一侧移除逆。

我发现奇怪的是为什么它将Category.ChildrenCategories提到Category.ChildrenCategories,而不是ParentCategories?

非常感谢任何帮助!

我刚刚为此创造了一笔赏金,因为这对我来说非常重要。拜托,我对“你不能这样做”不感兴趣。

3 个答案:

答案 0 :(得分:12)

这很可能是一个FNH错误,很可能已在最新的FNH source code中修复。使用FNH1.0和NH2.1时没有问题。等效的HBM映射在FNH1.2和NH3.1中运行良好:

<bag name="ParentCategories" cascade="all" table="parentcategorychildren">
    <key column="ChildID" />
    <many-to-many column="ParentID" class="Category" />
</bag>

<bag name="ChildrenCategories" inverse="true" table="parentcategorychildren">
    <key column="ParentID" />
    <many-to-many column="ChildID" class="Category" />
</bag>

编辑: 在深入了解FNH源代码后,我发现了一种解决方法。假设您的配置如下所示:

.Mappings(m => {
    m.FluentMappings.AddFromAssemblyOf<Category>();
})

此配置可以抑制不幸的代码:

.Mappings(m => {
    var persistenceModel = new PersistenceModel();
    persistenceModel.AddMappingsFromAssembly(typeof(Category).Assembly);
    persistenceModel.ValidationEnabled = false; // this makes the trick
    m.UsePersistenceModel(persistenceModel);
})

答案 1 :(得分:7)

这是Fluent NHibernate 2.1验证/关系配对的问题。 FNH pairs up relationships然后validates that only one side of the relationship has .Inverse() specified。因为两个引用(父/子)都属于同一个类,所以它们在配对时都是候选匹配。在那种情况下,FNH matches on name similarity。因此,他们每个人都与自己配对而不是彼此配对。因此,将.Inverse()置于其中任何一个上都会触发验证(该对的两侧都是相反的相反关系)。

应该可以使用FluentMappingsContainer上的OverrideBiDirectionalManyToManyPairing()方法更正此问题。理论上,这将允许您显式配对子关系和父关系。但是,在FNH 2.1中存在一个错误,并且永远不会调用覆盖回调。 (The callback value is captured before it can be set by the method)。

作为解决方法,您可以禁用FNH中的所有验证。有only two validations。首先,关系的双方都没有.Inverse()。其次,Id映射在每个实体上。我发现禁用验证的最简洁方法是:

.Mappings(m => {
    var persistenceModel = new PersistenceModel() { ValidationEnabled = false };
    m.UsePersistenceModel(persistenceModel)
     .FluentMappings.AddFromAssemblyOf<Category>();
})

此方法允许您禁用验证,但仍然使用FluentMappings配置的完整表现力。

答案 2 :(得分:0)

是的,在我看来,它很可能是FNH中的一个错误,因为我直接使用NHibernate尝试了它而不使用Fluent NH并且它有效。但是,由于我已经使用FNH建立了一个系统,我不能只是恢复使用它。

我所做的是我自己创建的“中间阶级”,用于多对多关系,通常是自动生成的。我创建了一个ContentPage_ChildLink页面,该页面链接了ParentsChildren类别。这使我能够与FNH合作并解决问题:)

ContentPage_ChildLink基本上会有两个字段ChildIDParentID。然后,我可以单独设置“反向”关系,没有任何问题。

FNH的问题似乎是当你有一个多对多的关系时,双方是同一个类,我能想到的唯一情况是允许多个父母的层次结构。