I have a complex application and encountered an error. I simplified my real problem with the following code.
I have a WCF Service with a method that performs a select on one of my tables:
public string FindDocumentNumber(int documentId)
{
using(var context = new MyDbContext())
{
return context.Documents.Where(x=>x.Id == documentId && x.Tag == "*")
.Select(x=>x.Number).FirstOrDefault();
}
}
In my Console application I have following code:
using(var scope = new TransactionScope())
{
using(var context = new MyDbContext())
{
var doc = context.Documents.Where(x=>x.Id == 12345).FirstOrDefault();
doc.Tag = "*";
context.SaveChange();
}
...
var number = myWCFService.FindDocumentNumber(12345); // At this point, I encounter an error
...
//some other updates on document with Id = 12345
scope.Complete();
}
However, when running the code, I encounter the following error:
System.Data.Entity.Core.EntityCommandExecutionException
HResult=0x8013193C Message=An error occurred while executing the command definition. See the inner exception for details.
Source= StackTrace:Inner Exception 1: SqlException: Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding.
Inner Exception 2: Win32Exception: The wait operation timed out
Where is the problem?
The issue is that you are attempting to dispose the DbContext while inside a Transaction scope. The Tx scope will want to ensure that changes to the DbContext and anything else that recognizes it will be committed at the same time, which will be blocking the
DbContext.Disposeat the end of it'susingblock which is most likely the source of your exception.If the API call is set up to work within a Tx Scope (which I suspect it isn't) then you would want to invert your
usingblocks to avoid that error:However, as the comments have said, the Tx Scope is likely not even necessary. The DbContext wraps its own transaction so if there is a condition where you don't want to commit the changes to the DB, just avoid calling `SaveChanges until you are satisfied everything should be committed.
Transaction scopes are meant to coordinate multiple separate operations to ensure they all commit or roll back together. A common scenario where I see separate transactions used is when developers feel they need to save a record first, for instance to get a generated ID so they can use or set that ID somewhere else, but then still want the option to "back out" of that insert. There may be rare cases where this is a legitimate issue but more often than not it is just a limited implementation with better options to consider.