9

I have Two Table , tableA and tableB.

tableA have column : tabAId, col2, col3 (tabAId primaryKey and Identity column.)

tableB have column : tabAId, name (tabAId is not null)

I have create Bag in hbm file of tableA, to maintain relation ship.

<bag name="tableB" lazy="true" inverse="false"
                    batch-size="25" cascade="all-delete-orphan">
  <key column="tabAId" />
  <one-to-many class="tableB" />
</bag>

When I try to update record in tableA it throw exception, where as I have list of child in tableA instance.

[NHibernate.Exceptions.GenericADOException] = {"could not delete collection: [MIHR.Entities.tableA.tableB#21][SQL: UPDATE dbo.tableB SET tabAId = null WHERE tabAId = @p0]"}

InnerException = {"Cannot insert the value NULL into column 'tabAId', table 'SA_MIHR_DEV.dbo.tableB'; column does not allow nulls. UPDATE fails.\r\nThe statement has been terminated."}

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
Amit Kumar
  • 5,888
  • 11
  • 47
  • 85

1 Answers1

12

There are only two ways how to solve this.

1) do not use inverse="false"

<bag name="tableB" lazy="true" inverse="true" // instead of false
                    batch-size="25" cascade="all-delete-orphan">
  <key column="tabAId" />
  <one-to-many class="tableB" />
</bag>

This setting (inverse="true") will instruct NHibernate to directly delete an item from DB.

While using inverse="false" will in general always lead to:

  • UPDATE (with null) == act of removing from collection
  • DELETE item == act of cascade

2) make the reference column nullable

That means, that we can leave NHibernate to do UPDATE and DELETE. Because column is now nullable.

These are only two ways how to solve it here.

My preference would be: inverse="true"

To work properly with inverse="true" we always have to assign both sides of relation in C#. This is a must for Add(), INSERT operation:

Parent parent = new Parent();
Child child = new Child
{
    ...
    Parent = parent,
};
// unless initialized in the Parent type, we can do it here
parent.Children = parent.Children ?? new List<Child>();
parent.Children.Add(child);

// now just parent could be saved
// and NHibernate will do all the cascade as expected
// and because of inverse mapping - the most effective way
session.Save(parent);

As we can see, we have assigned - explicitly - both sides of relationship. This is must to profit from NHibernate inverse mapping. And it is also good practice, because later, when we load data from DB we expect, that NHibernate will take care about setting that for us

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335
  • 1
    If I set Inverse="true" then It will not insert newly generated Identity column value into child table , while inserting new record in parent table . – Amit Kumar May 05 '15 at 06:56
  • Kohler : Please tell me how to do , when I will set `inversr="true"` . – Amit Kumar May 05 '15 at 06:58
  • Now you should see that ... I updated my answer. Of course, your child entity must have reference to Parent. Check this http://stackoverflow.com/a/30005490/1679310 for ALL DETAILS – Radim Köhler May 05 '15 at 07:01
  • Kohler: let me do it in your way . – Amit Kumar May 05 '15 at 07:03
  • Kohler : 1- It will throw you exception when you will try to add child items in list, as you haven't initialize child object. 2- Add Parent object in child , it will create circular referance . – Amit Kumar May 05 '15 at 07:23
  • There is NO problem with circular reference. the Circular reference is what we **need**. We must be sure that Parent knows about Child and Child knows about Parent. It is what we want... Check my link for all the details – Radim Köhler May 05 '15 at 07:27
  • Here is expressed what is the "good practice" for collection mapping. http://stackoverflow.com/a/30005490/1679310. And you almost have that. just the inverse="true" should be used. If then you will use my code snippet to assign parent and child... and call session.Save(parent)... all will work as expected. – Radim Köhler May 05 '15 at 07:44
  • Seems it helped a bit. That is amazing. Enjoy mighty NHibernate, sir! It is great tool ;) – Radim Köhler May 05 '15 at 08:06