How to update/create many-to-many relational data in MVC Code-first using EF?

后端 未结 1 1136
旧巷少年郎
旧巷少年郎 2021-02-04 18:50

I have pored through StackOverflow, Google and asp.net trying to find a clear cut, basic example of how to do this. All the examples have been abstract or involved complications

1条回答
  •  慢半拍i
    慢半拍i (楼主)
    2021-02-04 19:26

    I assume that you get a list of CategoryIds from the controller post action, a List or more general just an IEnumerable.

    1) When saving an edited article, update the existing relations in the relation table without creating duplicates?

    Article article; // from post action parameters
    IEnumerable 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();
    }
    

    Note that the code also works when you have a ArticleViewModel instead of an Article, given that the property names are the same (SetValues takes an arbitrary object).

    2) When saving a new article, create the chosen relations in the relation table?

    More or less the same idea as above but simpler because you don't need to compare with an original state in the database:

    Article article; // from post action parameters
    IEnumerable 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 讨论(0)
提交回复
热议问题