Ali Baghdadi
Ali Baghdadi

Reputation: 648

NHibernate: trying to save collection of children of the same object type fails

I have a class that has a one-to-many relationship within itself, when trying to save a collection of children, only the first child is being saved, here is my mapping:

 <class name="AMU" table="AMU">
        <id name="ID" column="ID">
          <generator class="identity"/>
        </id>

        <many-to-one name="_Manager" class="AMU" column="ParentID" access="field"/>
        <many-to-one name="User" column="UserID"/>
        <many-to-one name="MCT" column="MctID"/>
        <set name="ManagedAMUs" fetch="select" cascade="all-delete-orphan" inverse="false">
          <key column="ParentID"/>
          <one-to-many class="AMU"/>
        </set>
      </class>

here is the class definition:

public class AMU : TABS.Components.BaseEntity
    {
        public AMU()
        {
            this.User = null;
            this.Manager = null;
            this.ManagedAMUs = new List<AMU>();
        }

        public virtual int ID { get; set; }
        public virtual User User { get; set; }
        private AMU _Manager;
        public virtual AMU Manager
        {
            get { return _Manager; }
            set { _Manager = value; }
        }
        public virtual ICollection<AMU> ManagedAMUs { get; set; }
public virtual MCT MCT { get; set; }
}

when I use a for loop to add several AMUs to a parent AMU

foreach(var amu in AMUList)
{
    myAMU.ManagedAMUs.Add(amu);
}

and then saving the parent AMU, it only saves one child

Upvotes: 1

Views: 391

Answers (1)

Radim K&#246;hler
Radim K&#246;hler

Reputation: 123861

The issue is related to the fact, that NHiberante <set> (in comparison with <bag>) is representing a collection of unique records. How to fix it? There are two, very different ways:

  1. change the mapping from <set> to <bag>
  2. implement the bool Equals(object obj) and int GetHashCode() in the AMU class

The first solution, is in fact saying: collection could contain one same item many times.

The second solution is about handling the word same. How to check if the objects are the same? well from perspective of the <set> the methods GetHashCode() and Equals() are called.

In this case we need to distinguish child objects (becuase of hierarchical nature, the parent as well). It should

  • not be based on the surrogated key (ID) but
  • e.g. on properties like Code or Name... or combination. Or in the example above on the User.ID

NOTE: By the way, even if we change <set> to be a <bag>, our mapped entities should override these methods. It is simply a good practice.

Upvotes: 1

Related Questions