0

I try to update a field of my object, and save it right away to the database.

using (var ctx = new DataModel(_connectionString))
{
    var MyObject it = ctx.MyObjects.Where(someConstraint).ToList()[0];
    try
    {
        //update check time
        ctx.Refresh(RefreshMode.StoreWins, it); //making sure I have it
        ctx.AcceptAllChanges(); // in case something else modified it - seems unnecessary
        it.TimeProperty= DateTime.UtcNow; //Setting the field
        ctx.DetectChanges(); //seems unnecessary
        ctx.SaveChanges(SaveOptions.AcceptAllChangesAfterSave); //no SaveOptions changed the behavior
    }
    catch (OptimisticConcurrencyException)
    {
        _logger.DebugFormat(workerClassName + ": another worker just updated the LastCheckTime");
    }
    //Do some other work and/or sleep
}

When I run this in Azure emulator with 2 instances or more, I get a lot of OptimisticConcurrencyExceptions here.

I am trying to refresh the object, update one of its fields, then push those changes to the database. However, Optimistic Concurrency is preventing me.

note: The optimistic concurrency is set on a TimeStamp field which I never touch.

Why is that, and how can I fix it?

svick
  • 236,525
  • 50
  • 385
  • 514
iliaden
  • 3,791
  • 8
  • 38
  • 50

1 Answers1

1

It's possible you have more than one thread inside this try block, modifying their own copies of the same entity after both have refreshed from the DB but before either of them saved their changes.

Try this:

using (var ctx = new DataModel(_connectionString))
{
    bool saved = false;

    do
    {
        var MyObject it = ctx.MyObjects.Where(someConstraint).ToList()[0];

        try
        {
            it.TimeProperty= DateTime.UtcNow; //Setting the field
            ctx.SaveChanges(SaveOptions.AcceptAllChangesAfterSave); 

            saved = true;
        }
        catch (OptimisticConcurrencyException)
        {
            _logger.DebugFormat(workerClassName + ": another worker just updated the LastCheckTime");

            ctx.Refresh(RefreshMode.StoreWins, it);
            ctx.AcceptAllChanges();
       }
    } while( !saved )
    //Do some other work and/or sleep
}

If this works for you, change the while condition to limit the amount of attempts.

Moho
  • 15,457
  • 1
  • 30
  • 31
  • no - I have several processes executing the same code, but each process is single-threaded – iliaden Mar 27 '13 at 22:38
  • It's still possible that separate processes are modifying the same entity at the same time. Handle the refresh after the exception is encountered – Moho Mar 27 '13 at 22:44
  • I don't care much about the refresh - I need to push this to the DB. Locally, the variable 'it' is never used after this. Also - I just checked with the debugger: this code runs in a single thread on each of the processes – iliaden Mar 27 '13 at 22:50