【发布时间】:2013-05-20 23:06:12
【问题描述】:
我正在使用具有自动映射功能的 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
{
}
每个班级可以有一个父母,有些父母可以有两种类型的孩子。我正在使用 table-per-type 继承,这会导致表格
- “基类”
- “A 类”
- “B 类”
- “C 类”
- “D 类”
为了获得有效的双向映射,我进行了以下覆盖 (A类的一个例子)
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 语句。
(在我更新解决方法1 后,我不再确定这是否是一个可行的解决方案)
通过添加一列,它们的方式与使用带有 discriminatorValue 的 table-per-hierarchy 继承时相同。即 BaseType 表将获得一个值为 ClassA、ClassB 的新列...考虑到 NHibernate 整体处理继承的能力以及通过阅读 NHibernate 手册,我相信每个类型的表中都不需要鉴别器在这种情况下,似乎 Nhibernate 已经在做最难的部分了,应该能够以一种干净的方式处理这个问题,而无需添加新列,只是无法弄清楚如何。
【问题讨论】:
标签: nhibernate fluent table-per-type