Mouhong Lin
Mouhong Lin

Reputation: 4509

NHibernate one-to-many mapping: Insert Child Item Problem

Here is my code:

Order order = new Order { ... };
OrderItem item = new OrderItem { ... };
order.Items.Add(item);
item.Order = order;

using(var tran = session.BeginTransaction()) {
    session.Save(order);
    // Without this, an exception will be thrown: Unexpected row count: 0; expected: 1
    // session.Save(item);

    tran.Commit();
}

If I uncomment the line session.Save(item), it will insert the order and its item. Otherwise, it throw the exception "Unexpected row count: 0; expected: 1".

If I mark the many end (Items property) as inverse="true", no exception will be thrown, but it inserts only the Order! The order item won't be inserted to the DB.

If I call session.Save(item) without calling session.Save(order), it inserts both the order and it's item.

How can I save the order and its order items without calling session.Save(orderItem) but only call session.Save(order) ? Thanks!

Here is my mappings:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="Core" assembly="Core">
  <class name="Order" table="[Order]">
    <id name="Id">
      <generator class="assigned" />
    </id>

    <property name="Name" />
    <bag name="Items">
      <key column="CategoryId" />
      <one-to-many class="Core.OrderItem, Core"/>
    </bag>
  </class>

  <class name="OrderItem">
    <id name="Id">
      <generator class="assigned" />
    </id>
    <property name="Title" />
    <many-to-one name="Order" column="OrderId" cascade="save-update" not-null="true" />
  </class>

</hibernate-mapping>

Upvotes: 1

Views: 5039

Answers (2)

Florian Lim
Florian Lim

Reputation: 5362

Try putting the cascade in your Order mapping:

<bag name="Items" cascade="all">
  <key column="CategoryId" />
  <one-to-many class="Core.OrderItem, Core"/>
</bag>

Upvotes: 2

jishi
jishi

Reputation: 24614

Because you don't have any cascade on the Order.Items collection, it will not automatically create the item for you when you save your Order.

But you do cascade from Item to Order, so when you save Item, it will also update Order.

When you specified inverse="true" you told NHibernate not to update the "Item.Order" property automatically, and that you will handle that manually. Therefor the Order is never associated when you add it to the collection hence never shows up there after the commit.

I think you just need to add:

<bag name="Items" cascade="all">

and it will create, update, delete items that belongs to orders.

EDIT: of course cascade goes on the bag, not the one-to-many node.

Upvotes: 5

Related Questions