views:

279

answers:

2

We have a test that runs within a transaction scope. We dispose of the transaction scope at the end to avoid changing the database.

This works fine in most cases.

However, when we use Entity Framework to execute a stored procedure which contains a transaction, which is committed inside the stored procedure. We get the following error:

"Distributed transaction completed. Either enlist this session in a new transaction or the NULL transaction.\r\n "

Is it possible combine transaction scope with committing a transaction inside a stored procedure?

+1  A: 

I use the following code inside an SP to handle contexts where a transaction may or may not be currently in force:-

DECLARE @InTran int

Set @InTran = @@TRANCOUNT

IF @InTran = 0 BEGIN TRANSACTION

/* Stuff happens */

IF @InTran = 0 AND @@TRANCOUNT > 0 COMMIT TRANSACTION

Only thing I'm not sure of is if @@TRANCOUNT reflects a transaction from a Transaction scope, its worth a shot though.

AnthonyWJones
+6  A: 

While you may or may not be able to solve this particular problem, I'd suggest that avoiding it entirely might be a better option. As you've seen, depending on a transaction to guarantee that your database is in a particular state doesn't always work. Also, because you are using multiple connections to the DB, you've automatically promoted any transactions that do occur to distributed transactions -- a subtle distinction, perhaps, but it changes the nature of the test. You may end up writing code to overcome the particular limitations of distributed transactions that wouldn't otherwise have been needed.

A better strategy would be -- for unit tests, anyway -- to mock out the database dependency, using in-memory mock or fake objects in place of the database. I've done something similar for LINQ to SQL (see my blog entry on the subject) For integration tests, I think you are better off using a test instance and writing set up code that reinitializes the state of the DB to known values before each test than introducing an extra transaction to clean things up. That way if your clean up code fails in a test, it won't affect other tests being run.

tvanfosson
I would give this two up votes if I could.
Craig Stuntz