Другой объект того же типа уже имеет то же значение первичного ключа

Я работаю над методом редактирования для модели, которая имеет отношение один-ко-многим: Grid и Gridboxes. Всякий раз, когда я пытаюсь редактировать содержимое сетки, я получаю эту ошибку:

Не удалось присоединить объект типа "MyProject.Models.Gridbox", поскольку другой объект того же типа уже имеет такое же значение первичного ключа. Это может произойти при использовании метода "Присоединить" или установке состояния объекта на "Неизменен" или "Изменен", если какие-либо объекты в графе имеют конфликтующие значения ключей. Это может быть потому, что некоторые объекты являются новыми и еще не получили сгенерированные базой данных значения ключей. В этом случае используйте метод "Добавить" или "Добавленный" объект сущности, чтобы отслеживать график, а затем установите состояние не новых объектов в "Неизмененный" или "Измененный", в зависимости от ситуации.

Вот мой метод редактирования:

    [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. Если у gridbox была изменена его позиция или размер, обновите эти значения в базе данных (с помощью db.Entry(originalGridbox).CurrentValues.SetValues(gridbox),
  3. Если gridbox был удален из сетки, удалите его из коллекции Grid.Gridboxes

Так что я не могу понять ошибку выше. Первичный ключ - GridboxID.

Наблюдение: добавляются новые сетки и существующие размеры сетки изменяются без проблем. После того, как я получаю сообщение об ошибке, я могу вернуться в таблицу, и изменения были сохранены. Кажется, проблема в существующих сетках. Он пытается повторно добавить их в базу данных по какой-то причине.

1 ответ

После десериализации вашего объекта json попробуйте подключить его к текущему контексту базы данных перед вызовом метода update - вот почему он завершается неудачно при обновлении, поскольку у него есть два объекта с одинаковым идентификатором. Код для этого будет выглядеть примерно так:

   db.grids.Attach(grid);

Таким образом, ef должен корректно отслеживать все изменения на вашем объекте.

Другие вопросы по тегам