我正在设计的模型的一部分是层次结构地理位置。由于有多个层并共享一些信息,我决定使用这样的类层次结构:
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实例化正确的子类似乎是合理的。
在这里使用继承还有什么主要问题吗?使用类层次结构可以减少代码量(至少在模型中),但是我担心拥有这些隐式而非显式的关系(例如区域的父级总是一个国家)可能会让我遇到麻烦。
谢谢!
答案 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,因为它很容易,通常对性能没有多大意义