Usage of TransactionManager

Usage of TransactionManager

Old forum URL: forums.lhotka.net/forums/t/8183.aspx


amir.gheibi posted on Friday, December 18, 2009

I'm trying to figure out what's the best way to use the "TransactionManager".
Let me provide an example:
There is an Editable Collection class called "Activities". Sometimes this class is used as part of something bigger, like an engine, which initiates a transaction using "TransactionManager" and updates "Activities" and some other Editable Collection classes and save them all together. On the contrary, the "Activities" class could be used in stand-alone manner and only save a bunch of its childs into database. That's where I ought to wrap the content of the "DataPortal_Update" method in a "Using(TransactionManager..." block and at the end just commit the transaction. But if I do that (commit the transaction in the "Activities" class), I could be committing an outsider transaction prematurely (When I'm using "Activities" as part of the engine).
So the only option I can think of is that the Editable Business Objects never commit or rollback any transaction. All the transactions have to be initiated, committed or rolled back from outside the Business Objects. Is there any better way you could suggest?

admin replied on Friday, December 18, 2009

I think TransactionManager needs some improvement to make this scenario work well.

I think it should have a Commit() method that you always call at the end of your using block.

Internal to TransactionManager, the Commit() method would actually do nothing, unless the reference count is 1, in which case it would really commit the transaction.

If the reference count hits 0 without that last Commit() call, the transaction would roll back.

If you are willing to work with me on this, we can do these changes and make the class better. Does that sound good?

RockfordLhotka replied on Friday, December 18, 2009

OK, so this is untested, but seems like a good overall solution:

http://www.lhotka.net/cslacvs/viewvc.cgi/core/branches/V3-8-x/cslacs/Csla/Data/TransactionManager.cs?view=markup

Why don't you give this a try (drop this code in place of the TransactionManager you have now) and see if it works.

You should now be able to write DAL code like this:

using (var tr = TransactionManager.GetManager<...>(...))
{
  // do stuff here
  tr.Commit();
}

The Commit() call won't actually do anything unless it is in the top-level using block, so it is safe to put in every using block.

The actual commit/rollback won't occur until the TransactionManager is disposed as it leaves the last using block.

Let me know if this works, or if you can see a better/different solution.

tiago replied on Tuesday, July 27, 2010

RockfordLhotka

using (var tr = TransactionManager.GetManager<...>(...))
{
  // do stuff here
  tr.Commit();
}

 

Hi Rocky

I'm using CSLA.NET 4 and ADO transactions. I found two different ways of commiting and can't find out which is the good one:

using (var ctx = TransactionManager<SqlConnectionSqlTransaction>.GetManager(Database.MyConnectionfalse))
{
    using (var cmd = new SqlCommand("AddStuff", ctx.Connection))
    {
        cmd.Transaction = ctx.Transaction;
        ...
    }

    ...
    ctx.Commit(); // (A)
ctx.Transaction.Commit(); // (B)
}

 In your above example you use (A).

(B) seems to refer to the SqlTransaction. Does it also trigger the TransactionManager logic?

What's the difference of using (A) or (B)?

RockfordLhotka replied on Tuesday, July 27, 2010

You should use (A).

If you commit directly on the IDbTransaction object itself you might be committing before some higher level code is complete.

If you commit on the TransactionContext object, it just records that you want to commit. A higher level bit of code could still cause a rollback - ultimately the commit/rollback decision isn't made until the highest level using block is closed and the context object is disposed - that's the only point at which you know that all your code has had a chance to "vote" on commit/rollback.

rxelizondo replied on Monday, December 21, 2009

Besides using the new TransactionManager changes that Rocky suggested, perhaps another approach that you could take would be to create a “Switchable Object”. This technique is explained on page 184 of the “Expert C# 2008 Business Objects”.

RockfordLhotka replied on Monday, December 21, 2009

They may be using Oracle, in which case TransactionScope won't work (without triggering the DTC), in which case the best option is to manually use ADO.NET transactions.

Of course this is all guesswork since the poster hasn't responded :)

amir.gheibi replied on Monday, December 21, 2009

Hi Rocky,

Thanks a lot for the reply. You are actually right. I couldn't use TransactionScope with Oracle. It raised an exception that certain components are missing that turn out to be Oracle's MTS components which I didn't have it installed.
However, your new TransactionManager and Manual approach did the work. Thanks a lot.

RockfordLhotka replied on Wednesday, December 23, 2009

Excellent, thank you for helping make that type better.

Copyright (c) Marimer LLC