Maintaining Parent/Child relations with NHibernate

Discussion of open issues, suggestions and bugs regarding Entity Developer - ORM modeling and code generation tool
Post Reply
doubret
Posts: 4
Joined: Fri 15 Mar 2013 13:25

Maintaining Parent/Child relations with NHibernate

Post by doubret » Fri 15 Mar 2013 13:29

Hello, i posted this on stackoverflow, but as it is strongly related to Entity Developer i repost it here.


I'm using Entity Developer to generate business classes and mapping from a DB in c#.

I've used Entity Framework before and it looks like the pilosophy in NHibernate is quite different.

For instance my problem is that classes generated by Entity Developer expose the relations between different entities but do nothing to keep these relations in sync.

Let's take the simple Parent/Child example. I have created two Parent and Child tables in a DB, and Child table has a ParentId column wich is a foreign key to the Parent table.

Entity Developer generated Parent and Child classes, with a Parent property in the Child class, and a collection of Child in the Parent class.

Now, this code generates the exception because the Child instance didn't get its Parent property set :

Code: Select all

class Program
{
    static void Main(string[] args)
    {
        Parent parent = new Parent();
        Child child = new Child();

        parent.Children.Add(child);

        if (child.Parent == null)
        {
            throw new Exception("The parent in the Child entity was not set");
        }
    }
}
The same code with Entity Framework doesn't throw the exception. Classes generated by EF embed all the logic to keep the relations in sync at both sides.

I wonder if there is a way to generate the same behaviour and use NHibernate as a mapper ? Is this a limitation of Entity Developer ? Is there another tool that can generate entity classes capable of maintaining these relations in sync ? Or did i configure Entity Developer wrong ?

Thanks in advance.

EDIT

Here are the mappings :

Code: Select all

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping default-cascade="save-update" assembly="ConsoleApplication6" namespace="ConsoleApplication6" xmlns="urn:nhibernate-mapping-2.2">
  <class name="Child" table="Child" schema="dbo">
    <id name="Id" type="Int32">
      <column name="Id" not-null="true" precision="10" scale="0" sql-type="int" />
      <generator class="identity" />
    </id>
    <many-to-one name="Parent" class="Parent">
      <column name="ParentId" not-null="true" precision="10" scale="0" sql-type="int" />
    </many-to-one>
  </class>
</hibernate-mapping>

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping default-cascade="save-update" assembly="ConsoleApplication6" namespace="ConsoleApplication6" xmlns="urn:nhibernate-mapping-2.2">
  <class name="Parent" table="Parent" schema="dbo">
    <id name="Id" type="Int32">
      <column name="Id" not-null="true" precision="10" scale="0" sql-type="int" />
      <generator class="identity" />
    </id>
    <bag name="Children" inverse="true" generic="true">
      <key>
        <column name="ParentId" />
      </key>
      <one-to-many class="Child" />
    </bag>
  </class>
</hibernate-mapping>

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Re: Maintaining Parent/Child relations with NHibernate

Post by Shalex » Tue 19 Mar 2013 16:43

doubret wrote:The same code with Entity Framework doesn't throw the exception. Classes generated by EF embed all the logic to keep the relations in sync at both sides.
This behaviour depends on the implementation of a particular ORM framework: EF adds a reference to the parent object in the child object, but NHibernate does not do that because the collections used in NHibernate are not strongly typed (the type of collection members is determined in runtime).

You can initialize child.Parent manually but NHibernate doesn't provide "tools" (firing events when parent object is modified/removed) for updating the corresponding child.Parent property.

doubret
Posts: 4
Joined: Fri 15 Mar 2013 13:25

Re: Maintaining Parent/Child relations with NHibernate

Post by doubret » Tue 19 Mar 2013 17:51

the collections used in NHibernate are not strongly typed (the type of collection members is determined in runtime)
Not sure about what you mean here, the type of the collection is generic and perfectly knows the type of objects they contain.

Code: Select all

        public virtual Iesi.Collections.Generic.ISet<Child> Children
        {
            get;
            set;
        }
I agree that this is not directly related to NHibernate though as NHibernate only "maps" business objects with a database.

On the other hand many developers are used to use their ORM to generate their business classes directly from the database.
That's my case, and in this case the work done by the generator is not enough.

If i had to develop the parent/child relationship myself, i would never let someone access the parent child.Parent setter. I would have a child.SetParent(Parent parent) method instead, to take care of the relationship logic.

The way this coherency is automaticaly handled by EF or L2S is a good option for them over NH in my opinion.

I think that a generator like Entity Developer could easily integrate such a mechanism over NH. Would be a great advantage as i didn't find any generator for NH that supported it.

Thanks.

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Re: Maintaining Parent/Child relations with NHibernate

Post by Shalex » Thu 21 Mar 2013 17:40

doubret wrote:
the collections used in NHibernate are not strongly typed (the type of collection members is determined in runtime)
Not sure about what you mean here, the type of the collection is generic and perfectly knows the type of objects they contain.
Sorry for the misprint. I meant "the type of collection itself is determined by NHibernate in runtime". A similar issue was discussed at http://forums.devart.com/viewtopic.php?f=32&t=22950.
doubret wrote:I think that a generator like Entity Developer could easily integrate such a mechanism over NH.
NHibernate collections do not provide firing events so that we can implement the logic to keep the relations in sync at both sides.

doubret
Posts: 4
Joined: Fri 15 Mar 2013 13:25

Re: Maintaining Parent/Child relations with NHibernate

Post by doubret » Thu 21 Mar 2013 18:12

The event mechanism is not needed to implement a system taking care of the relationship.

In fact LinqToSql doesn't implement it using events.

On the child side, they just generate a Parent setter taking care of removing the child from the old parent and adding it to the new parent. Trivial.

On the parent side, they have an attach/detach mechanism plugged to the collection of children. This is convenient and i'm not sure if collections used in NH can do this natively.
Anyway, writing an helper for this is not hard at all and can be made non intrusive.

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Re: Maintaining Parent/Child relations with NHibernate

Post by Shalex » Tue 26 Mar 2013 16:50

The INotifyPropertyChanged interface is not implemented in the NHIbernate collections. That's why we do not have a technical possibility to implement a proper relation synchronization at a parent side when a child side is changed.

doubret
Posts: 4
Joined: Fri 15 Mar 2013 13:25

Re: Maintaining Parent/Child relations with NHibernate

Post by doubret » Tue 26 Mar 2013 17:37

You DON'T need NHibernate to implement INotifyPropertyChanged to implement the relation sychronization.

On the parent side, just implement the ICollection interface as a proxy to the real collection and do your stuff in the Add/Remove methods. That's enough to keep the relation in sync.

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Re: Maintaining Parent/Child relations with NHibernate

Post by Shalex » Fri 29 Mar 2013 17:42

doubret wrote:implement the ICollection interface as a proxy to the real collection
There is no way to do that because the type of the collection is determined by NHibernate in runtime (e.g.: Iesi.Collections.Generic.ISet is only interface, not a particular type).

Post Reply