Another entity of the same type already has the same primary key value

I'm working on an edit method for a model that has a one-to-many relationship: Grid and Gridboxes. Whenever I try to edit the contents of the grid, I get this error:

Attaching an entity of type 'MyProject.Models.Gridbox' 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.

Here is my Edit method:

    [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);
    }

Here's the helper UpdateGridGridboxes method:

    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);
            }
        }
    }

My thought process goes like this:

  1. If a gridbox has been added to the grid, add it to the Grid.Gridboxes collection.
  2. If a gridbox has had its position or size changed, update those values in the database (with db.Entry(originalGridbox).CurrentValues.SetValues(gridbox).
  3. If a gridbox has been removed from the grid, remove it from the Grid.Gridboxes collection

So I can't make sense of the error above. The primary key is GridboxID.

Observation: New gridboxes are added and existing gridboxes are resized without issues. After I get the error, I can come back to the grid and the changes have been saved. The problem seems to be with existing gridboxes. It tries to re-add them to the database for some reason.

Answers


After you deserialize you json object try attaching it to your current db context before calling update method - it is why it fails on update as it has two objects that has the same ID. The code for this would be something like this:

   db.grids.Attach(grid);

This way ef should correct track all the changes on your object.


Need Your Help

Node.js: Closing all Redis clients on shutdown

javascript node.js redis node-redis

Today, I integrated Redis into my node.js application and am using it as a session store. Basically, upon successful authentication, I store the corresponding user object in Redis.

Cloudant / CouchDB "pull" replication for 600+ documents to iPhone

iphone couchdb cloudant couchcocoa

I'm using Cloudant and I'm struggling to pull/replicate 600 documents from server to my iPhone. First, it's pretty slow because it has to go one-document-at-a-time, and Second Cloudant was giving ...