Исключение «объект с тем же ключом уже существует в ObjectStateManager ...» выдается при установке измененного состояния объекта - PullRequest
12 голосов
/ 28 августа 2011

Я следовал некоторым примерам (включая такие книги, как "Pro ASP.NET MVC 3" и "Professional 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 не может отслеживать несколько объектов с одним и тем же ключом "

Я знаю, что подобные вопросы уже обсуждались здесь, но мой вопрос немного отличается:

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

Ответы [ 3 ]

22 голосов
/ 29 августа 2011

После нескольких часов поиска решения я нашел подходящее решение после того, как прочитал достаточно.

Исправление здесь:

Объект с таким же ключом уже существует в ObjectStateManager. ObjectStateManager не может отслеживать несколько объектов с одним и тем же ключом

В основном, извлеките запись из контекста и позвоните:

var currentProduct = _context.Products.Find(product.ProductId);    
_context.Entry(currentProduct).CurrentValues.SetValues(product);

Это кажется плохой идеей и тем, что я всегда ненавидел в EF в своих предыдущих работах, но, по словам Ладислава Мринки (который, по всей видимости, отвечает на каждый вопрос, связанный с EF в Stackoverflow) в этом посте:

Entity Framework и пул соединений

EF будет хранить запрос для сущности внутри, поэтому в идеале он уже будет там, и он не будет делать дополнительный обратный вызов в базу данных.

Основная причина проблемы, по-видимому, заключается в том, что, как только продукт извлекается из контекста, контекст отслеживает его, и именно это вызывает все проблемы. Таким образом, объединение ваших изменений - единственный способ.

Надеюсь, это поможет.

3 голосов
/ 28 августа 2011

Похоже, вы не обновляете product.ProductId, когда элемент сохраняется в первый раз. Это означает, что когда вы возвращаетесь, чтобы сохранить элемент снова, он снова добавляет его в контекст, поэтому возникает ошибка.

Поскольку идентификатор будет добавлен базой данных (я предполагаю, что это автоматически сгенерированный идентификатор), вам потребуется прочитать данные о продукте обратно на клиент.

0 голосов
/ 29 января 2014

С точки зрения обобщения, вот как я решил эту проблему совсем недавно:

    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;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...