在数据库设计中,多对多关系是一个常见的概念,它描述了两个实体之间复杂的关联关系。例如,一个训练师可以训练多个课程,而一个课程也可以由多个训练师来管理。为了在数据库中实现这种关系,需要创建一个额外的关联表来存储这些关系。
在本文中,将通过一个实际的示例来展示如何在Entity Framework中实现多对多关系。将创建一个名为“TrainsOnCourse”的新表,用于存储训练师和课程之间的关联关系。
首先,需要创建一个名为“Trainer”的模型。这个模型将代表数据库中的训练师实体。可以使用Entity Framework的迁移功能来更新数据库,以便在SQL Server数据库中添加训练师表。
        public class Trainer
        {
            public int TrainerId { get; set; }
            public string Name { get; set; }
            // 导航属性
            public virtual ICollection<TrainsOnCourse> TrainsOnCourses { get; set; }
        }
    
接下来,需要在DbContext类中添加一个DBSet实体属性,用于表示TrainsOnCourse表。
        public class DNSCContext : DbContext
        {
            public DbSet<Trainer> Trainers { get; set; }
            public DbSet<TrainsOnCourse> TrainsOnCourses { get; set; }
        }
    
然后,需要修改Trainer模型,添加导航属性,并保存在列表框中选择的集合项。
        public class Trainer
        {
            public int TrainerId { get; set; }
            public string Name { get; set; }
            // 导航属性
            public virtual ICollection<TrainsOnCourse> TrainsOnCourses { get; set; }
        }
    
完成模型的修改后,需要再次构建解决方案,并执行“Add-Migration”命令,以便在数据库中添加TrainsOnCourse表。
        Add-Migration AddTrainsOnCourseTable
    
更新数据库,运行迁移文件。
        update-database
    
此时,打开SQL Server,应该可以看到TrainsOnCourse表已经被创建,并且包含两个外键。
接下来,需要添加一个新的控制器“Trainer”。在控制器中,需要选择Trainer.cs模型和DNSCContext。
然后,需要修改Create Action方法,以便从数据库中填充课程表的多选列表值。
        public ActionResult Create()
        {
            ViewBag.CourseId = new SelectList(db.Courses, "CourseId", "Title");
            return View();
        }
    
在Trainer文件夹中的Create.cshtml视图页面中,需要添加一个ListBoxControl。
        <select id="CourseId" name="CourseId" multiple="multiple">
            <option value="1">课程1</option>
            <option value="2">课程2</option>
            <option value="3">课程3</option>
        </select>
    
运行应用程序,并导航到“Trainer/Create”Action方法,通过在URL中输入相应的路径。应该能够看到一个包含一组值的ListBox。
接下来,需要修改HTTPPost Create Action方法,以便保存选定的项到数据库。
        [HttpPost]
        public ActionResult Create(Trainer trainer, List<int> CourseIds)
        {
            if (ModelState.IsValid)
            {
                db.Trainers.Add(trainer);
                db.SaveChanges();
                foreach (var courseId in CourseIds)
                {
                    var trainsOnCourse = new TrainsOnCourse
                    {
                        TrainerId = trainer.TrainerId,
                        CourseId = courseId
                    };
                    db.TrainsOnCourses.Add(trainsOnCourse);
                }
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            return View(trainer);
        }
    
然后,需要修改Trainer控制器中的Edit Action方法,以便处理ListBox控件。
在Trainer文件夹中的Edit.cshtml视图页面中,需要添加一个ListBoxControl。
        <select id="CourseId" name="CourseId" multiple="multiple">
            <option value="1">课程1</option>
            <option value="2">课程2</option>
            <option value="3">课程3</option>
        </select>
    
打开HTTPPost Edit Action方法的Trainer控制器,并执行所需的操作。
        [HttpPost]
        public ActionResult Edit(int id, List<int> CourseIds)
        {
            var trainer = db.Trainers.Find(id);
            if (trainer == null)
            {
                return HttpNotFound();
            }
            trainer.Name = Request.Form["Name"];
            db.Entry(trainer).State = EntityState.Modified;
            var existingCourses = db.TrainsOnCourses.Where(toc => toc.TrainerId == id).ToList();
            foreach (var course in existingCourses)
            {
                if (!CourseIds.Contains(course.CourseId))
                {
                    db.TrainsOnCourses.Remove(course);
                }
            }
            foreach (var courseId in CourseIds)
            {
                var trainsOnCourse = existingCourses.FirstOrDefault(toc => toc.CourseId == courseId);
                if (trainsOnCourse == null)
                {
                    trainsOnCourse = new TrainsOnCourse
                    {
                        TrainerId = id,
                        CourseId = courseId
                    };
                    db.TrainsOnCourses.Add(trainsOnCourse);
                }
            }
            db.SaveChanges();
            return RedirectToAction("Index");
        }