EF Core 3.0 - конвертировать SQL в LINQ - PullRequest
3 голосов
/ 07 января 2020

Пример, приведенный в блоге , имеет следующее

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

Логик содержит c не будет работать, когда мы ищем точное совпадение. Если студент записался на 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 ]

0 голосов
/ 07 января 2020

Вы можете достичь этого простым способом, как это, живая демонстрация здесь

Допустим, у вас есть список зачислений таким образом

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);
0 голосов
/ 07 января 2020

Я не знаю о запросе 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 подзапрос. К сожалению, этого недостаточно для случая, когда связанных записей ссылок больше, чем совпадающих идентификаторов, так что дополнительное сравнение подсчетов решает эту проблему.

...