【问题标题】:Fluent NHibernate HasMany relation with different subtypes of same superclassFluent NHibernate HasMany 与同一超类的不同子类型的关系
【发布时间】: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


    【解决方案1】:

    您的基类映射是什么?您的子类映射是什么样的? 你应该可以做到

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

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

    UseUnionSubclassForInheritanceMapping();
    

    【讨论】:

    • 我正在使用自动映射,所以除了提到的覆盖之外,我没有任何真正的 classMap。 mapping.HasMany(x =&gt; x.BChilds); should be the same as mapping.HasMany&lt;ClassB&gt;(x =&gt; x.BChilds); 即与我的解决方法 1 相同(使用错误的表)我将查看 UseUnionSubclassForInheritanceMapping();
    • 查看 UseUnionSubclassForInheritanceMapping 我的第一个理解是您将使用该技术或鉴别器技术。通过将其添加到我的映射中,我无法注意到任何不同,因此我怀疑这是已经在使用的策略。我将详细说明我的问题何时出现错误表的问题,经过所有来回测试后我的脑海中滑落的东西。基本上,如果使用上面的映射加载 ClassA 对象,则调用 ClassA.BChilds 将给出正确的结果,但 NhibernateLinq 查询将使用错误的表。
    猜你喜欢
    • 2010-11-02
    • 1970-01-01
    • 1970-01-01
    • 2014-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多