繁体   English   中英

使用LINQ左外连接 - 理解代码

[英]Left outer join using LINQ — understanding the code

我将不胜感激,如果有人可以解释这个词的含义into同时使用LINQ。 一般来说,我试图了解如何在C#中进行INNER JOINLEFT OUTER JOIN等。

我有主表Students存储一些外国ID密钥,然后在运行查询时用它们的名称替换。 名称从Marks表中读取,例如MarksSoftwareVersionsDepartments等。所有字段都是必需的,但MarkID 我试图在LINQ中构建的查询是这样的:

SELECT * FROM dbo.Students
INNER JOIN dbo.Departments ON dbo.Students.DepartmentID=dbo.Departments.DepartmentID
INNER JOIN dbo.SoftwareVersions ON dbo.Students.SoftwareVersionID=dbo.SoftwareVersions.SoftwareVersionID
INNER JOIN dbo.Statuses ON dbo.Students.StatusID=dbo.Statuses.StatusID
LEFT JOIN dbo.Marks ON dbo.Students.MarkID=dbo.Marks.MarkID
WHERE dbo.Students.DepartmentID=17;

在阅读了大量文章和观看一些视频之后,我设法让下面的代码得到了解决,但我不觉得我对代码有完整的理解。 这让我困惑的是位在5日线与结尾into ,然后在第二天符合开头from m ... 我很困惑什么into不和和真正发生的事情from m ... 这是LINQ中的代码:

var result = from st in dbContext.Students where st.DepartmentID == 17
             join d in dbContext.Departments on st.DepartmentID equals d.DepartmentID
             join sv in dbContext.SoftwareVersions on st.SoftwareVersionID equals sv.SoftwareVersionID
             join stat in dbContext.Statuses on st.StatusID equals stat.StatusID
             join m in dbContext.Marks on st.MarkID equals m.MarkID into marksGroup
             from m in marksGroup.DefaultIfEmpty()
             select new
             {
                 student = st.StudentName,
                 department = p.DepartmentName,
                 software = sv.SoftwareVersionName,
                 status = st.StatusName,
                 marked = m != null ? m.MarkName : "-- Not marked --"
             };

我相信如何:执行左外连接MSDN页面的 示例部分真的很好解释。 让我们把它投射到你的例子中。 引用页面的第一段

生成两个集合的左外连接的第一步是使用组连接执行内连接。 (有关此过程的说明,请参见如何:执行内部联接(C#编程指南)。)在此示例中,Person对象列表基于与Pet.Owner匹配的Person对象内部连接到Pet对象列表。 。

所以你的情况,第一步是执行列表的内连接Students与列表对象Marks基于对象MarkIDStudents对象匹配MarkIDMarks物。 从引用中可以看出,内连接是使用组连接执行的。 如果您在MSDN页面中查看有关如何执行组加入的Note部分,您可以看到

无论是否在第二个集合中找到相关元素,第一个集合的每个元素都出现在组连接的结果集中。 在没有找到相关元素的情况下,该元素的相关元素序列是空的 因此,结果选择器可以访问第一个集合的每个元素。

这意味着在你的榜样的背景下,是通过使用intogroup joined的结果,你有所有Students的对象,和相关的元素序列Marks的情况下,物体(没有匹配的Marks物,序列是要是空的。

现在让我们回到How to: Perform Left Outer Joins MSDN page ,特别是第二段

第二步是将第一个(左)集合的每个元素包含在结果集中,即使该元素在右集合中没有匹配项也是如此。 这是通过在组连接的每个匹配元素序列上调用DefaultIfEmpty来实现的。 在此示例中,在匹配Pet对象的每个序列上调用DefaultIfEmpty。 如果任何Person对象的匹配Pet对象的序列为空,则该方法返回包含单个默认值的集合,从而确保在结果集合中表示每个Person对象。

再次,为了将此项目投射到您的示例中,将在匹配Marks对象的每个序列上调用DefaultIsEmpty() 如上所述,如果匹配Marks对象的序列对于任何Student对象为空,则该方法返回包含单个默认值的集合,这确保每个Student对象将在结果集合中表示。 正如你所设置元素的结果,包含所有Student对象,并匹配Marks的对象,或者如果没有匹配的Marks对象的默认值Marks ,在这种情况下是null

我可以说是“进入MarksGroup”将连接表的结果数据存储到临时(基于应用程序,而不是基于数据库)结果集中(以sql术语表示:一个表,所以它是一个SELECT INTO

在下一行中,您的代码然后从Marksgroup中选择包含您的数据的列(以sql术语: SELECT student, department, software, status, marked FROM Marksgroup

所以基本上,它是从数据库中获取数据,然后将其放在“Marksgroup”旁边,并在下一步中让Marksgroup回到您的手指中以取出您想要在c#代码中使用的数据。

尝试摆脱Marksgroup,它应该是可能的(没有测试过你的代码)。 它应该是这样的:

from st in dbContext.Students where st.DepartmentID == 17
             join d in dbContext.Departments on st.DepartmentID equals d.DepartmentID
             join sv in dbContext.SoftwareVersions on st.SoftwareVersionID equals sv.SoftwareVersionID
             join stat in dbContext.Statuses on st.StatusID equals stat.StatusID
             join m in dbContext.Marks on st.MarkID equals m.MarkID

             select new
             {
                 student = st.StudentName,
                 department = p.DepartmentName,
                 software = sv.SoftwareVersionName,
                 status = st.StatusName,
                 marked = m != null ? m.MarkName : "-- Not marked --"
             };

关于'm'的第二个问题:如果没有临时结果集“Marksgroup”,这也应该显示不同的行为

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM