0
votes

I am just learning NHibernate. I have been using examples from the documentation and here at stackoverflow, but I must be missing something.

I have a PARENT object that has a collection of CHILD. A CHILD is meaningless without a PARENT, so the database has FK set to NOT NULL. Implementing NHibernate from CHILD to PARENT works fine, though I have no need for this direction of relationship.

Instead, I tried to implement the PARENT owning the relationship, but I consistently get a Database error bubbling up "Cannot insert the value NULL into PARENT_ID". Neither the ID nor the entity of the PARENT is being stored in the CHILD when saving.

See the code sample below. Please advise.

Class Files

public class PARENT {
   private readonly IList<CHILD> _children = new List<CHILD>();
   public virtual Id { get; set; }
   public virtual void AddChild(CHILD child) {
      _children.add(child);
   }
}
public class CHILD {
   public virtual Id { get; set; }
}

Mappings

<class name="PARENT" table="Parent">
  <cache usage="read-write"/>

  <id name="Id" column="Id" unsaved-value="0" >
    <generator class="identity" />
  </id>

  <bag name="Children" access="field.camelcase-underscore" cascade="all-delete-orphan">
    <key column="ParentId"/>
    <one-to-many class="CHILD"/>
  </bag>

</class>
<class name="CHILD" table="Child">
  <cache usage="read-write"/>

  <id name="Id" column="Id" unsaved-value="0" >
    <generator class="identity"/>
  </id>

</class>
2
not sure if you know but, go here -> summerofnhibernate.com for some really good screencasts on NHibernate! - Perpetualcoder

2 Answers

2
votes

You must define both sides of the relationship in your mapping and object model. You then declare one as inverse="true" in the mapping. So something like this should work:

Class files

public class PARENT {
   private readonly IList<CHILD> _children = new List<CHILD>();
   public virtual Id { get; set; }
   public virtual void AddChild(CHILD child) {
      _children.add(child);
   }
}
public class CHILD {
   public virtual PARENT Parent { get; set; }
   public virtual Id { get; set; }
}

Mappings

<class name="PARENT" table="Parent">
  <cache usage="read-write"/>

  <id name="Id" column="Id" unsaved-value="0" >
    <generator class="identity" />
  </id>

  <bag name="Children" access="field.camelcase-underscore"
     cascade="all-delete-orphan" inverse="true">
    <key column="ParentId"/>
    <one-to-many class="CHILD"/>
  </bag>

</class>
<class name="CHILD" table="Child">
  <cache usage="read-write"/>

  <id name="Id" column="Id" unsaved-value="0" >
    <generator class="identity"/>
  </id>
  <many-to-one name="Parent" class="PARENT" column="ParentId" />

</class>

And you might want to change your AddChild method to this:

public virtual void AddChild(CHILD child) {
   _children.add(child);
   child.Parent = this;
}
0
votes

I had the same problem, for now I just removed the not-null constraints on this kind of foreign keys. Since the database is only used with NH, it is not possible to get any null values there.

I think NHibernate stores the child first. Then it stores the parent. Because you need identity ids, it does not have a primary key for the parent before it is inserted to the database. Then it needs to update the child afterwards.

Try another id generator. hilo is recommended. This is also faster.