在 LINQ 中复制 SQL 查询

发布于 2024-10-26 06:19:38 字数 1894 浏览 2 评论 0原文

我有一个 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 

现在是 Web 应用程序。 ASP 视图“进度”传递变量“组”,它是几个选定组的列表。我目前正在使用以下代码,该代码非常慢(加载页面需要 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,然后对组中的每个注册进行 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 数据类型,但我希望它能完成我在这里尝试做的事情。

我不确定我是否解释得很好,但如果有人有任何想法,我将非常感激,这已经困扰我好几天了!

I have an ASP.NET MVC application which I have being using with LINQ to SQL for a while now. I have got the hang of replicating most queries in LINQ but there is one that has had me stumped for several days now.

I am trying to select a list of "Progressions" where a condition is met, and I have a list of groups.

My ERD is as follows:

"Group" 1<->Many "Enrolments" Many<->1 "Students" 1<->Many "Progressions"

And the standard SQL would be (Except in the code I have a specific set of groups passed to the function):

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 

Now for the Web App. The ASP view "Progression" gets passed the varibale "groups" which is a list of a few selected groups. I am currently using the follwing code, which is very slow (30 secs or more to load page)

<%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>       
      <%   
      } %>  

I am counting some other stuff too but for this example I'll stick to one. Now obviously this is quite slow because it has to do a foreach for groups, then for each enrolment in the group, so around 10 groups times 20 students in each. I deally I want to do something like the following which eliminates the second 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>       
      <%   
      } %>  

That code doesn't work as the nested where clause doesn't return a bool data type, but I hope it get accross what I'm trying to do here.

I'm not sure if I've explained this very well but if anyone has any ideas I would be very grateful, this has been bugging me for days!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

疾风者 2024-11-02 06:19:38

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 看起来有点奇怪!


顺便说一句,如果您的最终目标是选择进度列表,那么我发现最简单的方法是使用进度作为第一个选择的内容而不是使用组来启动查询。

A literal conversion of your SQL is something like:

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

although g.CourseID equals e.GroupID looks a bit odd!


As an aside, if your end goal is to select a list of Progressions, then I find it easiest to start the query with the Progressions as the first thing being selected rather than with the Groups.

似梦非梦 2024-11-02 06:19:38

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

此查询将非常高效,因为它让数据库进行计数,并且仅返回实际使用的数据。如果它仍然不够快,只需添加正确的数据库索引即可完成;-)

This LINQ query would do what you expressed in the comments:

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

This query would be very efficient, because it lets the database do the counting and it returns only the data that is actually used. If it still isn't fast enough, just add the right databases indexes and you're done ;-)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文