1

I am developing student marking system using ASP.NET MVC and Entity Framework. There is a heavy method I am using for calculate marking. At a given time there are about 50 users enter marks to system and that heavy method call by all the users. It gives me deadlock most of the time. I am using a TransactionScope.

This is my code:

try
{
    using (context = new SIMSDBAPPEntities())
    {
        using (TransactionScope scope = new TransactionScope())
        {
              // My heavy calculation
        } 

        scope.Complete();
        context.SaveChanges();           
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

My heavy method is running inside a TransactionScope. I want to know whether my code has any problems? If yes, what can I do to avoid deadlock situation?

Luke Girvin
  • 13,221
  • 9
  • 64
  • 84
Krishan
  • 169
  • 2
  • 12
  • you haven't posted any implementation of "your heavy calculation", which is probably the most important part of determining how to alleviate a deadlock situation. – Kritner Nov 18 '15 at 18:10
  • also, aren't EF CUDs transacted by default? – Kritner Nov 18 '15 at 18:18
  • Thanks for replying me. it's difficult to post..it has more than 400 lines....It is not EF CUDs by default.... – Krishan Nov 18 '15 at 18:23
  • 2
    hopefully your `scope.Complete()` is within the using statement for the `TransactionScope`. – Matthew Whited Nov 18 '15 at 18:48
  • I agree with @Kritner, unless you are doing additional 'server state' logic in your TransactionScope, the SaveChanges of the context should be sufficient. And note what Matthew Whited said too. – The Senator Nov 18 '15 at 20:02
  • Yes, scope.Complete() within TransactionScop. – Krishan Nov 19 '15 at 10:53

3 Answers3

2

If you are using just one context for saving data. You dont need to use TransactionScope. when you call SaveChanges Ef automatically enlist all changes and apply them on single transaction. For distributed transactions must use TransactionScope.

[link]Using Transactions or SaveChanges(false) and AcceptAllChanges()?

https://coderwall.com/p/jnniww/why-you-shouldn-t-use-entity-framework-with-transactions

Community
  • 1
  • 1
hvojdani
  • 460
  • 3
  • 13
0

Consider using an async method to do the heavy calculating.

using (var transaction = Database.BeginTransaction())
{
    try
    {
        var heavyCalulation = await heavyCalulationMethodAsync();
        await context.SaveChangesAsync();
    }
    catch
    {
        transaction.Rollback();
    }
}
Stephen Brickner
  • 2,584
  • 1
  • 11
  • 19
0

The only way to avoid a deadlock is to access and update records in the same table order every time for every operation that does an update.

This can be very tricky to accomplish in ORMs like EF and nHibernate because the concept of table operations is hidden behind the implementation. You're at the mercy of whatever strategy the framework decides. To work around it, you'd have to be careful to update objects individually and save your changes on a per-object basis. You'd also have to make sure you always save these objects in the same order for every operation that does an update.

What I've done in the past to minimize this issue is to enable the database for isolated snapshots, and use that method for your transaction scope.

https://msdn.microsoft.com/en-us/library/tcbchxcb(v=vs.110).aspx

There are some things that can go wrong here as well (such as writing back to a stale record). But I've found it happens less often than deadlocks.

I found this article helpful too (and gives examples of snapshot isolation).. http://blogs.msdn.com/b/diego/archive/2012/04/01/tips-to-avoid-deadlocks-in-entity-framework-applications.aspx