Question

I have the following problem.

I have a parent class with a collection of child objects.

 public class Parent{

      int _id;
      IList<Child> _childs = new List<Child>();


      public IList<Child> Childs {get;}
 }

 public class Child{

      int _id;
      string _name;
      Parent _parent;

      protected Child(){}

      public Child(Parent parent, string name){
         _parent = parent;
         _name = name;
      }
 }

The classes are mapped with nhibernate for database where the column tblChild.colName has a unique index.

 // Parent
 <bag name="_childs" access="field" cascade="all-delete-orphan" inverse="true">
    <key column="ParentId" />
    <one-to-many class="Parent" />
 </bag>

// Child
<many-to-one name="_parent" column="ParentId" cascade="none" access="field">

My problem: The following code throw exception because of unique index:

 Parent parent = new Parent();
 Child child1 = new Child(parent, "Child1");
 Child child2 = new Child(parent, "Child2");
 Child child3 = new Child(parent, "Child3");

 parent.Childs.Add(child1);
 parent.Childs.Add(child2);
 parent.Childs.Add(child3);

 parentDao.Save(parent);
 parentDao.FlushAndClear();

 Child child4 = new Child(parent, "Child1"); // Duplicate Name
 parent.Childs.Remove(child1);
 parent.Childs.Add(child4);

 parentDao.Save(parent);
 parentDao.FlushAndClear();

The reason for the exception is that NHibernate first inserts child4 and then removes child1. Why does NHibernate do so? Someone an explaination and can help me resolving this problem?

Was it helpful?

Solution

The order of SQL statements is predefined in NHibernate:

The SQL statements are issued in the following order

  • all entity insertions, in the same order the corresponding objects were saved using ISession.Save()

  • all entity updates

  • all collection deletions

  • all collection element deletions, updates and insertions

  • all collection insertions

  • all entity deletions, in the same order the corresponding objects were deleted using ISession.Delete()

NHibernate thinks that new instance of child is actually a new entity. So it inserts it first, violating your database constraint. It means that you have two options:

1) Flush immediately after removing and before adding child.

2) Change your design a bit so that instead of Remove/Add you simply edit the child. This seems more logical because it looks like Child is an entity that is identified by Name. It is not clear why you actually adding and removing same child:

Child child = parent.GetChildByName("Child1");
child.DoSomething();

or like this:

parent.DoSomethingWithChild("Child1");

P.S. I assume your Child.Equals implementation uses name and in your mapping you have <one-to-many class="Child" />, not <one-to-many class="Parent" />. This is probably just a typo.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top