如何通过Entity Framework同时向3张关联表提交数据?
解决Entity Framework同时提交关联表数据的问题
看起来你已经搭好了基础的视图和控制器逻辑,现在只需要完善视图的工作日选择,以及编写POST提交的逻辑来关联三个表的数据。下面一步步来帮你搞定:
1. 修正视图绑定并添加工作日选择项
你的视图目前缺少WeekDay的选择模块,而且Teacher的绑定逻辑有点小问题(应该直接绑定到TeacherId字段,而不是Teacher.Id)。更新后的Create视图代码如下:
<div class="form-horizontal"> <h4>Appointment</h4> <hr /> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) <div class="form-group"> @Html.LabelFor(model => model.TeacherId, "Teacher Name", htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> <!-- 修正绑定目标为Appointment.TeacherId字段 --> @Html.DropDownListFor(m => m.TeacherId, (List<SelectListItem>)ViewBag.TeacherId, "Select a teacher", new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.TeacherId, "", new { @class = "text-danger" }) </div> </div> <!-- 新增工作日选择下拉框 --> <div class="form-group"> @Html.Label("WeekDayId", "Week Day", htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.DropDownList("WeekDayId", (List<SelectListItem>)ViewBag.DayId, "Select a weekday", new { @class = "form-control" }) @Html.ValidationMessage("WeekDayId", "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Hours,"Working Hour", htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Hours, new { htmlAttributes = new { @class = "form-control", placeholder = "e.g. 09:00 - 17:00" } }) @Html.ValidationMessageFor(model => model.Hours, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Create" class="btn btn-default" /> </div> </div> </div>
这里的核心调整:
- 将教师下拉框直接绑定到
Appointment.TeacherId,让模型绑定能直接获取选中的教师ID - 添加工作日选择模块,用
WeekDayId作为表单字段名,后续在POST方法中单独接收
2. 编写POST版Create方法处理数据提交
现在需要实现提交逻辑,接收表单数据后关联Teacher和WeekDay,最终保存到数据库。注意因为Appointment和WeekDay是多对多关系,我们需要从数据库中获取已存在的实体来建立关联,避免EF误创建新的工作日/教师记录:
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Create(Appointment appointment, int WeekDayId) { if (ModelState.IsValid) { // 1. 获取数据库中已存在的教师实体,建立关联 var targetTeacher = db.Teachers.Find(appointment.TeacherId); appointment.Teacher = targetTeacher; // 2. 获取选中的工作日实体,添加到Appointment的关联集合中 var targetWeekDay = db.WeekDays.Find(WeekDayId); appointment.WeekDays.Add(targetWeekDay); // 3. 将Appointment存入数据库并保存所有变更 db.Appointments.Add(appointment); db.SaveChanges(); return RedirectToAction("Index"); } // 验证失败时,重新填充下拉列表并返回视图 var myTeacherList = (from teacher in db.Teachers.ToList() select new SelectListItem { Text = teacher.Firstname + " " + teacher.Lastname, // 增加空格优化显示 Value = teacher.Id.ToString(), }).ToList(); var myDayNameList = (from day in db.WeekDays.ToList() select new SelectListItem { Text = day.Name, Value = day.Id.ToString(), }).ToList(); ViewBag.TeacherId = myTeacherList; ViewBag.DayId = myDayNameList; return View(appointment); }
关键逻辑说明:
- 通过
WeekDayId参数接收选中的工作日ID(因为Appointment实体没有直接的WeekDayId字段,所以单独作为参数接收) - 使用
Find()方法获取数据库中已存在的实体,确保EF只建立关联,不会重复插入教师/工作日数据 - 将获取到的WeekDay添加到
Appointment.WeekDays集合,EF会自动维护多对多的中间表记录
3. 可选:添加模型验证增强用户体验
为了确保输入合法性,可以在Appointment实体的属性上添加验证特性:
public partial class Appointment { // ... 原有代码 ... [Required(ErrorMessage = "Please select a teacher")] public int TeacherId { get; set; } [Required(ErrorMessage = "Please enter working hours")] [Display(Name = "Working Hours")] public string Hours { get; set; } // ... 原有代码 ... }
这样用户未选择教师或未输入工作时长时,页面会显示对应的错误提示。
测试你的示例场景
按照你给出的例子:
- 选择John Reese + 周五 + 09:00-17:00提交后,EF会:
- 创建一条Appointment记录,关联John的TeacherId,存入输入的工作时长
- 在Appointment与WeekDay的中间表中添加关联记录,绑定这条新Appointment和周五的WeekDay
- Harold Finch + 周一 + 11:00-15:00的记录也会被正确创建和关联
内容的提问来源于stack exchange,提问作者agahpars
相关产品推荐
相关产品推荐

