Ando
Ando

Reputation: 11409

Entity Framework handling concurrency

Scenario:

I have multiple accounts. Every account has a remaining credit. Every account corresponds to multiple users.

I want the RemainingCredit field to correctly reflect the remaining credit (I'm using EF to abstract away the db).

E.G. In a scenario where initial credit is X and 2 users log in, one spends A , and one spends B, I want the end sum to be X-A-B (order of read/modify/save should be irrelevant).

After reading up I think optimistic concurrency handling is what I'm looking for, as it scales well and this is very important to my scenario. The end procedure would be something like:

ComputeRemainingCredit(Double amountToBeDeducted) {
    Account acc = context.Accounts.Where(condition)
    ComputeRemainingCreditInternal(acc, amountToBeDeducted);
}

ComputeRemainingCreditInternal(Account acc, Double amountToBeDeducted) {
try {
    acc.RemainingCredit = acc.RemainingCredit - amountToBeDeducted;
    context.SaveChanges();
}
catch (OptimisticConcurrencyException  ex) {
    context.Refresh(RefreshMode.StoreWinds, acc);
    //now I need to rerun the operation
    ComputeRemainingCreditInternal(acc, amountToBeDeducted);
}
}
  1. Is this a correct interpretation/implementation of optimistic concurrency in EF?
  2. My end objective is to have the RemainingCredit field up to date. Are there any better solutions than OptimisticConcurrencyException?

Upvotes: 2

Views: 3264

Answers (2)

Rui Jarimba
Rui Jarimba

Reputation: 17994

As an alternative you can show an error message to the user saying that the operation failed because the data was modified, and then show him the current state of the data. The user would then decide to retry the operation if that was his/her intention.

You can find a good article about concurrency in Entity Framework here:

Handling Concurrency with the Entity Framework in an ASP.NET MVC Application

Upvotes: 0

Roy Dictus
Roy Dictus

Reputation: 33139

You need a field in your table that acts as a timestamp, or a version number, and use that for optimistic concurrency checking.

Say that you have a Version field. Set that field's ConcurrencyMode property to Fixed, and then EF will do the optimistic concurrency checking for you and throw an OptimisticConcurrencyException when necessary.

The alternative is to do this work yourself -- fetching the current record, verifying the field value against the one in the record you're updating, allowing or disallowing the update accordingly.

EDIT See also http://blogs.msdn.com/b/alexj/archive/2009/05/20/tip-19-how-to-use-optimistic-concurrency-in-the-entity-framework.aspx

EDIT More or less in pseudocode:

bool mustRetry = true;
while (mustRetry)
{
    try
    {
        SpendTheMoney(context, parameters);
        mustRetry = false;
    } catch (OptimisticConcurrencyException exc)
    {
        // Do logging if you need, then just swallow the exception
    }
}

Upvotes: 2

Related Questions