EF Core 3.0 - 将 SQL 转换为 LINQ
EF Core 3.0 - Convert SQL to LINQ
the blog中给出的例子有以下
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),查询将 return一场不应该的比赛。当学生注册了所请求列表的子集时,另一种方法效果很好。
以下解决方案有效但需要帮助将以下 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
我不知道 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
子查询完成的。不幸的是,当相关的 link 记录多于匹配的 id 时,这还不够,所以额外的计数比较解决了这个问题。
你可以通过这样一个简单的方法实现它,live demo here
假设您通过这种方式获得了注册列表
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);
the blog中给出的例子有以下
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),查询将 return一场不应该的比赛。当学生注册了所请求列表的子集时,另一种方法效果很好。
以下解决方案有效但需要帮助将以下 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
我不知道 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
子查询完成的。不幸的是,当相关的 link 记录多于匹配的 id 时,这还不够,所以额外的计数比较解决了这个问题。
你可以通过这样一个简单的方法实现它,live demo here
假设您通过这种方式获得了注册列表
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);