EF Core:如何访问一对多关联中多方自动生成的外键字段
问题
我有一个简单数据库,包含Instructor表(一方)和Course表(多方)。讲师可以是课程的作者或编辑。正在搭建一个编辑讲师的视图,其中包含带复选框的课程列表,用于勾选该讲师所编写和编辑的课程。
设置的关联在Course表中生成了两个外键:AuthorId和EditorId,但这些字段并未在Course模型中定义,是EF通过迁移自动创建的。需要在判断语句中比较Instructor.Id与Courses.AuthorId,判断该讲师是否为课程作者,从而设置复选框选中状态,EditorId同理。
模型类
public class Course { public int Id { get; set; } [DisplayName("Course")] public string CourseName { get; set; } public Instructor? Author { get; set; } public Instructor? Editor { get; set; } } public class Instructor { public int Id { get; set; } [DisplayName("Instructor")] public string InstructorName { get; set; } [ForeignKey("AuthorId")] [DisplayName("Author Of")] public ICollection<Course> CoursesAuthored { get; set; } = new List<Course>(); [ForeignKey("EditorId")] [DisplayName("Editor Of")] public List<Course> CoursesEdited { get; set; } = new List<Course>(); }
视图模型
public class EditInstructorCourseViewModel { public string CourseId { get; set; } public string CourseName { get; set; } public string CourseAuthor { get; set; } public string CourseEditor { get; set; } public bool IsSelected { get; set; } // 可能需要IsEditor和IsAuthor字段 }
Fluent API配置
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Course>() .HasOne(c => c.Editor) .WithMany(i => i.CoursesEdited); modelBuilder.Entity<Course>() .HasOne(c => c.Author) .WithMany(i => i.CoursesAuthored); }
数据库的Courses表生成列:
Id CourseName AuthorId EditorId
控制器GET编辑方法
public async Task<IActionResult> EditInstructorCourse(int? id) { var instructor = _context.Instructors .Where(c => c.Id == id).ToList(); var courses = await _context.Courses .ToListAsync(); ViewData["InstructorId"] = id; ViewData["InstructorName"] = instructor[0].InstructorName; var model = new List<EditInstructorCourseViewModel>(); foreach (var course in courses) { var editInstructorCourseViewModel = new EditInstructorCourseViewModel { CourseId = course.Id.ToString(), CourseName = course.CourseName }; // 需要判断course.AuthorId是否等于讲师id,设置选中状态 // EditorId同理,可能需要视图模型中的IsEditor和IsAuthor字段 if (id == course.) // 无法访问AuthorId字段 { editInstructorCourseViewModel.IsSelected = true; } else { editInstructorCourseViewModel.IsSelected = false; } model.Add(editInstructorCourseViewModel); } return View(model); }
使用点标记访问Course类时,智能提示不显示AuthorId字段,因为模型中没有该属性,请问如何实现需求?
解决方案
方法1:显式添加外键属性到Course模型
这是最直接的方式,将EF自动生成的外键字段显式添加到Course类中,即可直接访问:
修改Course模型:
public class Course { public int Id { get; set; } [DisplayName("Course")] public string CourseName { get; set; } // 显式添加外键属性 public int? AuthorId { get; set; } public int? EditorId { get; set; } public Instructor? Author { get; set; } public Instructor? Editor { get; set; } }
修改视图模型,增加区分作者/编辑的字段:
public class EditInstructorCourseViewModel { public string CourseId { get; set; } public string CourseName { get; set; } public string CourseAuthor { get; set; } public string CourseEditor { get; set; } public bool IsAuthor { get; set; } public bool IsEditor { get; set; } }
控制器中修改判断逻辑:
foreach (var course in courses) { var vm = new EditInstructorCourseViewModel { CourseId = course.Id.ToString(), CourseName = course.CourseName, IsAuthor = id == course.AuthorId, IsEditor = id == course.EditorId }; model.Add(vm); }
方法2:通过导航属性判断(需提前加载关联数据)
如果不想修改Course模型,可以通过导航属性的Id判断,但需确保EF提前加载关联数据,避免延迟加载导致额外数据库查询:
修改控制器中课程查询代码,Include导航属性:
var courses = await _context.Courses .Include(c => c.Author) .Include(c => c.Editor) .ToListAsync();
控制器中判断逻辑:
foreach (var course in courses) { var vm = new EditInstructorCourseViewModel { CourseId = course.Id.ToString(), CourseName = course.CourseName, IsAuthor = course.Author?.Id == id, IsEditor = course.Editor?.Id == id }; model.Add(vm); }
方法3:利用讲师的关联集合判断
先获取当前讲师关联的所有课程ID,再与每个课程对比:
修改控制器中讲师查询代码,Include关联集合:
var instructor = await _context.Instructors .Where(i => i.Id == id) .Include(i => i.CoursesAuthored) .Include(i => i.CoursesEdited) .FirstOrDefaultAsync(); if (instructor == null) { return NotFound(); } var authoredCourseIds = instructor.CoursesAuthored.Select(c => c.Id).ToList(); var editedCourseIds = instructor.CoursesEdited.Select(c => c.Id).ToList();
控制器中判断逻辑:
foreach (var course in courses) { var vm = new EditInstructorCourseViewModel { CourseId = course.Id.ToString(), CourseName = course.CourseName, IsAuthor = authoredCourseIds.Contains(course.Id), IsEditor = editedCourseIds.Contains(course.Id) }; model.Add(vm); }
视图复选框示例
在视图中根据IsAuthor和IsEditor渲染对应的复选框:
@model List<EditInstructorCourseViewModel> <h1>编辑讲师课程关联</h1> <form asp-action="EditInstructorCourse" method="post"> @foreach (var item in Model) { <div class="mb-2"> <input type="checkbox" name="AuthoredCourses" value="@item.CourseId" checked="@item.IsAuthor" /> <label>@item.CourseName(作者)</label> <input type="checkbox" name="EditedCourses" value="@item.CourseId" checked="@item.IsEditor" class="ms-3" /> <label>@item.CourseName(编辑)</label> </div> } <button type="submit" class="btn btn-primary">保存</button> </form>
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

