另一个相同类型的实体已具有相同的主键值

时间:2015-12-03 18:56:20

标签: c# asp.net-mvc entity-framework asp.net-mvc-5

我正在为具有一对多关系的模型编写一个编辑方法:Grid和Gridboxes。每当我尝试编辑网格的内容时,我都会收到此错误:

  

附加类型' MyProject.Models.Gridbox'的实体。失败,因为同一类型的另一个实体已具有相同的主键值。使用'附加'方法或将实体的状态设置为“未更改”#39;或者'修改'如果图中的任何实体具有冲突的键值。这可能是因为某些实体是新的并且尚未收到数据库生成的键值。在这种情况下,请使用'添加'方法或“添加”#39;实体状态跟踪图形,然后将非新实体的状态设置为“未更改”。或者'修改'酌情。

这是我的编辑方法:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit([Bind(Include = "GridID,Title")] Grid grid, string gridboxes)
    {
        GridboxCollection gridboxList = JsonConvert.DeserializeObject<GridboxCollection>(gridboxes);
        grid.Gridboxes = gridboxList.Gridboxes;
        UpdateGridGridboxes(gridboxList.Gridboxes, grid);

        if (ModelState.IsValid)
        {
            db.Entry(grid).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(grid);
    }

这是帮助UpdateGridGridboxes方法:

    private void UpdateGridGridboxes(Gridbox[] gridboxes, Grid gridToUpdate)
    {
        // If edited grid has no gridboxes (user has deleted all of them)
        if (gridboxes.Length == 0)
        {
            gridToUpdate.Gridboxes = new List<Gridbox>();
            return;
        }
        // If edited grid does have at least one gridbox
        else
        {
            gridToUpdate.Gridboxes = gridToUpdate.Gridboxes.ToList();
            foreach (var gridbox in gridboxes)
            {

                // If there is no gridboxID (if it's a new gridbox), add it to the grid's gridbox list
                if (gridbox.GridBoxID == 0)
                {
                    gridbox.GridID = gridToUpdate.GridID;
                    gridToUpdate.Gridboxes.Add(gridbox);
                    db.Entry(gridbox).State = EntityState.Added;
                    db.SaveChanges();
                }
                // If it's an existing gridbox, update its properties
                else
                {
                    var originalGridbox = db.Gridbox.Find(gridbox.GridBoxID);

                    if (originalGridbox != gridbox)
                    {
                        db.Entry(originalGridbox).CurrentValues.SetValues(gridbox);
                        db.Entry(originalGridbox).Property(x => x.GridID).IsModified = false;
                        db.Entry(originalGridbox).State = EntityState.Modified;
                        db.SaveChanges();
                    }
                    else
                    {
                        db.Entry(originalGridbox).State = EntityState.Unchanged;
                    }
                }
            }
        }
        var existingGridboxesInGrid = gridToUpdate.Gridboxes;

        // iterate through existing gridboxes and remove the ones that have been deleted from the grid
        foreach (var existingGridboxInGrid in existingGridboxesInGrid)
        {
            if (!gridboxes.Contains(existingGridboxInGrid))
            {
                gridToUpdate.Gridboxes.Remove(existingGridboxInGrid);
            }
        }
    }

我的思维过程是这样的:

  1. 如果已将网格框添加到网格中,请将其添加到Grid.Gridboxes集合中。
  2. 如果某个网格框的位置或大小已更改,请更新数据库中的这些值(使用db.Entry(originalGridbox).CurrentValues.SetValues(gridbox)
  3. 如果已从网格中删除了网格框,请将其从Grid.Gridboxes集合中删除
  4. 所以我无法理解上面的错误。主键是GridboxID。

    观察:添加了新的网格框,并且调整了现有网格框的大小而没有任何问题。收到错误后,我可以回到网格并保存更改。问题似乎与现有的网格盒有关。它出于某种原因尝试将它们重新添加到数据库中。

1 个答案:

答案 0 :(得分:0)

反序列化后,json对象尝试在调用update方法之前将其附加到当前的db上下文 - 这就是为什么它在更新时失败,因为它有两个具有相同ID的对象。这个代码就像这样:

   db.grids.Attach(grid);

这样,ef应该正确跟踪对象上的所有更改。