Search code examples
c#asp.netasp.net-mvcnhibernatenhibernate-mapping

NHibernate not persisting children objects


I have two objects, Parent and Child. I have persisted object Parent parent1. I would like to create a new Child object, set its Parent attribute to "parent1" and add it to collection of Childs on parent1.

Parent

public class Parent: IEquatable<Parent>
{
     public virtual IList<Child> Childs{ get; set; }
     ...
}

Child

public class Child: IEquatable<Child>
{
     public virtual Parent Parent { get; set; }
     ...
}

Parent.hbm.xml

 <bag name="Childs" lazy="false" inverse="true" cascade="all">
   <key column="Id" />
   <one-to-many class="Child" />
 </bag>

Child.hbm.xml

<many-to-one name="Parent">
   <column name="Parent" sql-type="int" not-null="true" />
</many-to-one>

running this code

var child = new Child();
child.Condition = value;
Parent parent= m_parentmanager.Get(2); // "parent1"
parent.Childs.Add(child);
child.Parent = parent;
m_childsmanager.Save(child);

When I call again "Parent parent= m_parentmanager.Get(2)" a few rows below, I can see in debug mode that collection Childs is empty. I have a button to add Child to Parent (to collection Childs) on my View. When I press button first time, this code runs but Childs collection is empty. When I press button second time, Child entity is added to Childs collections. All other button clicks also do not add any new Child entity into collection.

Can anybody tell me what I am doing wrong ?


Solution

  • In DB, a parent's relation to children and children's to parent - are defined by one (the same) column. It is a foreign key in child table. And that must be used on both sides in mapping

    // column must be the one, which is used for many-to-one
     <bag name="Childs" lazy="false" inverse="true" cascade="all">
       <!--<key column="Id" />-->
       <key column="Parent" />
       <one-to-many class="Child" />
     </bag>
    
    // column Parent represents the relation, it must be used for Childs coll as well
    <many-to-one name="Parent">
       <column name="Parent" sql-type="int" not-null="true" />
    </many-to-one>
    

    Also, collections should be loaded lazily. There is no benefit to map them as eager. Rather load it eagerly in query than force that mapping.

    The rest of the mapping seems to be ok - is inversed, and both sides are assign in C# ... it should work