views:

824

answers:

1

Hi,

I'm having one self-referencing class. A child has a reference to its parent and a parent has a list of children. Since the list of children is ordered, I'm trying to map the relation using NHibernate's .

This is my mapping:

<class name="MyClass">
  <id name="Id">
    <generator class="native"/>
  </id>
  <list name="Children" cascade="delete" inverse="true">
    <key column="ParentId"/>
    <index column="ListOrder"/>
    <one-to-many class="MyClass"/>
  </list>
  <many-to-one name="Parent" class="MyClass" column="ParentId"/>
</class>

The problem I'm having is when having a bi-directional mapping child<->parent, the list index (ListOrder) isn't updated in the database when I do my CRUD dance. This means that when I e.g. remove a child, I get holes in the children list after saving to the database and fetching the parent again. If I remove the bidirectionality, by not having a many-to-one from the children to the parent (and no inverse=true), the ListOrder is updated correctly.

Have any of you seen this before? Is there any simple solution?

+1  A: 

Yes, it's because of inverse=true, an alternate solution would be to use a set or bag instead of list with order="ListOrder", add the ListOrder column as a property to the MyClass class with an empty setter and a getter that always returns it's index from it's parent's child collection. Like this:

<class name="MyClass">
    <id name="Id">
        <generator class="native"/>
    </id>
    <bag name="Children" cascade="delete" inverse="true" order-by="ListOrder">
        <key column="ParentId"/>
        <one-to-many class="MyClass"/>
    </bag>
    <property name="ListOrder" column="ListOrder"/>
    <many-to-one name="Parent" class="MyClass" column="ParentId"/>
</class>

and the class

public class MyClass
{
    public virtual int ID { get; set; }
    public virtual IList<MyClass> Children { get; set; }
    public virtual MyClass Parent { get; set; }

    public virtual int ListOrder
    {
        get
        {
            if (Parent == null || !Parent.Children.Contains(this)) return -1;
            return Parent.Children.IndexOf(this);
        }
        set { }
    }
}
Andrei Silviu
Thanks for your suggestion.In my code today, I use hooks when adding/removing children to set the ListOrder correctly. I'm basically working around NHibernate not working as I expect by adding logic in my domain.Your suggestion is another domain layer workaround. It may be better than mine, but still a workaround. If the semantics for my list is a list, I want to map it as a list, not as a sorted bag.
Thomas Lundström

related questions