2011-08-28 4 views
12

Śledziłem kilka przykładów (w tym takich książek jak „Pro ASP.NET MVC 3” i „Professional ASP .NET MVC 3 ") do tworzenia prostych aplikacji ASP.NET MVC 3 przy użyciu EF 4.1 (ponieważ jestem nowy w tych technologiach).„Obiekt o tym samym kluczu już istnieje w ObjectStateManager ...” jest wyjątek podczas ustawiania w stan podmiotu do zmodyfikowanej

ja za pomocą następującego składu (pojedynczy przypadek jest wykorzystywany przez wszystkie metody działania sterownika), aby uzyskać dostęp do DB:

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(); 
     } 

.... 
} 

To repozytorium wykonuje aktualizację jak wykazano w przykładach Użyłem.

Klasa produktu:

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; } 
} 

W przypadku aktualizowania produktu, dostaję wyjątek „Obiekt o tym samym kluczu już istnieje w ObjectStateManager ObjectStateManager nie może śledzić wiele obiektów z tego samego. klawisz”

wiem, że podobne pytania zostały już omówione tutaj, ale moje pytanie jest nieco inny:

Dlaczego ten kod która została podjęta z exampl es nie działa (chociaż wygląda całkiem prosto i prosto)? Cóż złego mogłem zrobić lub coś przeoczyłem.

+0

Mam ten sam błąd przy użyciu domyślnego rusztowania, który ustawia się Visual Studio dla ciebie i nie były w stanie żeby to rozgryźć. –

Odpowiedz

22

Po wyszukaniu godzin na rozwiązanie, znalazłem jeden, który wydaje się odpowiedni po wykonaniu wystarczającej ilości czytania.

Rozwiązaniem jest tutaj:

An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key

Zasadniczo pobrać rekord z kontekstu i wywołać:

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

Wydaje się to zły pomysł i coś zawsze nienawidził o EF w moich poprzednich prac, ale cccording do Ladislav Mrnka (który apparnently odbiera każde pytanie związane z EF na StackOverflow) w tym poście:

Entity Framework and Connection Pooling

EF będzie wewnętrznie przechowywać żądanie dla jednostki, więc najlepiej będzie już tam i nie będzie wykonywać dodatkowego połączenia z powrotem do bazy danych.

Przyczyną problemu wydaje się, że gdy produkt jest pobierany z kontekstu, że kontekst jest śledzenie go i to, co jest przyczyną wszystkich kłopotów. Zatem scalenie twoich zmian z powrotem jest jedynym sposobem.

Nadzieję, że pomaga.

+2

Aby uniknąć tego śledzenia, pomocne może być [AsNoTracking()] (http://msdn.microsoft.com/en-us/library/gg679352%28v=vs.103%29.aspx). –

3

Wygląda na to, że nie aktualizujesz product.ProductId gdy pozycja zostanie zapisana po raz pierwszy. Oznacza to, że po powrocie, aby ponownie zapisać element, dodaje on go ponownie do kontekstu, stąd błąd.

jako identyfikator zostanie dodana przez bazę danych (jestem przy założeniu, że to wygenerowany automatycznie Id) to musisz czytać dane produktu z powrotem do klienta.

0

Z Generics punktu widzenia, oto jak mam rozwiązać ten sam problem całkiem niedawno:

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; 
    } 
Powiązane problemy