How do you map a class to other instances of the same class when that relationship has properties itself?
I have a class called Person which is mapped to a table Person
PersonID PersonName PersonAge
----------------------------------
1 Dave Dee 55
2 Dozy 52
3 Beaky 45
4 Mick 55
5 Tich 58
I want a many-to-many relationship between Person and Person using a join table called PersonPerson:
PersonPersonID PersonID RelatedPersonID RelationshipID
--------------------------------------------------------
1 1 5 1
2 3 4 2
3 2 1 3
I want the following attributes in the PersonPerson table:
RelationshipID RelationshipName
--------------------------------
1 Colleague
2 Manager
3 Tutor
This question and the linked-to post by Billy McCafferty explains that the PersonPerson relationship has to be promoted from a normal JOIN to an entity in its own right because of the additional columns in the PersonPerson table. However it doesn't explain what to when it is a self-join. The difference being that if I ask for all the related people to Dave Dee (ID = 1), not only should I get Tich (ID = 5), but I should get also get Dozy (ID = 2) as well because Dave Dee is also in the RelatedPersonID column.
What my solution is so far, is to have two properties in my Person class.
public virtual IList<PersonPerson> PersonPersonForward {get;set;}
public virtual IList<PersonPerson> PersonPersonBack {get;set;}
private List<PersonPerson> personPersonAll;
public virtual List<PersonPerson> PersonPersonAll
{
get
{
personPersonAll = new List<PersonPerson>(PersonPersonForward);
personPersonAll.AddRange(PersonPersonBack);
return personPersonAll;
}
}
And have the following in the hbm:
<bag name="PersonPersonForward" table="PersonPerson" cascade="all">
<key column="PersonID"/>
<one-to-many class="PersonPerson" />
</bag>
<bag name="PersonPersonBack" table="PersonPerson" cascade="all">
<key column="RelatedPersonID"/>
<one-to-many class="PersonPerson" />
</bag>
This seems a trifle clunky and inelegant. NHibernate usually has elegant solutions to most everyday problems. Is the above the sensible way of doing this or is there a better way?