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 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.