用Fluent-nHibernate混合遗传和树结构

用Fluent-nHibernate混合遗传和树结构,nhibernate,class,inheritance,hierarchy,fluent,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 virtua

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

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; }
}
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)
    }
}
公共类地理节点
{
公共虚拟整数Id{get;private set;}
公共虚拟字符串名称{get;set;}
公共虚拟地理位置节点ParentNode{get;set;}
公共虚拟IList子节点{get;set;}
}
公共类区域:地理节点
{
公共虚拟int SomeRegionData{get;set;}
}
公共类国家/地区:地理节点
{
公共虚拟整数SomeCountryData{get;set;}
}
为了映射这一点,我使用了一个表/类层次结构方法。Fluent nHibernate映射如下所示:

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; }
}
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)
    }
}
公共类地理地图:类地图
{
公共地理地图()
{
Id(x=>x.Id);
Map(x=>x.Name);
引用(x=>x.ParentNode);
HasMany(x=>x.ChildNodes).KeyColumn(“Id”).Cascade.All();
区分子类子列(“类型”);
}
}
公共类RegionMap:子类映射
{
公共区域地图()
{
映射(x=>x.SomeRegionData)
}
}
公共类CountryMap:子类映射
{
公共国家地图()
{
映射(x=>x.SomeCountryData)
}
}
这是我的问题:

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

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

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


谢谢

我在我的博客中写到:

它包括一个特殊的强制转换函数,可以正确地强制转换NHibernate代理


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

因为您将其映射为普通引用nhibernate无法在加载父对象时知道类型,因此当lazyloading父对象时,它不知道其类型,并创建基类的代理。有两种补救办法:

  • 禁用引用的懒散加载:
    References(x=>x.ParentNode)。Not.LazyLoad()
  • 将父类型存储在子节点的记录中:
    ReferenceAny x.ParentNode).TypeColumn(“parenttype”)…
    然后NH将创建正确的代理

我倾向于选项1,因为它很简单,而且通常对任何关心它的人来说都不会对性能有多大影响

:继承似乎在ActiveRecord中得到了正确的处理,即父/子节点使用正确的子类实例化,因此可以正确地强制转换。