0
votes

I'm having an issue with NHibernate when I try to save an entity that has a collection of other entities.

The example, Order and OrderLine. OrderLine is associated to Order with a Bag. Its cascade is set to Delete-Orphan and when I call SaveOrUpdate for an Order I call SaveOrUpdate for its OrderLines.

The exception occurs in the Order's SaveOrUpdate, but only if my OrderLine's collection is not null.

Before having the cascade set to "delete-orphan" I had "all-delete-orphan" and I thought I could leverage the OrderLine's SaveOrUpdate to NHibernate. The problem is that each OrderLine has a Number that must be unique. If I remove an OrderLine with Number=2 and add a new OrderLine with Number=2 it will throw an exception when I attempt to save again, because NHibernate inserts and updates new registries before deleting the old orphans.

Because of this, I thought that saving my Order entity (which had its Number=2 OrderLine removed from the collection) would delete that OrderLine and then, calling SaveOrUpdate for the current OrderLines would save them correctly with no unique key violations.

Turns out it didn't, because i get an exception when saving the Order itself.

Any help would be very appreciated. Thanks

2

2 Answers

0
votes

I think you've run into an order of operations problem with NHibernate sessions. NHibernate always does inserts first and deletes last. The only solution that comes to mind is to flush the session in between removing and adding items to the collection. Your process might look something like:

var session = factory.OpenSession();
var tx = session.BeginTransaction();

order.Lines.Remove(line);

// Write out the SQL up to this point, inside the transaction
session.Flush();

order.Lines.Add(new OrderLine(...));

tx.Commit();
0
votes

thanks for your answer.

The "No collection snapshot.." exception is thrown even if I create a new Order, add new OrderLines to the collection and call SaveOrUpdate for the Order object. It doesn't even require a flush or commit to throw the exception. It's in the SaveOrUpdate invocation. It doesn't have to do with unique constraint for the OrderLine.Number.

Anyway, the solution I've come up with is:

  • Map the OrderLines bag with cascade="all-delete-orphan" (leveraging the OrderLines saves/updates/deletes)
  • Remove the unique constraint for OrderLine.Number in the database.
  • Use an assertion in the SaveOrUpdate method of my OrderRepository class (i'm using SharpArchitecture) to make sure that I'll never save an order that has two or more orderlines with the same number.

I don't like this solution..but it works for now.

I'd like to hear some more thoughts about this, and how people often solve this problem with NHibernate (Order with OrderLines and the bag mapped with cascade="all-delete-orphan")