Репликация запроса SQL в LINQ - PullRequest
1 голос
/ 22 марта 2011

У меня есть приложение ASP.NET MVC, которое я уже некоторое время использую с LINQ to SQL. У меня есть навык репликации большинства запросов в LINQ, но есть один, который поставил меня в тупик на несколько дней.

Я пытаюсь выбрать список «Прогрессий», где выполняется условие, и у меня есть список групп.

Мой ERD выглядит следующим образом:

«Группа» 1 <-> Много «Зачислений» Много <-> 1 «Студентов» 1 <-> Много «Прогрессий»

И стандартный SQL будет (за исключением того, что в коде у меня есть определенный набор групп, переданных в функцию):

SELECT     dbo.[Group].GroupID, COUNT(*) AS returning
FROM         dbo.[Group] INNER JOIN  
dbo.Enrolment ON dbo.[Group].CourseID = dbo.Enrolment.GroupID INNER JOIN    
dbo.Student ON dbo.Enrolment.StudentID = dbo.Student.StudentID INNER JOIN  
dbo.Progression ON dbo.Student.StudentID = dbo.Progression.StudentID  
WHERE     (dbo.Progression.IsReturning = 0)  
GROUP BY dbo.[Group].GroupID 

Теперь для веб-приложения. ASP-представление «Progression» получает переменную «groups», которая представляет собой список нескольких выбранных групп. В настоящее время я использую следующий код, который очень медленный (30 секунд или более для загрузки страницы)

<%foreach (var tg in Model)  
      {%>  
        <% notreturning = 0; %>  


        <%foreach (Enrolment e in tg.Enrolments)  
                  {  
                   notreturning = notreturning + e.Student.Progressions.Where(p => !p.IsReturning).Count();  

                  }%>    
        <tr>  
            <td><% = notreturning %></td>
        </tr>       
      <%   
      } %>  

Я тоже считаю кое-что, но в этом примере я остановлюсь на одном. Теперь очевидно, что это довольно медленно, потому что он должен делать foreach для групп, а затем для каждого зачисления в группу, так что около 10 групп по 20 студентов в каждой. Я действительно хочу сделать что-то вроде следующего, которое устраняет второй foreach:

<%foreach (var tg in Model)  
      {%>  
        <% notreturning = 0; %>  

         <%var test = tg.Enrolments.Where(e => e.Student.Progressions.Where(p => !p.IsReturning)).Count(); %>

        <tr>  
            <td><% = notreturning %></td>
        </tr>       
      <%   
      } %>  

Этот код не работает как вложенный оператор where, который не возвращает тип данных bool, но я надеюсь, что он перебирает то, что я пытаюсь сделать здесь.

Я не уверен, хорошо ли я объяснил это, но если у кого-то есть какие-либо идеи, я был бы очень благодарен, это беспокоило меня в течение многих дней!

Ответы [ 2 ]

2 голосов
/ 22 марта 2011

Этот запрос LINQ будет делать то, что вы выразили в комментариях:

var groups =
    from g in db.Groups
    let returningStudents =
        from enrolment in g.Enrolments
        let student = enrolment.Student
        where student.Progressions.Any(p => p.IsReturning)
        select student
    select new GroupStudentReturnCountDto
    {
        Name = g.Name,
        StudentReturnCount = returningStudents.Count()
    };

Этот запрос будет очень эффективным, поскольку он позволяет базе данных выполнять подсчет и возвращает только те данные, которые фактически используются.Если это все еще не достаточно быстро, просто добавьте правильные индексы баз данных, и все готово; -)

2 голосов
/ 22 марта 2011

Буквальное преобразование вашего SQL выглядит примерно так:

from g in db.Groups
join e in db.Enrolments on g.CourseID equals e.GroupID
join s in db.Students in e.StudentID equals s.StudentID
join p in db.Progressions on s.StudentID equals p.StudentID  
where p.IsReturning == 0  
GROUP new {
   Group = g,
   Enrolment = e,
   Student = s,
   Progression = p
} by g.GroupID into grouped 
select new
{
   GroupId = grouped.Key,
   Returning = grouped.Count()
};

хотя g.CourseID equals e.GroupID выглядит немного странно!


Кроме того, если вашей конечной целью является выбор списка Progressions, то я считаю, что проще всего начинать запрос с Progressions в качестве первой выбранной вещи, а не с групп.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...