EF Core 3.0 - Convert SQL to LINQ

て烟熏妆下的殇ゞ 提交于 2021-01-27 10:48:29

问题


The example given in the blog has the following

from e in s.StudentCourseEnrollments where courseIDs.Contains(e.Course.CourseID) select e 

The contains logic will not work when we are looking for an exact match. If a student has enrolled for 6 courses (ex : 1,2,3,4,5,6) and the requested list contains 5 (ex: 1,2,3,4,5) the query will return a match when it should not. The other way works well when the student has enrolled in a subset of the requested list.

Below solution works but need help to convert the below sql to 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


回答1:


I don't know about the SQL query, but the EF Core 3.0 LINQ query for the same task is something like this:

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());

The main matching job is done with All subquery. Unfortunately that's not enough for the case when related link records are more than the matching ids, so additional counts comparison solves that.




回答2:


You can achieve it with a simple way like this, live demo here

Let's say that you've got the list of enrollments by this way

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

Then get the result by this way

    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);


来源:https://stackoverflow.com/questions/59621091/ef-core-3-0-convert-sql-to-linq

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!