A Teacher has a one-to-one with a Student.
A SpecialTeacher extends Teacher but deals specifically with SpecialStudents.
Using table per class in the hierarchies.
public class Teacher
{
public virtual int Id { get; set; }
public virtual int DepartmentId { get; set; }
public virtual String Name { get; set; }
public virtual Student Student { get; set; }
}
public class SpecialTeacher : Teacher
{
public virtual string TelephoneNumber { get; set; } //SpecialTeachers get to have a phone
public virtual SpecialStudent SpecialStudent { get { return (SpecialStudent)base.Student; } set { Student = value; } }
}
public class Student
{
public virtual int Id { get; set; }
public String Name { get; set; }
}
public class SpecialStudent : Student
{
public int SpecialMark { get; set; }
}
and the associated mappings:
<class name="Student">
<id name="Id" />
<property name="Name" />
</class>
<joined-subclass name="SpecialStudent" extends="Student">
<key column="Id" />
<property name="SpecialMark" />
</joined-subclass>
<class name="Teacher">
<id name="Id" />
<property name="DepartmentId" />
<property name="Name" />
<many-to-one name="Student" column="StudentId" />
</class>
<joined-subclass name="SpecialTeacher" extends="Teacher">
<key column="Id" />
<property name="TelephoneNumber" />
</joined-subclass>
So, let's say that we want to get the average mark for SpecialStudents for a given department:
public double GetAverageScoreForSpecialStudentsByDepartment(int departmentId)
{
return CurrentSession.Query<SpecialTeacher>()
.Where(st => st.DepartmentId == departmentId)
.Average(ss => ss.SpecialStudent.SpecialMark);
}
The test will fail because it will complain that SpecialStudent is not a mapped property of SpecialTeacher.
The only way that I can think of avoiding this issue is to map the property, but this is duplication since the base Teacher is already mapped to the Student hierarchy.
Update
I meant to also mention that previously we had the SpecialTeacher set up like:
public class SpecialTeacher : Teacher
{
public virtual string TelephoneNumber { get; set; } //SpecialTeachers get to have a phone
public virtual new SpecialStudent Student { get { return (SpecialStudent)base.Student; } set { Student = value; } }
}
which did appear to work ok, but Envers did not work with it when retrieving audited data.