#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. Использовали ли вы контекст вашего контроллера для чего-нибудь еще? Это для каждого контекста запроса или для общего контекста на глобальном уровне?