0
votes

I try to learn NHibernate for the first time. I'm using this book: NHibernate2

There is something I don't understand. On "contact.hbm.xml" mapping file there is defined mapping to OrderHeader table. OrderHeader table has 2 foreign keys to Contact table: "BillToContact_Id" and "ShipToContact_Id".

<bag name="BillToOrderHeaders" inverse="true" lazy="true" 
         cascade="all-delete-orphan">
      <key column="BillToContact_Id"/>
      <one-to-many class="Ordering.Data.OrderHeader, Ordering.Data"/>
    </bag>
    <bag name="ShipToOrderHeaders" inverse="true" lazy="true"
         cascade="all-delete-orphan">
      <key column="ShipToContact_Id"/>
      <one-to-many class="Ordering.Data.OrderHeader, Ordering.Data"/>
    </bag>

In mapping I have cascade="all-delete-orphan". Aa I understand, it is necessary to be set on primary table.

Then mapping on OrderHeader table is:

<many-to-one name="BillToContact" class="Ordering.Data.Contact, Ordering.Data">
      <column name="BillToContact_Id" not-null="false"/>
    </many-to-one>
    <many-to-one name="ShipToContact" class="Ordering.Data.Contact, Ordering.Data">
      <column name="ShipToContact_Id" not-null="false"/>
    </many-to-one>

When I try to save new data:

        ISessionFactory sessionFactory = cfg.BuildSessionFactory();
        ISession session = sessionFactory.OpenSession();
        ITransaction tx = session.BeginTransaction();
        Contact contact = new Contact("Joe", "Jones", "[email protected]");

        Address address = new Address("2000 E. Captive Way", null, "Madville", "MA", "78701");
        address.Contact = contact;
        contact.Addresses = new List<Address>();
        contact.Addresses.Add(address);

        OrderHeader header = new OrderHeader();
        header.Number = "0000001";
        header.OrderDate = DateTime.Now;
        header.BillToContact = contact;
        header.BillToAddress = address;
        header.ShipToContact = contact;
        header.ShipToAddress = address;
        session.SaveOrUpdate(header);
        tx.Commit();

I get an error: object references an unsaved transient instance - save the transient instance before flushing. Type: Ordering.Data.Contact, Entity: Ordering.Data.Contact

Then I have defined also cascade inside child table mapping:

<many-to-one name="BillToContact" class="Ordering.Data.Contact, Ordering.Data" cascade="all-delete-orphan">
      <column name="BillToContact_Id" not-null="false"/>
    </many-to-one>
    <many-to-one name="ShipToContact" class="Ordering.Data.Contact, Ordering.Data" >
      <column name="ShipToContact_Id" not-null="false"/>
    </many-to-one>

I don't understand this. If I add cascade="all-delete-orphan" to BillToContact mapping or to ShipToContact mapping, it works. Doesn't matter, just one of them must have this setting.

As I read if cascade is define on parent, it doesn't have to be defined also on child. But if must be on child, logically would be that it is on both mapping not only on one of them(doesn't matter which one).

Can someone explain?

1
I guess that you have high expectations on the "delete-orphan" feature, where you most probably will get disappointed. - Stefan Steinegger

1 Answers

1
votes

I guess it is a problem of the order. If it tries to store the address first, there is most probably no cascade on Address.Contact.

  • Either cascade for insert-update Address.Contact,
  • or explicitly add the contact before everything is stored.