使用 LINQ 的左外部联接 -- 理解代码

本文关键字:代码 LINQ 外部 使用 | 更新日期: 2023-09-27 18:31:32

如果有人能在使用 LINQ 时解释术语into的含义,我将不胜感激。一般来说,我试图了解如何在 C# 中进行连接、左外部连接等。

我有一个主表Students它存储了一些外部 ID 键,然后在运行查询时用它们的名称替换这些键。名称是从查找表中读取的,例如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;

在阅读了大量文章并观看了一些视频后,我不知何故设法使下面的代码正常工作,但我觉得我对代码没有完全的理解。让我感到困惑的部分是在以 into 结尾的第 5 行,然后在以 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 --"
             };

使用 LINQ 的左外部联接 -- 理解代码

我相信"如何:执行左外部联接 MSDN"页面中的示例部分得到了很好的解释。让我们将其投影到您的示例中。引用页面中的第一段

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

因此,在您的情况下,第一步是执行Students对象列表与基于MarkID对象匹配Marks对象中的MarkID Marks对象列表的内部联接Students对象。从报价中可以看出,内部联接是使用组联接执行的。如果检查 MSDN 页面中有关如何执行组加入Note部分,则可以看到

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

在您的

示例上下文中,这意味着通过使用into,您可以获得group joined结果,其中您拥有所有Students对象,以及Marks对象的相关元素序列(如果没有匹配Marks对象,则序列将为空)。

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

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

同样,为了将其投影到您的示例中,将在每个匹配Marks对象序列上调用DefaultIsEmpty()。如上所述,如果任何Student对象的匹配Marks对象的序列为空,该方法将返回一个包含单个默认值的集合,这可确保每个Student对象都将在生成的集合中表示。结果,您拥有的是一组元素,其中包含所有Student对象,并且Marks对象匹配,或者如果没有匹配Marks对象,则默认值为 Marks ,在本例中为 null

我可以

说的是,"into MarksGroup"将连接表的结果数据存储到临时(基于应用程序,而不是基于数据库)结果集中(用SQL术语来说:一个表,所以它是一个SELECT INTO

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

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

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

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"的第二个问题:这也应该在没有临时结果集"标记组"的情况下显示不同的行为