更新实体框架中从缓存返回的实体

时间:2014-09-12 06:37:18

标签: c# .net entity-framework caching

我有两个存储库(CacheEntityFramework)用于数据处理。我想从cache获取实体并在EntityFramework中更新,例如错误代码:

User user = _cacheRepo.Get<User>(2);
user.Name = "Qolzam";
_entityFrameworkRpo.Update<User>(user);

ERORR

  

无法附加实体进行更新

但另一方面,此代码有效:

User user = _entityFrameworkRpo.Get<User>(2);
user.Name = "Qolzam";
_entityFrameworkRpo.Update<User>(user);

成功:附加实体以更新是好的

[更新]

public T Update<T>(T item, bool commit = true) where T : class , IBaseEntity
  {
    var entry = this.Entry(item);
    if (entry != null)
    {
       entry.State = EntityState.Modified;
       entry.CurrentValues.SetValues(item);
    }
    else
    {
       this.Attach(item);
    }
    this.SaveChanges();

    return item;
  }
  

[异常]

发现了System.InvalidOperationException   _HResult = -2146233079   _message =附加类型&#39; Domain.User&#39;的实体。失败,因为同一类型的另一个实体已具有相同的主键值。使用&#39;附加&#39;方法或将实体的状态设置为“未更改”#39;或者&#39;修改&#39;如果图中的任何实体具有冲突的键值。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,请使用&#39;添加&#39;方法或“添加”#39;实体状态跟踪图形,然后将非新实体的状态设置为“未更改”。或者&#39;修改&#39;作为适当的。   的HResult = -2146233079   IsTransient = FALSE   消息=附加类型&#39; Domain.User&#39;的实体。失败,因为同一类型的另一个实体已具有相同的主键值。使用&#39;附加&#39;方法或将实体的状态设置为“未更改”#39;或者&#39;修改&#39;如果图中的任何实体具有冲突的键值。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,请使用&#39;添加&#39;方法或“添加”#39;实体状态跟踪图形,然后将非新实体的状态设置为“未更改”。或者&#39;修改&#39;作为适当的。   来源=的EntityFramework   堆栈跟踪:        at System.Data.Entity.Core.Objects.ObjectContext.VerifyRootForAdd(Boolean doAttach,String entitySetName,IEntityWrapper wrappedEntity,EntityEntry existingEntry,EntitySet&amp; entitySet,Boolean&amp; isNoOperation)        at System.Data.Entity.Core.Objects.ObjectContext.AttachTo(String entitySetName,Object entity)        at System.Data.Entity.Internal.Linq.InternalSet 1.<>c__DisplayClassa.<Attach>b__9() at System.Data.Entity.Internal.Linq.InternalSet 1.ActOnSet(Action action,EntityState newState,Object entity,String methodName)        在System.Data.Entity.Internal.Linq.InternalSet 1.Attach(Object entity) at System.Data.Entity.Internal.InternalEntityEntry.set_State(EntityState value) at System.Data.Entity.Infrastructure.DbEntityEntry 1.set_State(EntityState value)

1 个答案:

答案 0 :(得分:0)

我在repository中共享我的更新方法。我认为你可以使用这种方法。

protected override void PersistUpdateInternal(IStoreObject storeObject)
{
    if (storeObject == null)
        throw new NullReferenceException("storeObject");

    var original = GetOriginalEntity(storeObject);
    if (original != null)
    {
        var entry = _context.Entry(original);
        entry.CurrentValues.SetValues(storeObject);
    }
    else
    {
        GetDbSet().Attach((T)storeObject);
        _context.Entry(storeObject).State = EntityState.Modified;
    }

}
protected T GetOriginalEntity(IStoreObject storeObject)
{
    var objectContext = ((IObjectContextAdapter)_context).ObjectContext;
    var objectSet = objectContext.CreateObjectSet<T>();

    var entitySet = objectSet.EntitySet;
    var keyMembers = entitySet.ElementType.KeyMembers;

    Expression<Func<T, bool>> predicate = i => true;
    foreach (var keyMember in keyMembers)
    {
        var propertyInfo = typeof(T).GetProperty(keyMember.Name);

        var pe = Expression.Parameter(typeof(T), "i");
        var left = Expression.PropertyOrField(pe, keyMember.Name);
        var right = Expression.Constant(propertyInfo.GetValue(storeObject), propertyInfo.PropertyType);
        var body = Expression.Equal(left, right);
        var whereExpression = Expression.Lambda<Func<T, bool>>(body, pe);
        predicate = predicate.And(whereExpression);
    }

    var original = GetDbSet().Local.FirstOrDefault(predicate.Compile());

    return original;
}