title: NHibernate mappings when self-join relationships have additional properties
body: <p>How do you map a class to other instances of the same class <em>when that relationship has properties itself</em>?</p>
  
  <p>I have a class called Person which is mapped to a table Person</p>
  
  <pre><code>PersonID   PersonName    PersonAge 
  ----------------------------------
         1   Dave Dee             55
         2   Dozy                 52
         3   Beaky                45
         4   Mick                 55
         5   Tich                 58
  </code></pre>
  
  <p>I want a many-to-many relationship between Person and Person using a join table called PersonPerson:</p>
  
  <pre><code> PersonPersonID  PersonID  RelatedPersonID RelationshipID 
   --------------------------------------------------------
                1         1                5              1
                2         3                4              2
                3         2                1              3
  </code></pre>
  
  <p>I want the following attributes in the PersonPerson table:</p>
  
  <pre><code>RelationshipID  RelationshipName
  --------------------------------
               1  Colleague
               2  Manager
               3  Tutor
  </code></pre>
  
  <p><a href="https://stackoverflow.com/questions/350311/using-additional-data-on-intermediate-table-with-nhibernate/350702#350702">This question</a> and the linked-to <a href="http://devlicio.us/blogs/billy_mccafferty/archive/2008/07/11/when-to-use-many-to-one-s-vs-many-to-many-with-nhibernate.aspx" rel="nofollow noreferrer">post by Billy McCafferty</a> 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 <b>Dave Dee</b> (ID = 1), not only should I get <b>Tich</b> (ID = 5), but I should get also get <b>Dozy</b> (ID = 2) as well because Dave Dee is also in the RelatedPersonID column.</p>
  
  <p>What my solution is so far, is to have two properties in my Person class.</p>
  
  <pre><code>public virtual IList&lt;PersonPerson&gt; PersonPersonForward {get;set;}
  public virtual IList&lt;PersonPerson&gt; PersonPersonBack {get;set;}
  
  private List&lt;PersonPerson&gt; personPersonAll;
  public virtual List&lt;PersonPerson&gt; PersonPersonAll 
  {
     get
     {
         personPersonAll = new List&lt;PersonPerson&gt;(PersonPersonForward);
         personPersonAll.AddRange(PersonPersonBack);
         return personPersonAll;
     }
  }
  </code></pre>
  
  <p>And have the following in the hbm:</p>
  
  <pre><code> &lt;bag name="PersonPersonForward" table="PersonPerson" cascade="all"&gt;
        &lt;key column="PersonID"/&gt;
        &lt;one-to-many class="PersonPerson" /&gt;
   &lt;/bag&gt;
  
   &lt;bag name="PersonPersonBack" table="PersonPerson" cascade="all"&gt;
        &lt;key column="RelatedPersonID"/&gt;
        &lt;one-to-many class="PersonPerson" /&gt;
   &lt;/bag&gt;
  </code></pre>
  
  <p>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?</p>