EntityKey and ApplyPropertyChanges()

前端 未结 5 1314
时光取名叫无心
时光取名叫无心 2020-12-30 14:06

I need to set an EntityObject\'s EntityKey. I know its type and its id value. I don\'t want to query the database unnecessarily.

This works...

//
//         


        
5条回答
  •  佛祖请我去吃肉
    2020-12-30 14:24

    The reason your second block of code fails is because EF can't find the object in the ObjectStateManager - i.e. when it pulls objects from the db it puts them in the state manager so it can track them - this is similar to the Identity Map pattern. Despite having an EntityKey, your object isn't in the state manager so EF is unable to persist the changes. You can get around this by putting the object into the state manager youself but you have be a bit sneaky about it.

    This works:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(Guid id, Department model)
    {
      var entitySetName = db.DefaultContainerName + "." + model.GetType().Name;
      var entityKey = new System.Data.EntityKey(entitySetName, "Id", model.Id);
    
      db.Attach(new Department{Id = id, EntityKey = entityKey});
      db.AcceptAllChanges();
    
      db.ApplyPropertyChanges(entitySetName, model);
      db.SaveChanges();
    }
    

    ... but it's not very clean. Basically this is attaching an 'empty' object with just an entity key, accepting all changes and then calling ApplyPropertyChanges with the actual real updated values.

    Here's the same thing wrapped up in an extension method - this should work for anything that has uses a single db column for the primary key. The only interesting part of calling the method is that you need to tell it how to find the key property via a delegate as the second argument to the extension method:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(Guid id, Department model)
    {
      db.ApplyDetachedPropertyChanges(model, x => x.Id);
      db.SaveChanges();
    }
    

    and the extension method:

    public static class EfExtensions
    {
      public static void ApplyDetachedPropertyChanges(this ObjectContext db, T entity, Func getIdDelegate)
      where T : EntityObject
      {
        var entitySetName = db.DefaultContainerName + "." + entity.GetType().Name;
        var id = getIdDelegate(entity);
        var entityKey = new EntityKey(entitySetName, "Id", id);
    
        db.Attach(new Department {Id = id, EntityKey = entityKey});
        db.AcceptAllChanges();
    
        db.ApplyPropertyChanges(entitySetName, entity);
      }
    }
    

    As the extension method is calling AcceptAllChanges, you'd need to be careful about calling this if you are doing updates on multiple entities at once - you could easily 'lose' updates if you aren't careful. Hence this approach is only really suitable for simple update scenarios - e.g. a lot of MVC action methods :)

提交回复
热议问题