Transaction Best Practice

Posts   
 
    
Val
User
Posts: 37
Joined: 14-Nov-2008
# Posted on: 01-Mar-2009 07:36:32   

I had a situation where, for some reason, in a transaction, some of save operation where not performed and the transaction didn't fail. I tried to reproduce the issue but to no avail. I am trying to bulletproof the transactional save and I was looking for some guidance on how to make sure that everything is atomic within the transaction boundaries.

Is it possible for an entity or collection insert/update to fail without throwing an exception thus allowing the transaction to continue and ultimately to commit?

In the "Handling exceptions" section in documentation is specified: "You should always check for return values if the method returns a return value, for example true or false as your primary result check. " So, within a transaction should I always check the return value and not rely exclusively on exceptions?

What does the return value represent for the Collection SaveMulti()?

Thank you,

Val

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 03-Mar-2009 21:46:32   

Can you be more specific about which actions were not performed...?

It is quite possible to run a SQL query that does not do anything - this will not raise an error and so will not cause a transaction to fail (DELETE FROM table WHERE 1=0 for instance - it's a perfectly valid sql query that does nothing but will not cause a transaction to fail)

The return value for .SaveMulti is the number of entities saved.

Matt

Val
User
Posts: 37
Joined: 14-Nov-2008
# Posted on: 03-Mar-2009 21:53:27   

In what situation a Save operation on an entity can fail without throwing an exception? Should I check the return value for Save on a entity and throw an exception to rollback the transaction? The documentation and the examples provided are not very clear on this subject.

In my particular case I am running entity and collection updates, insert and deletes (no custom sql scripts) in various combinations and I want to make sure everything is done atomically.

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 03-Mar-2009 22:33:53   

It depends on what you mean by "Fail". As with the example above it is perfectly possible to run an

UDPATE table WHERE ID="{a non existent ID}"

which will not raise an exception - but which could be considered by your business rules as a failure that would need the rest of the transaction to be rolled back - in this case you will need to check for it manually and abort the transaction yourself.

Errors such as PK-FK mismatches will cause an error.

Unless you can reproduce the issue that you had, you are going to struggle to protect against it. I would rely on the generated code to ensure that all of your updates are happening atomically, rather than trying to second guess it - it's had many years and thousands of users verifiying that it works !

Val
User
Posts: 37
Joined: 14-Nov-2008
# Posted on: 03-Mar-2009 22:51:38   

I guess what throws me off are these return values for Save operations. When the return value can be false without having an exception?

Let use the example you provide for transactions in documentation. The Save operations are not checked to see if the operations were completed even if in documentation you clearly specify that "You should always check for return values if the method returns a return value". So shouldn't each operation be checked and in case that the return value is false, for entities, or the number of entities affected is different than the number expected, for collections, to throw an exception to rollback the transaction?

Transaction transactionManager = new Transaction(IsolationLevel.ReadCommitted, "Test");

// create a new order and then 2 new order rows. 
try
{

    OrderEntity newOrder = new OrderEntity();   
    ....

    transactionManager.Add(newOrder);

    // shouldn't this be check for return value?
    newOrder.Save();

    
    OrderDetailsEntity newOrderRow = new OrderDetailsEntity();
    
    transactionManager.Add(newOrderRow);

    // shouldn't this be checked for return value and throw an exception or rollback the transaction in case it is false?
    newOrderRow.Save();


    transactionManager.Commit();
}
catch(Exception)
{
    // abort, roll back the transaction
    transactionManager.Rollback();
    throw;
}
finally
{
    // clean up. Necessary action.
    transactionManager.Dispose();
}
Walaa avatar
Walaa
Support Team
Posts: 14983
Joined: 21-Aug-2005
# Posted on: 04-Mar-2009 12:21:18   

So shouldn't each operation be checked and in case that the return value is false, for entities, or the number of entities affected is different than the number expected, for collections, to throw an exception to rollback the transaction?

I don't agree with you, as this is a matter of prespective.

A Transaction only looks for atomic executions without any exceptions.

But if you have a query which executes well on the database and for which the database doesn't throw any exception, then the transaction will accept it too as a working query.

If your business requires such a query to rollback the transaction if no rows were affected in the database, then you should manually check for the return result and raise the exception or just rollback the transaction.

This can't be built inside the framework as it's very business related.

The general rule is: No database exception, no problem for the transaction.