在Repository模式中,个人Update方法老是没法更新实体,这个很是郁闷,Update方法以下:html
1: public virtual void Update(T entity)
2: {
3: try
4: {
5: if (entity == null) throw new ArgumentNullException("实体类为空");
6: Context.Entry(entity).State = EntityState.Modified;
7: //Context.SaveChanges();
8: }
9: catch (DbEntityValidationException dbex)
10: {
11: var msg = string.Empty;
12: foreach (var validationErrors in dbex.EntityValidationErrors)
13: foreach (var validateionError in validationErrors.ValidationErrors)
14: msg += string.Format("Property:{0} Error:{1}", validateionError.PropertyName, validateionError.ErrorMessage);
15:
16: var fail = new Exception(msg, dbex);
17: throw fail;
18: }
19: }
看上去是没有任何问题的代码,一旦有实体更新的时候,总会出现以下的错误提示:ios
Attaching an entity of type
'TinyFrame.Data.DomainModel.t_user_application' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
看字面意思,好像是个人EntityState设置不正确致使的,虽然我尝试太重新设置几回EntityState,可是仍旧没法解决个人问题。web
而后实在找不出缘由,就利用关键字 “ EF Repository Update ”在Google上面搜集,果真找到一篇文章:Advanced Entity Framework 6 Scenarios for an MVC 5 Web Application (12 of 12),其中有一段话,提出了问题的所在:mvc
This happened because of the following sequence of events:
The Edit method calls the ValidateOneAdministratorAssignmentPerInstructor method, which retrieves all departments that have Kim Abercrombie as their administrator. That causes the English department to be read. As a result of this read operation, the English department entity that was read from the database is now being tracked by the database context.
The Edit method tries to set the Modified flag on the English department entity created by the MVC model binder, which implicitly causes the context to try to attach that entity. But the context can't attach the entry created by the model binder because the context is already tracking an entity for the English department.
One solution to this problem is to keep the context from tracking in-memory department entities retrieved by the validation query. There's no disadvantage to doing this, because you won't be updating this entity or reading it again in a way that would benefit from it being cached in memory.
问题的缘由以下:app
在Context对象中,已经hold住了一个须要操做的对象,当咱们把EntityState修改为modified的时候,Context会再次去加载那个操做对象,可是这样加载是没法成功的,由于当前已经存在一个对象了,再加载会致使重复,而后抛出失败的错误。asp.net
解决方法很简单,就是在展现列表的时候,利用AsNoTracking将Hold住的对象释放掉便可。咱们修改代码以下:post
1: public virtual T Get(Expression<Func<T, bool>> where)
2: {
3: return Dbset.Where(where).AsNoTracking().FirstOrDefault<T>();
4: }
5:
6: public virtual IQueryable<T> GetMany(Expression<Func<T, bool>> where)
7: {
8: return Dbset.Where(where).AsNoTracking();
9: }
而后提交,OK,问题解决。this
=============================Update 2014.09.19======================spa
看到评论中有朋友虽然按照上述方法,可是仍然没法解决这一问题。缘由是在Context中还保留有当前实体的副本所致,这里只要咱们将实体副本从内存中彻底移除,就能够了。.net
//用于监测Context中的Entity是否存在,若是存在,将其Detach,防止出现问题。 private Boolean RemoveHoldingEntityInContext(T entity) { var objContext = ((IObjectContextAdapter)_context).ObjectContext; var objSet = objContext.CreateObjectSet<T>(); var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entity); Object foundEntity; var exists = objContext.TryGetObjectByKey(entityKey, out foundEntity); if (exists) { objContext.Detach(foundEntity); } return (exists); }
而后在Repository中,在进行更新和删除以前,运行一下便可:
public T Remove(T entity) { try { RemoveHoldingEntityInContext(entity); _context.DbSet<T>().Attach(entity); return _context.DbSet<T>().Remove(entity); } catch (DbEntityValidationException dbex) { var msg = string.Empty; foreach (var validationErrors in dbex.EntityValidationErrors) foreach (var validateionError in validationErrors.ValidationErrors) msg += string.Format("属性:{0} 错误:{1}", validateionError.PropertyName, validateionError.ErrorMessage); var fail = new Exception(msg, dbex); throw fail; } } public T Update(T entity) { try { RemoveHoldingEntityInContext(entity); var updated = _context.DbSet<T>().Attach(entity); _context.DbContext.Entry(entity).State = EntityState.Modified; return updated; } catch (DbEntityValidationException dbex) { var msg = string.Empty; foreach (var validationErrors in dbex.EntityValidationErrors) foreach (var validateionError in validationErrors.ValidationErrors) msg += string.Format("属性:{0} 错误:{1}", validateionError.PropertyName, validateionError.ErrorMessage); var fail = new Exception(msg, dbex); throw fail; } }
仍然出错,就说明你内存中仍然保留有实体对象,你能够经过调用objectcontext,来吧这个对象实体从内存中remove掉便可。