how to inc/dec multi user safe in entity framework 5

后端 未结 1 1903
误落风尘
误落风尘 2020-12-28 20:54

What is a clean, safe way to increment or decrement an integer field.

i use sql server 2012 in combination with entityframework 5.x

I look for an equivalent

相关标签:
1条回答
  • 2020-12-28 21:32

    The standard way would be to use optimistic concurrency.

    Say, you have a simple entity with an integer field Counter that you want to increment or decrement:

    public class SomeEntity
    {
        public int SomeEntityId { get; set; }
        public int Counter { get; set; }
    }
    

    You could mark the Counter then as a concurrency token. With Fluent API it is:

    modelBuilder.Entity<SomeEntity>()
        .Property(s => s.Counter)
        .IsConcurrencyToken();
    

    Then you can increment or decrement the Counter for example like so:

    public void IncDecCounter(int someEntityId, bool dec)
    {
        using (var context = new MyContext())
        {
            var someEntity = context.SomeEntities.Find(someEntityId);
            if (someEntity != null)
            {
                bool saveFailed;
                do
                {
                    saveFailed = false;
    
                    if (dec)
                        --someEntity.Counter;
                    else
                        ++someEntity.Counter;
    
                    try
                    {
                        context.SaveChanges();
                    }
                    catch (DbUpdateConcurrencyException e)
                    {
                        saveFailed = true;
                        e.Entries.Single().Reload();
                    }
                } while (saveFailed);
            }
        }
    }
    

    SaveChanges will fail with a DbUpdateConcurrencyException if the value of Counter when the entity has been loaded (with Find in this example, could be any other query) differs from the value of Counter in the database when the UPDATE statement is executed in the database which would mean that the Counter has been modified by another user in the meantime. Technically this is achieved by an extended WHERE clause of the generated UPDATE statement that tries to filter not only by the Id but also by the old value of Counter, basically something like: WHERE SomeEntityId = someEntityId AND Counter = oldCounterWhenTheEntityHasBeenLoaded.

    The catch block reloads the entity with the current Counter value from the database and the next loop tries to increment or decrement the reloaded value again until it succeeds without concurrency violation.

    0 讨论(0)
提交回复
热议问题