entity framework:objectstatemanager中已存在具有相同密钥的对象

我看到这个问题已经被问了很多,但是我还没有发现任何可以解决我遇到的问题的东西。

显然我正在使用entity framework来执行记录更新。 但是,一旦更新完成,每当我尝试保存时,都会收到以下错误消息:

An object with the same key already exists in the objectstatemanager 

起初,我从包含ZipCodeTerritory模型对象zipToUpdate副本的视图中传入一个集合对象。 我通过拉出这个对象来改变代码,而只是发送相关的字段。 但是,我仍然遇到同样的错误。

还有什么奇怪的是我第一次运行这段代码,它运行正常。 在我得到错误之后的任何尝试。

调节器

以下是调用编辑函数的方法的代码

 public static string DescriptionOnly(ZipCodeIndex updateZip) { if (!string.IsNullOrWhiteSpace(updateZip.newEffectiveDate) || !string.IsNullOrWhiteSpace(updateZip.newEndDate)) { return "Neither effective or end date can be present if updating Territory Code only; "; } _updated = 0; foreach (var zipCode in updateZip.displayForPaging.Where(x => x.Update)) { ProcessAllChanges(zipCode, updateZip.newTerritory, updateZip.newStateCode, updateZip.newDescription, updateZip.newChannelCode); } _msg += _updated + " record(s) updated; "; return _msg; } 

这是实际进行更新的方法。

 private static void ProcessAllChanges(ZipCodeTerritory zipToUpdate, string newTerritory, string newStateCode, string newDescription, string newChannelCode) { try { if (!string.IsNullOrWhiteSpace(newTerritory)) zipToUpdate.IndDistrnId = newTerritory; if (!string.IsNullOrWhiteSpace(newStateCode)) zipToUpdate.StateCode = newStateCode; if (!string.IsNullOrWhiteSpace(newDescription)) zipToUpdate.DrmTerrDesc = newDescription; if (!string.IsNullOrWhiteSpace(newChannelCode)) zipToUpdate.ChannelCode = newChannelCode; if (zipToUpdate.EndDate == DateTime.MinValue) zipToUpdate.EndDate = DateTime.MaxValue; _db.Entry(zipToUpdate).State = EntityState.Modified; _db.SaveChanges(); _updated++; } catch (DbEntityValidationException dbEx) { _msg += "Error during update; "; EventLog.WriteEntry("Monet", "Error during ProcessAllChanges: " + zipToUpdate.ToString() + " |EX| " + dbEx.Message); } catch (Exception ex) { _msg += "Error during update; "; EventLog.WriteEntry("Monet", "Error during ProcessAllChanges: " + zipToUpdate.ToString() + " |MESSAGE| " + ex.Message); } } 

编辑

ZipCodeIndex对象包含ZipCodeTerritory模型对象的列表。 这些不是从linq查询中提取的,而是简单地从视图传递回控制器。 以下是启动该过程的控制器方法的签名:

 [HttpPost] public ActionResult Update(ZipCodeIndex updateZip, string button) 

这是由于数据库上下文的不恰当处理,因为您从不处理上下文对象本身,您将遇到这些类型的问题。

我建议将代码包装在using语句中。

 using (var context = new MyContext()) { // Do my save code here... } 

这将确保正确处理背景!

当我遇到这种类型的问题时 – 我还没有看到这个问题,但有很多人喜欢它 – 这是因为要么我用一个上下文检索了我的实体而我试图用另一个来保存它们或者是因为某些东西碰巧导致entity framework失去对它们的追踪 – 使用GetAsNoTracking将它们从数据存储区中GetAsNoTracking会产生这种效果,尽管如果你知道你不会改变那些提供明显性能优势的实体。

这样做的结果是,EF认为您正在保存一个新实体,该实体恰好具有与其已知的相同的大部分属性,而不是对其熟悉的实体进行更改。

从您的代码中,我无法告诉您确切的解决方案是什么,但我会通过密切关注您检索实体的位置并确保通过相同的上下文保存更改来开始对此进行故障排除。

您的编辑建议您将新的ZipCodeTerritory对象从视图中传递给控制器​​。 这些可能会映射到商店中现有的ZipCodeTerritory条目,因此这里发生的是因为它们不是数据库中出来但是它们是正确类型的实体,因此数据上下文将它们视为新对象。 它不知道您正在更新现有记录,因为它没有创建它们,因此它不保留对从视图返回的这些对象的跟踪引用。

现在可能有一个更优雅的解决方案 – 我目前正在使用4.5,所以我还没有看到更近期的EF行为 – 但一个简单的解决方案是从数据存储中检索匹配的ZipCodeTerritory对象然后更新它们并保存回来。 在这种情况下,虽然您传回的对象属于ZipCodeTerritory类型,但它们的行为更像是数据传输对象,这是造成混淆的一部分 – 因为它们是由视图创建的(尽管源自数据存储区中的数据) )您的数据上下文根本无法识别它们。