Achieving NHibernate Nested Transactions Behavior
Asked Answered
D

2

5

I'm trying to achieve some kind of nested transaction behavior using NHibernate's transaction control and FlushMode options, but things got a little bit confusing after too much reading, so any confirmation about the facts I list below will be very usefull.

What I want is to open one big transaction that splits in little transactions. Imagine the following scenario:

  • TX1 opens a TX and inserts a Person's record;
  • TX2 opens a TX and updates this Person's name to P2;
  • TX2 commits;
  • TX3 opens a TX and updates this Person's name to P3;
  • TX3 rollbacks;
  • TX1 commits;

I'd like to see NH sending the INSERT and the TX2 UPDATE to the database, just ignoring what TX3, as it was rolled back.

I tried to use FlushMode = Never and only flushing the session after the proper Begins/Commits/Rollbacks have been demanded, but NH always update the database with the object's final state, independent of commits and rollbacks. Is that normal? Does NH really ignores transactional control when working with FlushMode = Never?

I've also tried to use FlushMode = Commit and openning the nested transactions, but I discovered that, because ADO.NET, the nested transactions are, actually, always the same transaction.

Note that I'm not trying to achieve a "all or nothing" behavior. I'm looking more to a savepoint way of working. Is there a way to do that (savepoints) with NH?

Thank you in advance.

Filipe

Deraign answered 19/4, 2010 at 19:5 Comment(2)
What is the practical advantage of using nested transactions like this?Lots
Paco, the idea is that we can have "containers" with transacional behavior associated to it. That's an integration framework that we are building and we can have different blocks whose transacional behavior differs: entities A and B are inserted together and any error will cause an entire rollback, but entity C is a third part of the same integration that must continue even on error. The scenario is a little bit complex, but I hope this description hope you understand. I was expecting ansers to confirm my understanding and will try to figure out some other way to solve these problems. Tnks.Deraign
D
8

Just to don't leave this question open forever, I'll post the solution that we've adopted.

We have a unit of work like container that manages the nested transaction behavior. Depending on the kind of treatment that we want, it creates (or not) new sessions. By example:

  • Continue on error: if we want that even if on a transaction error the other ones commits, the UoW container uses different sessions for each "transaction" and flushes every tx in the end of its work;
  • Rollback on error: if we want that on a session rollback (because of an error or a business rollback) every other transaction gets rolled back, the UoW container uses the same session for all of the nested transactions and rolls back everybody in the end.

It's important to say that the "transaction" that this UoW manipulates isn't the NH (ADO.NET) transaction directly. We've created an abstraction of a transaction so the manipulation code "votes" if our transaction might be commited or rolled back, but the real action just occurs in the end of everything, based on the selected error strategy.

We know that this usage isn't very common and only fits on specific scenarios (in our case it's an integration scenario with batch processing), so I'll now post code. If anyone thinks that this implementation can help, please, send me a message and I'll be glad to share the code.

Regards,

Filipe

Deraign answered 26/4, 2010 at 21:9 Comment(0)
P
1

NHibernate does not support nested transactions. Each ISession can have at most one active transaction. I'm not sure what you;re trying to accomplish because your example scenario doesn't make sense to me. Committing transaction 1 after the insert would have the same effect.

Possibly answered 20/4, 2010 at 2:33 Comment(3)
Jamie, but depeding on business questions I could want to rollback TX 1, and the behavior I want is that it would rollback ALL inserts/updates executed. My comment above, to Paco, gives a broader understanding of the situation. I'll try to find another way to solve the problem. I'll post back if I find another way.Deraign
Perhaps you could isolate each container in its own unit of work (ISession) which could then have its own transaction. You could combine ISessions using Lock or Merge to combine containers in a transaction.Possibly
Jamie, that's the way I'm going. I haven't thought about combining the different sessions (there's no need to it until now), but it'll probably fit in some situation in the future. Anyway, we'll isolate each container in a unit of work that provides the nested feature managing all commits/rollbacks in the end. I'll post the final solution after we advance a little bit more over here. Thank you.Deraign

© 2022 - 2024 — McMap. All rights reserved.