"Объект с тем же ключом уже существует в объекте ObjectStateManager..." возникает исключение при настройке состояния объекта для изменения
Я последовал за некоторыми примерами (включая такие книги, как "Pro ASP.NET MVC 3" и "Профессиональный ASP.NET MVC 3" ) для создания простых приложений ASP.NET MVC 3 с использованием EF 4.1 (поскольку я новичок в этих технологии).
Я использую следующий репозиторий (один экземпляр его используется всеми методами действий контроллера) для доступа к БД:
public class ProductRepository : IProductRepository
{
private readonly EFDbContext _context = new EFDbContext();
#region Implementation of IProductRepository
....
public void SaveProduct(Product product)
{
if (product.ProductId == 0)
{
_context.Products.Add(product);
}
else
{
_context.Entry(product).State = EntityState.Modified;
}
_context.SaveChanges();
}
....
}
Этот репозиторий выполняет обновление, как показано в примерах, которые я использовал.
Класс продукта:
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string Category { get; set; }
}
В случае обновления продукта я получаю исключение "Объект с тем же ключом уже существует в ObjectStateManager. ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом
Я знаю, что подобные вопросы уже обсуждались здесь, но мой вопрос немного другой:
Почему этот код , который был взят из примеров, не работает (хотя он выглядит довольно простым и понятным)? Что бы я не сделал или что-то пропустил.
Ответы
Ответ 1
После поиска часов для решения я нашел тот, который кажется подходящим после достаточного чтения.
Исправление:
Объект с тем же ключом уже существует в ObjectStateManager. ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом
В принципе, извлеките запись из контекста и вызовите:
var currentProduct = _context.Products.Find(product.ProductId);
_context.Entry(currentProduct).CurrentValues.SetValues(product);
Это похоже на плохую идею и что-то, что я всегда ненавидел в EF в своих предыдущих разработках, но в соответствии с Ladislav Mrnka (который прекрасно отвечает на каждый вопрос, связанный с EF на Stackoverflow) в этом сообщении:
Структура сущностей и пул соединений
EF будет хранить запрос для объекта внутри, так что в идеале он уже будет там, и он не будет делать дополнительный вызов обратно в базу данных.
Основная причина проблемы заключается в том, что, как только продукт извлекается из контекста, контекст отслеживает его и то, что вызывает все проблемы. Таким образом, объединение ваших изменений обратно является единственным способом.
Надеюсь, что это поможет.
Ответ 2
Похоже, вы не обновляете product.ProductId
, когда элемент сохраняется в первый раз. Это означает, что, когда вы вернетесь, чтобы снова сохранить элемент, он снова добавляет его в контекст, следовательно, ошибку.
Поскольку идентификатор будет добавлен базой данных (я предполагаю, что это автогенерированный идентификатор), вам нужно будет прочитать данные своего продукта на клиенте.
Ответ 3
С точки зрения Generics, вот как я решаю ту же самую проблему совсем недавно:
public TEntity Update(TEntity model, bool persist)
{
if (model == null)
{
throw new ArgumentException("Cannot update a null entity.");
}
var updateModel = Get(model.Id);
if (updateModel == null)
{
return model;
}
this.context.Entry<TEntity>(updateModel).CurrentValues.SetValues(model);
this.Save(persist);
return model;
}