Проблема с SaveChanges () Entity Framework 4.1

#many-to-many #entity-relationship #entity-framework-4.1

#многие ко многим #сущность-отношение #entity-framework-4.1

Вопрос:

У меня возникла проблема с сохранением изменений в базе данных.

Я обновляю модель A в своем контроллере, однако, когда я сохраняю изменения с помощью SaveChanges () В итоге у меня дублируется элемент в базе данных для B.

После вызова UpdateModel () я проверил свойство Bs, и все было так, как я ожидал, однако сразу после вызова SaveChanges (), если я проверю свойство Bs, я увижу, что идентификатор полностью отличается (новый идентификатор и новая запись).

Мой класс похож на этот:

 public class A
{
    [HiddenInput(DisplayValue = false)]
    public int AId { get; set; }

    public string Name { get; set; }

    public virtual ICollection<B> Bs{ get; set; }
}

public class B
{
    [HiddenInput(DisplayValue = false)]
    public int BId { get; set; }

    public string Name { get; set; }

    public virtual ICollection<A> As{ get; set; }
}
  

Мой контроллер такой :

     [HttpPost]
    public ActionResult Edit(A theA)
    {
        try
        {
           db.Entry(theA).State = EntityState.Modified;

           foreach (var item in theA.Bs)
           {
               db.Entry(item).State = EntityState.Modified;
           }

           db.SaveChanges();

           return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }
  

Я делаю что-то не так?

Заранее спасибо

Комментарии:

1. Ваш метод контроллера был бы важен, чтобы увидеть, где вы извлекаете объекты из базы данных, изменяете их и вызываете SaveChanges.

Ответ №1:

Это обычное поведение. Проблема в том, что EF не знает, что вы прикрепили существующую B , поэтому она автоматически вставляет новую запись. Вы должны сообщить EF, что B существует, вызвав:

 // here add B to the collection in the A and after that call:
dbContext.Entry<B>(someB).State = EntityState.Unchanged();
  

или путем прикрепления B перед добавлением в коллекцию в A (я не уверен, возможно ли это при использовании UpdateModel в ASP.NET MVC).

 dbContext.Bs.Attach(someB);
// now add B to the collection in the A
  

Другая возможность заключается в том, чтобы сначала загрузить B из базы данных и добавить загруженный объект в коллекцию в A , но это дополнительный обратный путь к базе данных.

 int id = someB.Id;
var loadedB = dbCotnext.Bs.Single(b => b.Id == id);
someA.Bs.Add(loadedB);
dbContext.As.Add(someA);
dbContext.SaveChanges();
  

Вывод: При каждом вызове Add весь граф объектов отслеживается как вставленный, если вы сначала не прикрепите связанные объекты (перед добавлением их к вставленному родительскому элементу — 2-й и 3-й примеры) или если вы вручную не измените состояние связанных объектов обратно на неизмененное после добавления родительского элемента. (первый пример).

Комментарии:

1. Спасибо, я попробовал первый метод, однако сразу после его вызова я получаю следующее сообщение: «Принятие изменений не может продолжаться, поскольку значения ключа объекта конфликтуют с другим объектом в ObjectStateManager. Убедитесь, что значения ключа уникальны, прежде чем вызывать AcceptChanges.»

2. Итак, как вы получили свой экземпляр B и как вы создали свой контекст? Создается ли экземпляр контекста для каждого запроса и используется ли B с заданным ключом только один раз (единственный экземпляр) для каждого контекста?

3. Я добавил свой ActionMethod к вопросу, не могли бы вы, пожалуйста, взглянуть?

4. Теперь я могу редактировать без каких-либо проблем, создав совершенно новый контекст в моем методе action. Правильно ли это? Почему я не могу сохранить один контекст для всего контроллера?

5. Использовали ли вы контекст вашего контроллера для чего-нибудь еще? Это для каждого контекста запроса или для общего контекста на глобальном уровне?