EF Core 3.0 - 将SQL转换为LINQ

3
这篇博客中给出的示例具有以下特点:
from e in s.StudentCourseEnrollments where courseIDs.Contains(e.Course.CourseID) select e 

当我们需要查找一个完全匹配时,包含逻辑将不起作用。如果学生已经选修了6门课程(例如:1、2、3、4、5、6),而请求列表中包含5(例如:1、2、3、4、5),则查询将返回匹配,但实际上不应该如此。当学生选择了请求列表的子集时,另一种方法可以很好地运行。
以下解决方案可行,但需要帮助将下面的SQL转换为LINQ(EF Core 3.0)?
Create TABLE dbo.Enrollments (StudentId INT NOT NULL, CourseId INT NOT NULL)
insert into dbo.Enrollments values (1,1)
insert into dbo.Enrollments values (1,2)
insert into dbo.Enrollments values (1,3)
insert into dbo.Enrollments values (1,4)
insert into dbo.Enrollments values (1,5)
insert into dbo.Enrollments values (1,6)

DECLARE @TempCourses TABLE
(
   CourseId INT
);

INSERT INTO @TempCourses (CourseId) VALUES (1), (2), (3),(4),(5);

SELECT t.StudentId
FROM
(
  SELECT StudentId, cnt=COUNT(*)
  FROM dbo.Enrollments
  GROUP BY StudentId
) kc
INNER JOIN
(
  SELECT cnt=COUNT(*)
  FROM @TempCourses
) nc ON nc.cnt = kc.cnt
JOIN dbo.Enrollments t ON t.StudentId = kc.StudentId
JOIN @TempCourses n ON n.CourseId = t.CourseId
GROUP BY t.StudentId
HAVING COUNT(*) = MIN(nc.cnt);

drop table dbo.Enrollments

db<>Fiddle

2个回答

1
我不知道SQL查询的情况,但是EF Core 3.0的LINQ查询可以像这样完成相同的任务:
var matchIds = new[] { 1, 2, 3, 4, 5 }.AsEnumerable();
var query = dbContext.Students
    .Where(s => s.Enrollments.All(e => matchIds.Contains(e.CourseId)) 
        && s.Enrollments.Count() == matchIds.Count());

主要匹配工作是通过All子查询完成的。不幸的是,当相关链接记录多于匹配ID时,这还不够,因此需要进行额外的计数比较来解决这个问题。

这里不需要使用AsEnumerable()。 - JohnyL
@JohnyL 这是为了表明这不需要特殊的集合类型(数组、列表等)来存放ID - 任何可枚举的类型都可以。 - Ivan Stoev
很好,它能正常工作...但只需要做几个小改动...新的int []和ToList()。 - sarvpk

0

你可以通过以下简单的方式实现它,现场演示在这里

假设你已经按照这种方式获取了报名列表

var enrollments  = from s in dc.Students
                   from c in s.Courses
                   select new { StudentID = s.StudentID, CourseID = c.CourseID };

然后通过这种方式获取结果

    var groupedEnrollment = enrollments.GroupBy(p => p.StudentId)
                                        .Select(g => new 
                                        {
                                            StudentId = g.Key,
                                            Courses = g.Select(p => p.CourseId).ToArray() 
                                        });
    var result = groupedEnrollment.Where(g => 
                                         g.Courses.Length == courses.Length && 
                                         g.Courses.Intersect(courses).Count() == courses.Length);

你根本没有使用Enrollments表。尝试了你的解决方案,出现了LINQ错误。@Ivan的解决方案非常好。我接受了他/她的答案。 - sarvpk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接