2012-07-08 20 views
6

He estudiado detenidamente StackOverflow, Google y asp.net tratando de encontrar un ejemplo claro y claro de cómo hacer esto. Todos los ejemplos han sido complicaciones abstractas o complicadas que no se aplican. No he podido extraer mucho de ellos. Hasta el momento, ninguno de ellos ha respondido completamente a mi pregunta o abordado mi (s) problema (s).¿Cómo actualizar/crear muchos datos relacionales en MVC Code-first usando EF?

estoy trabajando en un proyecto de MVC con el siguiente modelo:

Article.cs:

public class Article 
{ 

    public int ArticleId { get; set; } 
    public string Title { get; set; } 
    . 
    . 
    . 
    public virtual ICollection<Category> Categories { get; set; } 

    public Article() 
    { 
     Categories = new HashSet<Category>(); 
    } 
} 

Category.cs:

public class Category 
{ 
    public int CategoryId { get; set; } 
    public string Name { get; set; } 

    public virtual ICollection<Article> Articles { get; set; } 

    public Category() 
    { 
     Articles = new HashSet<Article>(); 
    } 
} 

ArticleEntities.cs:

public class ArticleEntities : DbContext 
{ 
    public DbSet<Article> Articles { get; set; } 
    public DbSet<Category> Categories { get; set; } 

} 

Un arte icle puede tener muchas categorías y una categoría puede pertenecer a muchos artículos.

Hasta ahora puedo guardar/actualizar/crear todos los campos del artículo excepto las Categorías.

Los estoy representando como casillas de verificación en la vista. Puedo obtener los valores para las casillas de verificación seleccionadas en el controlador, pero todos los intentos que hice para almacenarlos en el DB con el artículo han fallado.

¿Cómo puedo:

1) Al guardar un artículo editado, actualizar las relaciones existentes en la tabla de relación sin crear duplicados?

2) Al guardar un nuevo artículo, cree las relaciones elegidas en la tabla de relaciones?

Respuesta

9

Supongo que obtendrá una lista de CategoryId s de la acción de la acción del controlador, un List<int> o más general solo un IEnumerable<int>.

1) Al guardar un artículo editado, actualice las relaciones existentes en la tabla de relaciones sin crear duplicados?

Article article; // from post action parameters 
IEnumerable<int> categoryIds; // from post action parameters 

using (var ctx = new MyDbContext()) 
{ 
    // Load original article from DB including its current categories 
    var articleInDb = ctx.Articles.Include(a => a.Categories) 
     .Single(a => a.ArticleId == article.ArticleId); 

    // Update scalar properties of the article 
    ctx.Entry(articleInDb).CurrentValues.SetValues(article); 

    // Remove categories that are not in the id list anymore 
    foreach (var categoryInDb in articleInDb.Categories.ToList()) 
    { 
     if (!categoryIds.Contains(categoryInDb.CategoryId)) 
      articleInDb.Categories.Remove(categoryInDb); 
    } 

    // Add categories that are not in the DB list but in id list 
    foreach (var categoryId in categoryIds) 
    { 
     if (!articleInDb.Categories.Any(c => c.CategoryId == categoryId)) 
     { 
      var category = new Category { CategoryId = categoryId }; 
      ctx.Categories.Attach(category); // this avoids duplicate categories 
      articleInDb.Categories.Add(category); 
     } 
    } 

    ctx.SaveChanges(); 
} 

Tenga en cuenta que el código también funciona cuando se tiene un ArticleViewModel en lugar de un Article, teniendo en cuenta que los nombres de propiedad son los mismos (SetValues toma un arbitraria object).

2) Al guardar un nuevo artículo, cree las relaciones elegidas en la tabla de relaciones ?

Más o menos la misma idea que el anterior pero más simple, ya que no es necesario comparar con un estado original en la base de datos:

Article article; // from post action parameters 
IEnumerable<int> categoryIds; // from post action parameters 

using (var ctx = new MyDbContext()) 
{ 
    foreach (var categoryId in categoryIds) 
    { 
     var category = new Category { CategoryId = categoryId }; 
     ctx.Categories.Attach(category); // this avoids duplicate categories 
     article.Categories.Add(category); 
     // I assume here that article.Categories was empty before 
    } 
    ctx.Articles.Add(article); 

    ctx.SaveChanges(); 
} 
+0

"Asumo que se obtiene una lista de CategoryIDs de la controlador post acción, una lista o más general solo un IEnumerable . " – panzerblitzer

+0

Sí, soy categoryIds en una colección (Iumerable, en realidad). Todo parece que debería funcionar, pero una línea de código no se compilará: "if (! CategoryIds.Cualquiera (c => c.CategoryId == categoryInDb.CategoryId)) "Recibo un error que'int 'no contiene una definición para CategoryId.- – panzerblitzer

+0

@panzerblitzer: Sí, eso fue un error, lo siento. corrigió el código (usando 'Contains', ver arriba).' if (! categoryIds.Any (c => c == categoryInDb.CategoryId)) 'funcionaría igual. – Slauma

Cuestiones relacionadas