在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掉便可。