0

由于我当前的继承,我正在使用具有自动映射功能的 Fluent Nhibernate,并且在设置双向 HasMany 关系时遇到问题。

我的代码的简化版本如下所示

public abstract class BaseClass
{
    public BaseClass Parent { get; set; }
}

public class ClassA : BaseClass
{
    public IList<ClassB> BChilds { get; protected set; }
    public IList<ClassC> CChilds { get; protected set; }
}

public class ClassB : BaseClass
{
    public IList<ClassD> DChilds { get; protected set; }
}

public class ClassC : BaseClass
{
}

public class ClassD : BaseClass
{
}

每个班级可以有一个父母,有些父母可以有两种类型的孩子。我正在使用每个类型的表继承,这会导致表格

  • “基类”
  • “A级”
  • “B级”
  • “C级”
  • “D级”

为了获得有效的双向映射,我进行了以下覆盖(来自 ClassA 的一个示例)

mapping.HasMany<BaseType>(x => x.BChilds).KeyColumn("Parent_Id");
mapping.HasMany<BaseType>(x => x.CChilds).KeyColumn("Parent_Id");

这适用于只有一种子类型的类,但具有两种子类型的 ClassA 将在每个列表中获取 BaseType 的所有子类型,这当然会导致异常。我查看了两种不同的解决方法,但没有一种感觉真的足够,我真的相信有更好的方法来解决它。

解决方法 1:指向 HasMany 映射中的具体子类型。(更新了更多信息)

mapping.HasMany<ClassB>(x => x.BChilds).KeyColumns("Parent_Id"); 

(BaseType 替换为 ClassB)

通过这种映射,NHibernate 在某些情况下会在 ClassB 表中查找名为 Parent_Id 的列,显然没有这样的列,因为它属于 BaseClass 表。仅当您在 ClassA 选择期间添加基于 BChilds 的语句时,才会出现此问题。例如加载 ClassA 的实体然后调用 ClassA.BChilds 似乎可以工作,但是执行查询(使用 NhibernateLinq)类似

Query<ClassA>().Where(c => c.BChilds.Count == 0) 

将使用错误的表。因此,我必须在此表中手动创建一个具有相同名称的新列并复制所有值。它有效,但它有风险,而且根本不灵活。

变通方法 2:向 BaseClass 添加一列以告知具体类型,并向 HasMany 映射添加 where 语句。

(在我更新到 workaround1 之后,我不再确定这是否是一个可行的解决方案)

通过添加一个列,它们与使用带有 discriminatorValue 的 table-per-hierarchy 继承时所做的相同。即 BaseType 表将获得一个值为 ClassA、ClassB 的新列...考虑到 NHibernate 整体处理继承的能力以及通过阅读 NHibernate 手册,我相信每个类型的表中都不需要鉴别器在这种情况下,似乎 Nhibernate 已经在做最难的部分了,应该能够以一种干净的方式处理这个问题,而无需添加新列,只是无法弄清楚如何。

4

1 回答 1

0

你的基类映射是什么,你的子类映射是什么样的?你应该能够做到

mapping.HasMany(x => x.BChilds);

并且使用正确的映射,您应该没有问题。如果它是流利的nhibernate,请查看

UseUnionSubclassForInheritanceMapping();
于 2013-05-26T11:30:45.480 回答