Using Transactions or Locking in Entity Framework to ensure proper operation

asp.net-mvc, c#, entity-framework, sql, sql-server

Solution

Use Optimistic concurrency http://msdn.microsoft.com/en-us/data/jj592904

//Object Property:
public byte[] RowVersion { get; set; }
//Object Configuration:
Property(p => p.RowVersion).IsRowVersion().IsConcurrencyToken();

This Allows dirty read. BUT when you go to update the record the system checks the rowversion hasn't changed in the mean time, it fails if someone has changed the record in the meantime. Rowversion is maintained by DB each time a record changes.

Out of the box EF optimistic locking.

Problem

I am fairly new to EF and SQL in general, so I could use some help clarifying this point. Let's say I have a table "wallet" (and EF code first object Wallet) that has an ID and a balance. I need to do an operation like this: ``` if(wallet.balance > 100){ doOtherChecksThatTake10Seconds(); wallet.balance -= 50; context.SaveChanges(); } ``` As you can see, it checks to see if a condition is valid, then if so it has to do a bunch of other operations first that take a long time (in this exaggerated example we say 10 seconds), then if that passes it subtracts $50 from the wallet and saves the new data. The issue is, there are other things happening that can change the wallet balance at any time (this is a web application). If this happens: - wallet.balance = 110; - this operation passes its "if" check because wallet.balance > 110 - while it's doing the "doOtherChecksThatTake10Seconds()", a user transfers $40 out of their wallet - now wallet.balance = 70 - "doOtherChecksThatTake10Seconds()" finishes, subtracts 50 from wallet.balance, and then saves the context with the new data. In this case, the check of wallet.balance > 100 is no longer true, but the operation still happened because of the delay. I need to find a way of locking the table and not releasing it until the entire operation is finished, so nothing gets edited during. What is the most effective way to do this? It should be noted that I have tried putting this operation within a TransactionScope(), I am not sure if that will have the intended effect or not but I did notice it started causing a lot of deadlocks with an entirely different database operation that is running.

Original source