ASP.NET MVC + Entity Framework with Concurrency check

后端 未结 3 520
感动是毒
感动是毒 2021-02-06 06:16

I am trying to implement a application following the sample in this page: http://www.asp.net/entity-framework/tutorials/handling-concurrency-with-the-entity-framework-in-an-asp-

相关标签:
3条回答
  • 2021-02-06 06:41

    It doesn't work this way. Once you load entity by Find you cannot change its timestamp directly. The reason is that timestamp is computed column. EF holds internally original and current values for each loaded entity. If you change the value in the loaded entity, only current value is changed and during update EF compares the original value with the current value to know which columns must be updated. But in case of computed columns EF don't do that and because of that your changed value will never be used.

    There are two solutions. The first is not loading the entity from database:

    public ActionResult Edit(int id, FormCollection collection) 
    {
         // You must create purchase order without loading it, you can use model binder
         var purchaseOrder = CreatePurchaseOrder(id, collection);
         db.Entry(purchaseOrder).State = EntityState.Modified;
         db.SaveChanges();
    }
    

    The second solution is small hack described in linked question for ObjectContext API. If you need this for DbContext API you can try something like:

    public ActionResult Edit(int id, FormCollection collection) 
    {
         var purchaseOrder = db.PurchaseOrders.Find(id);
         purchaseOrder.Timestamp = GetTimestamp(collection);
         // Overwrite original values with new timestamp
         context.Entry(purchaseOrder).OriginalValues.SetValues(purchaseOrder);
         UpdateModel(purchaseOrder, "PurchaseOrder", collection);
         db.SaveChanges();
    }
    
    0 讨论(0)
  • 2021-02-06 06:56

    Try putting a [ConcurrencyCheck] attribute in your TimeStamp Property

    public class PurchaseOrder {
        [ConcurrencyCheck]
        [Timestamp]
        public byte[] Timestamp {get; set;}
    }
    
    0 讨论(0)
  • 2021-02-06 07:01

    We have overriden the DbContext class, and the SaveChanges method. In it, we look for the TimeStamp values, and if it does not match the value in the OriginalValues collection, we throw an exception.

    we have a BaseEntity type for each entity, and it has a SI_TimeStamp column which is of type TimeStamp.

    public override int SaveChanges()
    {
            foreach (var item in base.ChangeTracker.Entries<BaseEntity>().Where(r => r.State != System.Data.EntityState.Deleted && 
                                                                                     r.State != System.Data.EntityState.Unchanged))
                if (!item.Entity.SI_TimeStamp.ValueEquals(item.OriginalValues.GetValue<byte[]>("SI_TimeStamp")))
                    throw new Exception("The entity you are trying to update has ben changed since ....!");
    }
    

    you have to place the original value in your forms. Html.HidderFor (r => r.SI_TimeStamp)

    I would actually recommend you to check the timestamp against the original value either when loading or after loading the entity. The overriden DbContext class method is a general solution, and it actually makes sense to check against the timestamp value before trying to save changes back to database.

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