如何在Entity Framework中查询未修完必修课程的学生
解决方案
一、先修正代码里的低级错误
你原代码里的判断逻辑和变量引用全错了:
x.Student.ID.Equals(c.ID)应该是x.Student.ID.Equals(s.ID),你把学生ID和课程ID搞混了dict.Add(r.Name, c)里的r和c都是无意义的变量,正确应该是添加课程名称和对应的学生,比如dict.Add(c.Name, s)- 另外你的需求是未修必修课程的学生,原代码没过滤必修课程,会把所有课程都算进去
二、优化性能解决卡顿问题
嵌套循环+每次调用Any遍历整个actions集合,时间复杂度是O(NMK),数据量稍微大一点必然卡顿。换个思路:先把已修记录预处理成哈希映射,之后查找就是O(1):
// 1. 先筛选出所有必修课程 var requiredCourses = Courses.Where(c => c.Required).ToList(); // 2. 预处理已修课程的学生ID集合:课程ID → 修过该课的学生ID集合 var attendedMap = actions .GroupBy(a => a.CourseId) .ToDictionary( group => group.Key, group => new HashSet<Guid>(group.Select(a => a.StudentId)) ); // 3. 构建结果字典(注意:原需求的Dictionary<string, Student>不合理,一个课程会有多个未修学生,这里改成Dictionary<string, List<Student>>,如果确实要单个学生请自行调整) var result = new Dictionary<string, List<Student>>(); foreach (var course in requiredCourses) { // 获取修过当前课程的学生ID集合,没有的话就是空集合 attendedMap.TryGetValue(course.ID, out var attendedStudentIds); attendedStudentIds ??= new HashSet<Guid>(); // 筛选出未修该课程的学生 var notAttendedStudents = Students.Where(s => !attendedStudentIds.Contains(s.ID)).ToList(); result.Add(course.Name, notAttendedStudents); }
三、修正EF多对多关联配置
你的Action类缺少外键属性,EF无法正确识别关联关系,也没法生成数据库索引,这会导致查询actions时效率极低。修改Action类并配置关联:
1. 修改Action实体类
public class Action: IBaseEntity { [Key] public Guid ID { get; set; } // 添加外键属性(必须) public Guid StudentId { get; set; } public Student Student { get; set; } public Guid CourseId { get; set; } public Course Course { get; set; } public DateTime AttendedDate { get; set; } // removed additional fields for brevity }
2. 在DbContext中配置关联(Fluent API方式)
protected override void OnModelCreating(ModelBuilder modelBuilder) { // 配置Action与Student的关联 modelBuilder.Entity<Action>() .HasOne(a => a.Student) .WithMany() // 如果Student类里有Actions集合,就改成.WithMany(s => s.Actions) .HasForeignKey(a => a.StudentId) .OnDelete(DeleteBehavior.Cascade); // 配置Action与Course的关联 modelBuilder.Entity<Action>() .HasOne(a => a.Course) .WithMany() // 如果Course类里有Actions集合,就改成.WithMany(c => c.Actions) .HasForeignKey(a => a.CourseId) .OnDelete(DeleteBehavior.Cascade); }
这样EF会为外键字段生成索引,查询actions的速度会大幅提升。
内容的提问来源于stack exchange,提问作者RAAPereira
相关产品推荐
相关产品推荐

