使用流畅的nHibernate混合继承和树结构

时间:2010-02-28 09:33:47

标签: nhibernate class inheritance hierarchy fluent

我正在设计的模型的一部分是层次结构地理位置。由于有多个层并共享一些信息,我决定使用这样的类层次结构:

public class GeographicNode
{
    public virtual int Id { get; private set; }
    public virtual string Name { get; set; }
    public virtual GeographicNode ParentNode { get; set; }
    public virtual IList<GeographicNode> ChildNodes { get; set; }
}


public class Region : GeographicNode
{
    public virtual int SomeRegionData { get; set; }
}

public class Country : GeographicNode
{
    public virtual int SomeCountryData { get; set; }
}

要映射这个,我使用的是每个类的表层次结构方法。 Fluent nHibernate映射如下所示:

public class GeographicNodeMap : ClassMap<GeographicNode>
{
    public GeographicNodeMap()
    {
        Id(x => x.Id);
        Map(x => x.Name);
        References(x => x.ParentNode);
        HasMany(x => x.ChildNodes).KeyColumn("Id").Cascade.All();

        DiscriminateSubClassesOnColumn("Type");
    }
}

public class RegionMap : SubclassMap<Region>
{
    public RegionMap()
    {
        Map(x => x.SomeRegionData)
    }
}

public class CountryMap : SubclassMap<Region>
{
    public CountryMap()
    {
        Map(x => x.SomeCountryData)
    }
}

以下是我的问题:

当我获得一个节点并尝试访问ParentNode(或子节点)时,其类型实际上是GeographicNode,而不是相应的子类。因此,例如,如果我获得Region节点并且其父节点应该是Country节点,则我无法将ParentNode强制转换为Country类。

有没有办法强制nHibernate用适当的子类实例化ParentNode和Child对象?此信息存储在Type列中,因此nHibernate实例化正确的子类似乎是合理的。

在这里使用继承还有什么主要问题吗?使用类层次结构可以减少代码量(至少在模型中),但是我担心拥有这些隐式而非显式的关系(例如区域的父级总是一个国家)可能会让我遇到麻烦。

谢谢!

2 个答案:

答案 0 :(得分:0)

我在博客中写到这个: http://mikehadlow.blogspot.com/2010/04/nhibernate-get-vs-load-and-sub-types.html

它包含一个特殊的Cast函数,可以正确地转换NHibernate代理。

然而,最好的解决方案不是强制转换,而是构建正确的多态代码:)

答案 1 :(得分:0)

因为你把它映射为普通引用,所以nhibernate不能知道withoput加载父类的类型,所以当延迟加载父类时它不知道它的类型并创建一个基类的代理。解决这个问题的两个方案:

  • 禁用对引用的延迟加载:References(x => x.ParentNode).Not.LazyLoad();
  • 将父类型存储在子记录中:ReferenceAny<(x => x.ParentNode).TypeColumn("parenttype")...然后NH将创建正确的代理

我赞成选项1,因为它很容易,通常对性能没有多大意义