Entity Framework Pitfalls: TransactionScope
Most people using Entity Framework use the TransactionScope API to manage database transactions. This is a powerful API, that can be used to enlist .NET APIs and even WS-*-compatible web services in transactions, that may well be distributed. Microsoft used to recommend it for working with EF, but isn’t doing it anymore, or, at least, developers need to understand a thing or two.
Most modern APIs offer asynchronous methods in addition, or instead, of blocking ones, and Entity Framework is a good example – just think of SaveChangesAsync, FindAsync and ToListAsync. The problem with TransactionScope prior to version 4.5.1 was that it didn’t handle well transaction-enabled methods running in other threads – which is what EF’s asynchronous methods do. In this version, Microsoft introduced the
TransactionScopeAsyncFlowOption flag, which can be used to tell TransactionScope to flow transactions across async threads.
Also, if we open two database connections inside a TransactionScope, the transaction gets automatically promoted to a distributed one. The problem is, distributed transactions require Microsoft Distributed Transaction Coordinator service running, and it is not available in Azure, for example (Web Apps).
So, the key here is: if we cannot be certain of the environment where EF will run, which may include pre-.NET 4.5.1 or Azure, we should use explicit transactions instead. It’s not that difficult, it’s just a matter of calling Database.BeginTransaction() and either committing or rolling back/disposing of the returned object when we are done with it.