1

Working on Transactions in .net. Had a question on flowing transactions through sub functions. Do I need to use dependent transactions if the object context is common across the sub - methods?

For example, in the following code - I declare the object context in the constructor of my class (not sure if this is best practice)

public class EmployeeRepository
{
    private EmployeeContext ec;        
    public EmployeeRepository()
    {
        objectContext = new EmployeeContext();            
    }       
    public InitTransaction(EmployeeEntity emp1)
    {
         using (TransactionScope transaction = new TransactionScope())
        {
            try
            {   ec.employees.AddObject(emp1);
                SubFunction1();
                ec.SaveChanges();                               
            }
            catch
            {
                //catch 
            }
        }
        //commit the transaction here 
        ec.AcceptAllChanges();
    }

    public SubFunction1()
    {
        //some processing 
        //using same object context
        ec.someother.AddObject(someobject);
        ec.SaveChanges();
    }
}

I want the subfunctions to be a part of the transactions as well? In this case should I use a dependent transaction within SubFunction1 even though I am using the same object context? Or Should I add a

using (TransactionScope transaction = new TransactionScope());

within SubFunction1. Pointers in the right direction would be greatly appreciated.

user275157
  • 1,332
  • 4
  • 23
  • 45

2 Answers2

1

Transaction Scopes can be nested (they work similar to the SQL @@TRANCOUNT mechanism), so you could in theory use TransactionScopes in your Repository, e.g. to keep parent : child table relationships ACID, but also in your Business / Service layers as well (e.g. to have a Distributed Transaction across multiple entities, possible across multiple Databases, and even across other resources such as Message Queues and Transactional file systems.

Note that the default isolation level of TransactionScope is Read Serializable - this can lead to locking / deadlocks.

Community
  • 1
  • 1
StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • Now my question is - will my code work as is -i.e. Will subfunction1 be part of the transaction if I use the same object context. Should I explicitly begin a transaction in SubFunction1. – user275157 Aug 19 '11 at 11:29
  • 1
    Yes - it will work - SubFunction1 (and anything else called by SubFunction1) will, by default, enlist in your TransactionScope. "Transaction" aware resources such as *Contexts and SQLConnections will enlist automatically. – StuartLC Aug 19 '11 at 11:33
  • Thanks for the input. So no new transactionscope in subfunction1. Also on isolation levels - I am using mysql and have the option of bubbling up failed transactions to the end user (for them to retry). So I thought read serializable would be safe. Should I be changing isolation level to readcommitted? – user275157 Aug 20 '11 at 04:55
  • also - wanted to add that this app is read/write intensive and not just read heavy... – user275157 Aug 20 '11 at 05:06
  • Yes, ReadCommitted is usually a better 'default' starting point for most transactions. You can exclude code (e.g. logging) from a encapsulating transaction by starting a new TransactionScope with RequiresNew. But the suggestion is to regard TransactionScope as a 'logical' transaction, at a higher level than your database connections. We usually control the outermost TransactionScope in the Business or Service tiers - see http://stackoverflow.com/questions/1656986/in-which-layer-would-you-implement-transactions-using-asp-net-transactionscope – StuartLC Aug 20 '11 at 10:39
0

You can consider using Dependency Injection to pass around the same ObjectContext so you can avoid the TransactionScope.

Instead of creating Context inside the Repository inject it through constructor.

public class EmployeeRepository
{
    private EmployeeContext ec;        
    public EmployeeRepository(EmployeeContext objectContext)
    {
        ec = objectContext;            
    }       

}

Take a look at this answer

Community
  • 1
  • 1
Eranga
  • 32,181
  • 5
  • 97
  • 96
  • Thanks. The code is similar (just omitted it for clarity's sake). I actually have EmployeeRepository implement Idisposable and dispose of the connection. All the ops happen on a wcf rest service. – user275157 Aug 20 '11 at 04:58