尝试保存更新时,由于相同的主键而附加实体时出错

我试图保存对现有数据库条目的更新,但是当我这样做时,我收到错误:

附加“FFInfo.DAL.Location”类型的实体失败,因为同一类型的另一个实体已具有相同的主键值。 如果图中的任何实体具有冲突的键值,则在使用“附加”方法或将实体的状态设置为“未更改”或“已修改”时,可能会发生这种情况。 这可能是因为某些实体是新的并且尚未收到数据库生成的键值。 在这种情况下,使用“添加”方法或“已添加”实体状态来跟踪图形,然后根据需要将非新实体的状态设置为“未更改”或“已修改”。

这是我的控制器代码。 我正在使用的保存方法与我在其他几个方面使用的保存方法相同,可以毫无问题地更新数据。

[HttpPost, ValidateAntiForgeryToken] public ActionResult EditLocation(AddEditLocationVM model, HttpPostedFileBase MapFile) { try { using (var db = new GeographyContext()) { model.Sections = new SelectList(db.Sections.Where(s => s.ID > 1).OrderBy(s => s.Title), "ID", "Title").ToList(); model.GeographyTypes = new SelectList(db.GeographyTypes.Where(gt => gt.SectionID == model.Section).OrderBy(gt => gt.Name), "ID", "Name").ToList(); model.ParentLocations = new SelectList(db.Locations.Where(l => l.SectionID == model.Section).OrderBy(l => l.Name), "ID", "Name").ToList(); if (MapFile != null) { if (FileHelper.IsNotValidImage(MapFile)) { ModelState.AddModelError("Invaalid File Type", "Images must be JPG, GIF, or PNG files."); } } if (ModelState.IsValid) { if (MapFile != null) { var SectionRoute = db.Sections.Where(s => s.ID == model.Section).Select(s => s.Route).First(); model.MapFileID = FileHelper.UploadFile("Images/" + SectionRoute + "/Maps/" + MapFile.FileName.ToList(), "site", MapFile); } if (model.ParentLocation == 0) { model.ParentLocation = null; } var UpdatedLocation = new Location() { Description = model.Description, GeographyTypeID = model.GeographyType, ID = model.ID, MapFileID = model.MapFileID, Name = model.Name, ParentLocationID = model.ParentLocation, SectionID = model.Section }; db.Entry(UpdatedLocation).State = EntityState.Modified; db.SaveChanges(); ViewBag.Results = "Location information updated."; } return View(model); } } catch (Exception ex) { ErrorSignal.FromCurrentContext().Raise(ex); model.Sections = Enumerable.Empty(); ViewBag.Results = "Error updating location informaiton, please try again later."; return View(model); } } 

这是我的位置实体代码:

 public class Location { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ID { get; set; } [Required, Index("IX_Location", 1, IsUnique = true)] public string Name { get; set; } [Index("IX_Location", 2, IsUnique = true)] public Int16 SectionID { get; set; } [Column(TypeName = "varchar(MAX)")] public string Description { get; set; } public Int16 GeographyTypeID { get; set; } public int? MapFileID { get; set; } public int? ParentLocationID { get; set; } [ForeignKey("SectionID")] public Section Section { get; set; } [ForeignKey("GeographyTypeID")] public GeographyType GeographyType { get; set; } [ForeignKey("MapFileID")] public File Map { get; set; } [ForeignKey("ParentLocationID")] public Location ParentLocation { get; set; } public ICollection TransitionPoints { get; set; } } 

这是我第一次尝试更新这样一个更复杂的实体,但是从我在网上找到的内容我看不出有什么不妥。

在Entity Framework中,内存中不能有两个具有相同主键的实体(相同类型)。

问题是

 model.ParentLocations = new SelectList(db.Locations.Where(l => l.SectionID == model.Section).OrderBy(l => l.Name), "ID", "Name").ToList(); 

在上面的行中你以某种方式加载了它的IDmodel.ID

然后在

 var UpdatedLocation = new Location() { Description = model.Description, GeographyTypeID = model.GeographyType, ID = model.ID, MapFileID = model.MapFileID, Name = model.Name, ParentLocationID = model.ParentLocation, SectionID = model.Section }; db.Entry(UpdatedLocation).State = EntityState.Modified; 

您正在创建一个新Location并尝试将其附加到上下文(通过将其状态设置为已修改),但您已将另一个具有精确主键的Location实体作为UpdatedLocation到内存中,这会导致exception。

尝试获取位置,然后更改属性。

 var UpdateLocation = db.Locations.First(l => l.ID == model.ID); // var UpdateLocation = db.Locations.Find(model.ID); maybe a better option UpdatedLocation.Description = model.Description; UpdatedLocation.GeographyTypeID = model.GeographyType; UpdatedLocation.MapFileID = model.MapFileID; UpdatedLocation.Name = model.Name; UpdatedLocation.ParentLocationID = model.ParentLocation; UpdatedLocation.SectionID = model.Section; 

尝试通过id获取实体,而不是创建具有固定ID的新实体:

 var UpdateLocation = db.Locations.FirstOrDefault( l => l.ID == model.ID ); UpdateLocation.Description = model.Description; ... 

你看到你的例外的原因是因为你的

 model.ParentLocations = ... 

实现最有可能包含您尝试修改的实体的实体。 因此,该实体已经处于第一级缓存中。

但后来你试图假装另一个存在相同身份的实体。