1

I have a solution which consists of Data Access Layer(DAL), Business Layer and Presentation layer. I create data-context in DAL as follows :

using(var context = new DBContext){ ....  }

For one complete process say 'Purchase', I have to move between layers constantly. I want to revert back all the changes in case of any exception raised either in Business layer or in DAL during process using Transactions. But my problem is that when I move from DAL to business layer, the corresponding context gets disposed. So how do I manage Transactions in this case. Is there anything wrong with my design.

Please share links if you have any for the same, it will be helpful.

Thanks

Vishal Anand
  • 1,431
  • 1
  • 15
  • 32

1 Answers1

1

You have a number of options, e.g. I've seen all of the below strategies in production systems:

  1. Assuming single threaded usage, you can extend the lifespan of the DbContext beyond the Data Access Layer, such that it is managed by the calling layer(s) (an IoC container might be useful here to save passing the (I)DbContext around, with a per-Request / per-Thread type instantiation). The potential benefit of carying DbContext around is that it can double as a cache if AsNoTracking() is left off. Use the final SaveChanges() as the commit point.
  2. Leave your design as-is, and instead use a System.Transactions.TransactionScope in your business (or higher) layers, which then wrap all DAL and other transactional code in a unit of work. The benefit of TS is that many underlying database and queue adapters work seamlessly with ts, so you can leave transaction boundaries as an afterthought and work with multiple DAL technologies, and TS will handle both single phase and distributed ACID transactions.
  3. Invent your own UnitOfWork pattern, which wraps the DbContext. This is really just a wrapper around option 1.

For simplicity, I would generally always go with TransactionScope - this is what it is designed for, and it will also allow you to control distributed ACID transactions if your design changes (e.g. your data is distributed across multiple databases). There are some things you do need to know about TS, e.g. the default Isolation Level is potentially overzealous, and you'll want to ensure you close each connection before opening another on a single thread in order to obtain the benefit) of the Lightweight transaction manager

Edit Much more on all the fine print of TransactionScope here

Community
  • 1
  • 1
StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • I've updated - FWIW, I've built several financial systems with TransactionScope and haven't had many regrets. Although `DbContext.SaveChanges()` is (single phase) transactional, it always seems messy to pass it around as a dependency, and the other headache is to prevent DAL methods calling `SaveChanges` halfway through a transaction. – StuartLC Dec 09 '14 at 04:40