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

本文关键字:出错 实体 于主键 保存 更新 | 更新日期: 2023-09-27 18:12:32

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

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

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

[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<SelectListItem>();
        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<LocationTransitionPoint> TransitionPoints { get; set; }
}

这是我第一次尝试更新这样一个更复杂的实体,但从我在网上发现的,我看不到任何错误。

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

在实体框架中不能有两个具有相同主键的实体(相同类型)

问题是

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

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

then in

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加载到内存中的某个地方,这会导致异常。

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

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 = ...

具体化的实体很可能包括您试图修改的实体。因此,实体已经在第一级缓存中。

但是你试图假装存在另一个相同id的实体

我刚刚创建了一个新的contexttity实例,代码运行正常