需要领域建模建议 - 希望是常见的场景

时间:2011-03-28 15:45:46

标签: c# nhibernate inheritance domain-driven-design csla

并提前感谢您的时间。

我们正在使用CSLA 3.5.1,但最终,这个问题可能与CSLA没什么关系。

我的公司在一个常见的建模错误的道路上走了很长一段路,最终不得不面对它。我已经简化了下面的域对象来澄清问题:

我们有3个类定义如下:

类Person:BusinessBase

班级学生:人

班级老师:人

我们正在使用NHibernate作为我们的ORM,Student和Teacher类在我们的映射(我们有Person,Student和Teacher表)中加入了Person的子类,使用PersonID作为派生键。

问题,正如您可能已经预料到的那样,现在我们的情况是学生也可以成为教师。在当前的对象和数据模型下,当我们尝试添加已经是教师的学生时,这会导致主键违规。反之亦然。

问题一:在保存新记录之前,我是否可以对业务对象执行任何CSLA魔术以防止出现这种情况?

如果没有......

在研究这个问题时,我已经看到了两个解决它的建议,第一个是赞成合成而不是继承。据我了解,这意味着学生和教师都将包含人物属性。

问题二:为了使其工作,假设Student和Teacher表需要在Person表中使用外键是否正确?我想我对这个解决方案并不完全了解,并希望得到一些指导。

第二种解决方案是将学生和教师视为某个人扮演的角色。根据我的看法,Person类需要一个Roles集合,链接表(PersonRoles?)用于将Student和Teacher表中的记录映射到Person。

问题三:Role基类和PersonRoles表是什么样的?我相信Student和Teacher子类只包含它们的适当属性。这是对的吗?

对解决方案有何看法?如果有人能在网上找到一个充实的例子,我很乐意看到它。

谢谢,

威尔

3 个答案:

答案 0 :(得分:1)

问题1:据我所知。这并不是说得多;我没有使用CSLA,但我的想法是这是一个NHibernate的东西,必须用NHibernate来解决。

问题2:是的,从概念上讲。一个人有零到一个学生和零到一个教师,但所有学生和教师都需要一个人参考。我使用Fluent NHibernate,所以你必须查找等效的HBM语法,但是:

public class PersonMap:ClassMap<Person>
{
    public PersonMap()
    {
        Table("Person");
        Id(x=>Id).Column("PersonID");
        References(x=>x.Student).KeyColumn("StudentID")
            Nullable().Cascade.All();
        References(x=>x.Teacher).KeyColumn("TeacherID")
            Nullable.Cascade.All();
    }
}


public class TeacherMap:ClassMap<Teacher>
{
    public TeacherMap()
    {
        Table("Teacher");
        Id(x=>Id).Column("TeacherID");
        References(x=>x.Person).KeyColumn("PersonID")
            .Not.Nullable().Cascade.None();        
    }
}

public class StudentMap:ClassMap<Student>
{
    public StudentMap()
    {
        Table("Student");
        Id(x=>Id).Column("StudentID");
        References(x=>x.Person).KeyColumn("PersonID")
            .Not.Nullable().Cascade.None();        
    }
}

现在,Person是此对象图的顶点;您可以检索人员,学生或教师,但在保存更改时,请始终保存人员,并且该人员的子角色也将保留。

答案 1 :(得分:1)

只是详细说明基思的回答 -
Q2。值得补充的是,现在您的对象模型(类)看起来像这样:

    public class Student
{
    public IEnumberable<Class> ClassesIAttend {get; set}
    ...
}

public class Teacher
{
    public IEnumberable<Class> ClassesITeach {get; set;}
    ...
}

public class Person : BussinesBase
{
    //either of these can be null
    private Student studentPart;
    private Teacher teacherPart;

    public bool IsTeacher()
    {
        return teacherPart != null;
    }
}   

Q3。角色,AFAIK,更像是一种行为(通常是授权)的东西。含义 - 您通常不使用角色来存储数据。因此,只有当学生和教师之间的唯一差异是他们被允许执行的行为时,这种方法才适合您 即使在这种情况下,我也会建议不要这样做,因为它不会给你带来很大的灵活性。

总而言之,我认为构图解决方案是您最好的选择。

答案 2 :(得分:1)

您应该设计模型以支持应用程序必须支持的使用方案。

有以下假设:

  • 人可以是班上的老师和/或学生。

模型

Person : BusinessBase<Person> 塑造单一身份。

PersonList : BusinessListBase<PersonList, Person> 系统中所有身份的列表。

Student : BusinessBase<Student> 聚合具有学生附加属性和行为的人员。

StudentList : BusinessListBase<StudentList, Student> 所有学生名单。

Teacher : BusinessBase<Teacher> 聚合具有教师附加属性和行为的人员。

TeacherList : BusinessBase<TeacherList, Teacher> 所有教师名单。

Class : BusinessBase<Class> 模拟单个类

ClassTeacher : BusinessBase<ClassTeacher> 塑造班级老师。

ClassTeacherList : BusinessListBase<ClassTeacherList, ClassTeacher> 班级老师名单。

ClassStudent : BusinessBase<ClassStudent> 为班上的学生建模。

ClassStudentList : BusinessListBase<ClassStudentList, ClassStudent> 班级学生名单。

有了这样一个模型,即使在同一个班级,也没有停止同时成为学生和教师的人。

可以使用NHibernate将每个类(或DTO)映射到相关的数据表。例如,在获取Student时,您可以从Student表和Person表中获取数据。