2011-08-28 29 views
12

Modificado He seguido algunos ejemplos (incluidos libros como "Pro ASP.NET MVC 3" y "ASP profesional"). .NET MVC 3 ") para crear aplicaciones simples ASP.NET MVC 3 utilizando EF 4.1 (ya que soy nuevo en estas tecnologías)."Se lanza un objeto con la misma clave en la excepción ObjectStateManager ..." al establecer un estado de entidad en

estoy usando el siguiente repositorio (única instancia de que es utilizado por todos los métodos de acción del controlador) para acceder a la 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(); 
     } 

.... 
} 

Este repositorio realiza la actualización como se demostró en los ejemplos Solía.

clase de producto:

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

En caso de actualizar el producto, me estoy poniendo la excepción "Un objeto con la misma clave ya existe en la ObjectStateManager El ObjectStateManager no puede realizar un seguimiento de múltiples objetos con el mismo. tecla"

sé que las preguntas similares han sido ya discutidos aquí, pero mi pregunta es un poco diferente:

Por qué este código que fue tomado de exampl es no funciona (aunque parece bastante simple y directo)? ¿Qué mal podría haber hecho o perdido algo?

+0

estoy teniendo el mismo error utilizando el andamiaje predeterminado que Visual Studio prepara para usted y que no han podido para averiguarlo. –

Respuesta

22

Después de buscar horas para encontrar una solución, he encontrado una que parece adecuada después de leer lo suficiente.

La solución está aquí:

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

Básicamente, ir a buscar el registro del Contexto y llamar:

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

Esto parece una mala idea y algo que siempre he odiaba de EF en mis trabajos anteriores, pero de acuerdo con Ladislav Mrnka (que aparentemente contesta todas las preguntas relacionadas con EF en Stackoverflow) en esta publicación:

Entity Framework and Connection Pooling

EF almacenará una solicitud para una entidad internamente, por lo que, idealmente, ya estará allí y no hará una llamada adicional a la base de datos.

La causa principal del problema parece ser que una vez que se extrae un producto del Contexto, el contexto lo está siguiendo y eso es lo que está causando todos los problemas. Entonces, fusionar tus cambios nuevamente es la única forma.

Espero que ayude.

+2

Para evitar este seguimiento, [AsNoTracking()] (http://msdn.microsoft.com/en-us/library/gg679352%28v=vs.103%29.aspx) podría ayudar. –

3

Parece que no está actualizando product.ProductId cuando el elemento se guarda por primera vez. Esto significa que cuando vuelve a guardar el artículo nuevamente, lo vuelve a agregar al contexto, de ahí el error.

Como Id se agregará por la base de datos (supongo que es el identificador autogenerado), tendrá que volver a leer los datos del producto en el cliente.

0

Desde un punto de vista de los genéricos, así es como tengo que resolver el mismo problema hace muy poco:

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