Atomic Increment with Entity Framework

偶尔善良 提交于 2019-11-28 09:49:23
Slauma

With Entity Framework you can't make this an "atomic" operation. You have the steps:

  1. Load entity from database
  2. Change counter in memory
  3. Save changed entity to database

In between these steps another client can load the entity from the database which still has the old value.

The best way to deal with this situation is to use optimistic concurrency. It basically means that the change in step 3 won't be saved if the counter is not the same anymore that it was when you loaded the entity in step 1. Instead you'll get an exception that you can handle by reloading the entity and reapplying the change.

The workflow would look like this:

  • In the Work entity the WordCount property must be marked as a concurrency token (annotations or Fluent API in case of Code-First)
  • Load entity from database
  • Change counter in memory
  • Call SaveChanges in a try-catch block and catch exceptions of type DbUpdateConcurrencyException
  • If an exception occurs reload the entity in the catch block from the database, apply the change again and call SaveChanges again
  • Repeat the last step until no exception occurs anymore

In this answer you can find an code example for this procedure (using DbContext).

Next way will work if you hosting your site in single process(it won't work with web farm or web gardsen):

   private static readonly Locker = new object();

   void Foo()
   {
          lock(Locker)
          {
                 dbEntities myEntity = new dbEntities();

                 var currentWork = myEntity.works.Where(xXx => xXx.RID == 208).FirstOrDefault();
                 Console.WriteLine("Access work");

                 if (currentWork != null)
                 {
                     Console.WriteLine("Access is not null");
                     currentWork.WordCount += 5;//Default WordCount is 0
                     Console.WriteLine("Count changed");
                     myEntity.SaveChanges();
                     Console.WriteLine("Save changes");
                 }
                 Console.WriteLine("Current Count:" + currentWork.WordCount);
          }
   }

What else you can do, is use raw SQL query via ObjectContext:

   if (currentWork != null)
             {
                 Console.WriteLine("Access is not null");
                 myEntity.ExecuteStoredCommand("UPDATE works SET WordCount = WordCount + 5 WHERE RID = @rid", new MySqlParameter("@rid", MySqlDbType.Int32){Value = 208)
                 Console.WriteLine("Count changed");

             }
    var record = myEntity.works.FirstOrDefault(xXx => xXx.RID == 208);
    if(record != null)
        Console.WriteLine("Current Count:" + record .WordCount);
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!