EF Code First - 以多对多的方式填充数据

时间:2014-03-10 11:08:09

标签: asp.net-mvc ef-code-first

我是ASP.Net MVC的新手,想要创建一个简单的Blog项目,因此我有两个实体postscategories。每个帖子可以属于许多类别,每个类别可以属于许多帖子。

Models.cs

public class Category
{
    [Key]
    public int CategoryId { get; set; }
    public int? ParentId { get; set; }
    public virtual Category Parent { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
    public virtual ICollection<News> News { get; set; }

    public Category()
    {
        News = new List<News>();
    }
}
public class News
{
    [Key]
    public int NewsId { get; set; }
    public string Title { get; set; }
    public string Summary { get; set; }
    public string Content { get; set; }
    public string Source { get; set; }
    public string SourceURL { get; set; }
    public string Images { get; set; }
    public string Password { get; set; }

    public DateTime CreatedAt { get; set; }
    public DateTime? ModifiedAt { get; set; }
    public DateTime? DeletedAt { get; set; }
    public string CreatedBy { get; set; }
    public string DeletedBy { get; set; }
    public virtual PublishPeriod PublishPeriodId { get; set; }
    public virtual ICollection<Category> Categories { get; set; }

    public News()
    {
        Categories = new List<Category>();
    }

}

ModelsMap.cs

  public class CategoryMap:EntityTypeConfiguration<Category>
    {
        public CategoryMap()
        {
            Property(one => one.Title).HasMaxLength(100).IsRequired();
            HasOptional(x => x.Parent).WithMany().HasForeignKey(x => x.ParentId);
        }
    }

    public class NewsMap:EntityTypeConfiguration<News>
    {
        public NewsMap()
        {
            Property(x => x.CreatedBy).HasMaxLength(150);
            Property(x => x.DeletedBy).HasMaxLength(150);
            Property(x => x.Title).IsRequired().HasMaxLength(150);
            Property(x => x.Summary).IsRequired();
            Property(x => x.Content).IsRequired().HasColumnType("ntext");
            Property(x => x.CreatedAt).HasColumnType("datetime");
            Property(x => x.Password).IsOptional().HasMaxLength(128);
            Property(x => x.DeletedAt).IsOptional();
            Property(x => x.ModifiedAt).IsOptional();
            HasMany(x => x.Categories).WithMany(x => x.News).Map(x =>
            {
                x.ToTable("NewsCategories");
                x.MapLeftKey("News_NewsId");
                x.MapRightKey("Category_CategoryId");
            });
        }
    }

数据库上下文

  public DbSet<Category> Categories { get; set; }
    public DbSet<News> News { get; set; }
    public DbSet<PublishPeriod> PublishPeriod { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Configurations.Add(new CategoryMap());
        modelBuilder.Configurations.Add(new NewsMap());
        modelBuilder.Configurations.Add(new PublishPeriodMap());

我有一个posts的创建视图,它在列表中显示带有复选框的类别,每个复选框值都是类别的ID。如何插入或更新帖子并保持帖子和类别之间的关系
NewsController

//
// POST: /Admin/News/Create
[HttpPost]
public ActionResult Create(News news, List<string> Category)
{
    ViewBag.Categories = catRepository.All.OrderBy(x => x.Title);
    if (ModelState.IsValid)
    {
        foreach (var item in Category)
        {
            news.AddCategory(catRepository.Find(int.Parse(item)));
        }
        news.CreatedAt = DateTime.Now;
        news.CreatedBy = "M.Hesabi";
        newsRepository.InsertOrUpdate(news);
        newsRepository.Save();
        return RedirectToAction("Index");
    }
    else
    {
        return View();
    }
}

更新:我在News模型中创建了一个方法,因为@DanS说并编辑了我的控制器。

1 个答案:

答案 0 :(得分:1)

我建议在News类上创建一个方法:

public void AddCategory(Category category) {
    Categories.Add(category);
    category.News.Add(this);
}

然后,您可以从Controller中将每个选定的类别添加到新闻实例,然后在调用SaveChanges之前将新闻添加到DbContext。但是,这可能取决于您的存储库如何使用上下文 - 因为如果它们打开自己的上下文而不是访问共享上下文,您可能必须在保存之前将类别附加到新闻存储库的上下文。希望这有助于......

<强>更新

IEntityChangeTracker错误:

似乎MVCScaffolding为每个存储库使用单独的上下文。如上所述,具有单独的上下文可能会导致一些额外的必需步骤。按照现在的情况,您的类别由上下文A跟踪,而您的新闻由上下文B跟踪 - 您可以在两个上下文之间分离/附加类别实体,但我想建议的解决方案是将您的存储库更改为通过构造函数接受共享上下文。

我假设您在控制器的构造函数中实例化存储库,而不是使用依赖注入,因此您可以修改构造函数代码以执行以下操作:

myContext = new YourContextClass();
catRepository = new CategoryRepository(myContext);
newsRepository = new NewsRepository(myContext);

然后,您必须将构造函数添加到存储库以分配内部上下文属性,最后调整控制器以正确处理上下文。

protected override void Dispose(bool disposing)
{
    if (disposing)
        myContext.Dispose();

    base.Dispose(disposing);
}