建模(和映射)具有两个多态性程度的类层次结构

本文关键字:程度 多态性 层次结构 两个 映射 建模 | 更新日期: 2023-09-27 18:25:55

在父/子层次结构中,我遇到了两个多态性级别,一个在另一个中。

我认为最好用一个简单的例子来解释这一点:

    class Group
    {
        public IList<Person> People { get; set; }
    }
    class SpecialGroup : Group
    {
        public IList<SpecialPerson> People { get; set; }
    }
    class Person {}
    class SpecialPerson : Person {}

因此,一个Group有一个Person对象列表,而一个专门的Group(SpecialGroup)有一个Person(SpecialPerson)对象的专门列表。

这是编译的,但我收到一条警告,说我应该在SpecialGroup.Peoples上使用"new"关键字,因为它隐藏了Group.Peopes属性。

我理解这意味着什么,但也许我不完全理解如何在C#中正确地建模这样的东西。对如何以更好的方式建模有什么想法吗?

还有,你知道NHibernate会怎么玩吗?我不确定使用"new"关键字是否会减少它,因为Group.People属性可能已经映射为不同的类型。有没有更好的方法来建模,以与NH兼容的方式?


好吧,我想了一种使用泛型建模的方法:

    abstract class AbstractGroup<PersonType>
        where PersonType : Person
    {
        public IList<PersonType> People { get; set; }
    }
    class Group : AbstractGroup<Person>
    {}
    class SpecialGroup : AbstractGroup<SpecialPerson>
    {}
    class Person {}
    class SpecialPerson : Person {}

我想这是我想要的吗?现在Person可以与SpecialPerson共享特征,但只有SpecialPerson可以添加到SpecialGroup中。AbstractGroup基类型可以为任何组的共同特征建模。

现在的问题是,如果我试图绘制这个地图,NH会爆炸吗?


记录在案,似乎有些人已经成功地将query-over与泛型类一起使用了——对于HQL查询(我的用例),这是不受支持的。

我想到的另一种方法是简单地隐藏属性的父级实现,例如,在子类中为重写属性使用"new"关键字-下面的线程讨论了为什么这也不起作用:

NHibernate:每个子类的表映射和新的关键字

到目前为止的结论:运行时检查和异常,正如下面@empi所建议的。

建模(和映射)具有两个多态性程度的类层次结构

这种情况也称为"并行"或"双重"继承。

通常,在一个层次结构中有一个特定的类,它与另一个相关。

虽然不需要,但最好每个类都有一个"泛型"或"抽象"类,必须重写,但已经有了依赖性的概念。

这种情况在图形界面控件中非常常用,可能适用于其他情况。

在这种特殊情况下,通常最好只显示第一级

............................................................
....+----------------+................+----------------+....
....|  <<Abstract>>  |..<<contains>>..|  <<Abstract>>  |....
....| AbstractGroup  +<>--------------+ AbstractPerson |....
....|                |................|                |....
....+----------------+................+----------------+....
............................................................

但是,您可以对多个级别进行建模,这是不推荐的

............................................................
....+----------------+................+----------------+....
....|  <<Abstract>>  |..<<contains>>..|  <<Abstract>>  |....
....| AbstractGroup  +<>--------------+ AbstractPerson |....
....|                |................|                |....
....+-------+--------+................+--------+-------+....
............|..................................|............
............|..................................|............
............^..................................^............
............|..................................|............
............|..................................|............
....+-------+--------+................+--------+-------+....
....|  <<Concrete>>  |..<<contains>>..|  <<Concrete>>  |....
....|      Group     +<>--------------+     Person     |....
....|                |................|                |....
....+----------------+................+----------------+....
............|..................................|............
............|..................................|............
............^..................................^............
............|..................................|............
............|..................................|............
....+-------+--------+................+--------+-------+....
....|  <<Concrete>>  |..<<contains>>..|  <<Concrete>>  |....
....|   SchoolGroup  +<>--------------+     Student    |....
....|                |................|                |....
....+----------------+................+----------------+....
............................................................

您提到NHibernate,您的类是否表示要存储的数据?

一些类似的问题:

避免并行继承层次结构

并行继承层次重构

如何避免GUI控件和域对象之间的并行继承层次结构

C++中接口类与实现类的并行继承

干杯。

如果您想强制执行SpecialGroup只包含SpecialPerson的规则,那么您可以在不隐藏People属性的情况下以程序方式执行。我想你有一些方法AddPerson。如果有人试图添加不是SpecialPerson的条目,您可以在SpecialGroup中覆盖它并抛出异常。如果您想要获得SpecialPerson的列表,那么您可以添加方法IEnumerable<SpecialPerson> GetSpecialPeople()并将Person强制转换为SpecialPerson(由于您在AddPerson方法中检查类型,因此它将始终是有效的强制转换)。通过这样做,你不必跟踪People的财产,NHibernate会很好地工作。