Tuesday, August 18, 2015

NHibernate: mapping many to many with a linked table

For example I have 2 tables called ClassA and ClassB. 2 classes have connection many to many in the third table called ClassAB. ClassAB is very simple has some columns such as Id, ClassA_Id, ClassB_Id.

public class ClassA
{
public virtual string Name { get; set; }
private IList<ClassB> listB;
public virtual IList<ClassB> ListB
{
get
{
if (listB == null)
listB = new List<ClassB>();
return listB;
}
set { this.listB = value; }
}


public class ClassB
{
   public virtual string Name { get; set; }
   private IList<ClassA> listA;
   public virtual IList<ClassA> ListA
   {
     get
     {
       if (listA == null)
         listA = new List<ClassA>();
       return listA;
     }
     set { this.listA = value; }
   }
}


Mapping file for Class A will be:

<class name="ClassA" mutable="true"  optimistic-lock="none" select-before-update="false" >
    <cache usage="read-write"/>
    <id name="Id" >
      <column name="Id"  not-null="true"/>
      <generator class="guid.comb" />
    </id>

    <property name="Name" type="string" not-null="true"/>
    <idbag name="ListB" lazy="true" table="ClassAB">
      <collection-id column="Id" type="Guid">
        <generator class="guid.comb" />
      </collection-id>
      <key column="ClassA_Id"/>
      <many-to-many column="ClassB_Id" class="ClassB"/>
    </idbag>
</class>

Mapping file for Class B will be same as Class A:

<class name="ClassB" mutable="true"  optimistic-lock="none" select-before-update="false" >
    <cache usage="read-write"/>
    <id name="Id" >
      <column name="Id"  not-null="true"/>
      <generator class="guid.comb" />
    </id>

    <property name="Name" type="string" not-null="true"/>
    <idbag name="ListA" lazy="true" table="ClassAB" >
      <collection-id column="Id" type="Guid">
        <generator class="guid.comb" />
      </collection-id>
      <key column="ClassB_Id"/>
      <many-to-many column="ClassA_Id" class="ClassA"/>
    </idbag>
  </class>



Insert a new ClassB and add a link to ClassA by inserting a record to the linked table

using (var trans = new Transaction())
{

var b = new ClassB();
b.Name = "class b";
SaveOrUpdate(b);
a.ListB.Add(b);
SaveOrUpdate(a);
trans.Commit();
}

Note: If I add an attribute inverse = true at idbag as <idbag name="ListB" lazy="true" table="ClassAB" inverse="true"> NHibernate won't insert into linked table ClassAB.