简体   繁体   English

使用实体框架解决乐观并发更新问题

[英]Solving Optimistic Concurrency Update problem with Entity Framework

How should I solve simulation update, when one user updates already updated entery by another user? 当一个用户更新另一个用户已经更新过的Entery时,我应该如何解决模拟更新?

First user request 'Category' entityobject, second user does the same. 第一个用户请求“类别”实体对象,第二个用户执行相同的操作。
Second user updates this object and first user updates. 第二个用户更新此对象,第一个用户更新。

I have field timestamp field in database that wa set to Concurrency Mode - Fixed. 我在数据库中将字段时间戳字段设置为“并发模式-固定”。

This is how I update: 这是我的更新方式:

public class CategoriesRepository : BaseCategoryRepository
{

     public  void Update(....)
    {
    try
     {
          Category catToUpdate = (from c in Contentctx.Categories where c.CategoryID == categoryId select c).FirstOrDefault();
          catToUpdate.SectionReference.EntityKey = new System.Data.EntityKey("ContentModel.Sections", "SectionID", sectionId);

          if (catToUpdate != null)
          {
               //Set fields here....
              Contentctx.SaveChanges();
          }

          base.PurgeCacheItems(CacheKey);
    }

    catch (OptimisticConcurrencyException ex)
    {

             }
    }

}
//Contentctx comes from base class: Contentctx:  
private ContentModel _contenttx;
        public ContentModel Contentctx
        {
            get
            {
                if ((_contenttx == null))
                {                   
                    _contenttx = new ContentModel();
                }

                return _contenttx;
            }
            set { _contenttx = value; }
        }



//on Business layer:
using (CategoriesRepository categoriesRepository = new CategoriesRepository())
{
            categoriesRepository.UpdateCategory(.....);
}

Exception never jumps... 异常永无止境...
How should I handle this? 我该如何处理?

Are you sure that sequence of calls is performed as you described? 您确定按照您的描述执行通话顺序吗? Anyway the main problem here is that you should not use the timestamp returned by the query in Upate method. 无论如何,这里的主要问题是您不应该在Upate方法中使用查询返回的时间戳。 You should use timestamp received when user get initial data for update. 当用户获取用于更新的初始数据时,应使用收到的时间戳。 It should be: 它应该是:

  • User requests data from update - all fields and timestamp are received from DB 用户从更新请求数据-从数据库接收所有字段和时间戳
  • Timestamp is stored on client (hidden field in web app) 时间戳记存储在客户端上(Web应用程序中的隐藏字段)
  • User modifies data and pushes Save button - all data including old timestamp are send to processin 用户修改数据并按下“保存”按钮-包括旧时间戳在内的所有数据均发送到processin
  • Update method loads current entity 更新方法加载当前实体
  • All updated fields are merged with old entity. 所有更新的字段都与旧实体合并。 Timestamp of entity is set to timestamp received in the first step. 实体的时间戳设置为第一步中收到的时间戳。
  • SaveChanges is called SaveChanges被称为

The reason for this is that it can pass a lot of time between first call and update method call so there can be several changes already processed. 这样做的原因是,它在第​​一次调用和update方法调用之间可能会花费很多时间,因此可能已经处理了一些更改。 You have to use initial timestamp to avoid silent overwritting other changes. 您必须使用初始时间戳,以避免无声地覆盖其他更改。

Edit: 编辑:

// You are updating category - update probably means that you had to load category
// first from database to show actual values. When you loaded the category it had some 
// timestamp value. If you don't use that value, any change between that load and c
// calling this method will be silently overwritten.
public void Update(Category category)     
{     
    try      
    {           
        Category catToUpdate = (from c in Contentctx.Categories where c.CategoryID == categoryId select c).FirstOrDefault();           
        ...           

        // Now categoryToUpdate contains actual timestamp. But it is timestamp of
        // actual values loaded now. So if you use this timestamp to deal with 
        // concurrency, it will only fire exception if somebody modifies data 
        // before you call SaveChanges few lines of code bellow.

        if (catToUpdate != null)           
        {                
            //Set fields here....  

            // To ensure concurrency check from your initial load, you must 
            // use the initial timestamp.           
            catToUpdate.Timestamp = category.Timestamp;
            Contentctx.SaveChanges();           
        }

        ...
    }      
    catch (OptimisticConcurrencyException ex)     
    {               
        ...
    }     
} 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM