如何使用EF在MVC Code-first中更新/创建多对多关系数据?

pan*_*zer 6 c# asp.net-mvc many-to-many entity-framework asp.net-mvc-3

我通过StackOverflow,谷歌和asp.net试图找到一个明确的基本示例,如何做到这一点.所有的例子都是抽象的或涉及不适用的并发症.我无法从中提取很多有用的东西.到目前为止,他们都没有完全回答我的问题或解决我的问题.

我正在使用以下模型开发MVC项目:

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>();
    }
}
Run Code Online (Sandbox Code Playgroud)

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>();
    }
}
Run Code Online (Sandbox Code Playgroud)

ArticleEntities.cs:

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

}
Run Code Online (Sandbox Code Playgroud)

一篇文章可以有很多类别,一个类别可以属于很多文章.

到目前为止,我可以保存/更新/创建除类别之外的所有文章字段.

我将它们表示为视图中的复选框.我可以将所选复选框的值添加到控制器中,但是,我用文章将它们存储在数据库中的每次尝试都失败了.

我如何能:

1)保存已编辑的文章时,更新关系表中的现有关系而不创建重复项?

2)保存新文章时,在关系表中创建所选关系?

Sla*_*uma 10

我假设您CategoryId从控制器发布操作获得一个s 列表,一个List<int>或多个通用只是一个IEnumerable<int>.

1)保存已编辑的文章时,更新关系表中的现有关系而不创建重复项?

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();
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果您具有a ArticleViewModel而不是a,则代码也可以使用Article,因为属性名称相同(SetValues采用任意object).

2)保存新文章时,在关系表中创建所选关系?

或多或少与上面相同,但更简单,因为您不需要与数据库中的原始状态进行比较:

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();
}
Run Code Online (Sandbox Code Playgroud)