开发者

Need domain modeling advice - hopefully common scenario

开发者 https://www.devze.com 2023-02-20 12:50 出处:网络
and thanks in advance for your time. We are using CSLA 3.5.1, although, ultimately, this problem may not have much to do with CSLA.

and thanks in advance for your time.

We are using CSLA 3.5.1, although, ultimately, this problem may not have much to do with CSLA.

My company has gone a long way down the road of a common modeling error and is finally having to face it. I've simplified the domain objects below to clarify the problem:

We have 3 classes defined as such:

class Person : BusinessBase

class Student : Person

class Teacher : Person

We are using NHibernate for our ORM, and the Student and Teacher classes are joined subclasses of Person in our mappings (we have Person, Student, and Teacher tables), using the PersonID as a derived key.

The problem, as you may have anticipated, is now we have a situation开发者_Python百科 where a Student can also be a Teacher. Under the current object and data models, this causes a primary key violation when we try to add a Student that is already a Teacher or vice-versa.

Question One: Is there any CSLA magic I can perform on the business object before saving the new record to prevent this situation?

If not...

In researching this problem, I've seen two suggestions to solve it, The first is to favor composition over inheritance. To my understanding, this means Student and Teacher would each contain a Person property.

Question Two: In order to get this to work, is it correct to assume the Student and Teacher tables would need a foreign key into the Person table? I guess I don't have a complete understanding of this solution, and would like some guidance.

The second solution involves thinking of Student and Teacher as Roles a given person plays. From what I've seen, the Person class would need a Roles collection, and link table (PersonRoles?) is used to map the records in the Student and Teacher tables to the Person.

Question(s) Three: What do the Role base class and the PersonRoles table look like? I believe the Student and Teacher subclasses would just contain their appropriate properties. Is this correct?

Any opinions on a solution? If anyone can find a fleshed-out example on the web, I'd love to see it.

Thanks,

Will.


Question 1: Not to my knowledge. That's not saying much; I haven't used CSLA, but my thoughts are that this is an NHibernate thing, and has to be solved with NHibernate.

Question 2: Yes, conceptually. A Person has zero to one Students and zero to one Teachers, but all Students and Teachers require a Person reference. I use Fluent NHibernate for this, so you'll have to look up the equivalent HBM syntax, but:

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();        
    }
}

Now, Person is the apex of this object graph; you may retrieve People, Students or Teachers, but when saving changes, always save the Person, and the child roles of that Person will also be persisted.


just to elaborate on Keith's answer-
q2. it's worth adding that now your object model (classes) would look something like so:

    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. roles, AFAIK, is more of a behavioral (usualy authorization) thing. Meaning- you don't usually use roles to store data. so this approach would be advisable for you only if the only differences between Student and Teacher are the actions they're allowed to perform.
Even in that case I would recommend against it, since it doesn't leave you with much flexibility for the future.

All in all, I think the composition solution is your best bet.


You should design the model to support the usage scenarios your application must support.

With the following assumptions:

  • Person can be Teacher and/or Student in a Class.

Model

Person : BusinessBase<Person> Models a single identity.

PersonList : BusinessListBase<PersonList, Person> List of all identities in system.

Student : BusinessBase<Student> Aggregates a Person with additional properties and behaviour for student.

StudentList : BusinessListBase<StudentList, Student> List of all students.

Teacher : BusinessBase<Teacher> Aggregates a Person with additional properties and behaviour for teacher.

TeacherList : BusinessBase<TeacherList, Teacher> List of all teachers.

Class : BusinessBase<Class> Models a single class

ClassTeacher : BusinessBase<ClassTeacher> Models a teacher of a class.

ClassTeacherList : BusinessListBase<ClassTeacherList, ClassTeacher> List of a class' teachers.

ClassStudent : BusinessBase<ClassStudent> Models a student in a class.

ClassStudentList : BusinessListBase<ClassStudentList, ClassStudent> List of a class' students.

With such a model there's no stopping Person from simultaneously being Student and Teacher even in the same class.

Each class (or DTO for such) can be mapped to the relevant data tables using NHibernate. For example, when fetching a Student you could be fetching data from the Student and Person tables.

0

精彩评论

暂无评论...
验证码 换一张
取 消