【问题标题】:Left join using LINQ to SQL使用 LINQ to SQL 的左连接
【发布时间】:2016-05-25 13:49:23
【问题描述】:

我正在使用 Visual Studio 2015 针对 Entity Framework 6 和 SQL Server 2008 构建一个 WPF 应用程序。我有这两个表:

Employee
-----------------------------
EmployeeId
FirstName
LastName
... other columns

EmployeeStatus
-----------------------------
EmployeeStatusId
EmployeeId (Foreign Key to Employee.EmployeeId)
ValidEmployeeStatusId

应用程序需要获取所有EmployeeStatus.ValidEmployeeStatusId 不是 2 也不是 4 的员工(非活动和请假)。我已经编写了这个 LINQ 查询,但它永远运行并且永远不会返回任何结果:

var query = (from e in context.Employees
             from es in context.EmployeeStatus
                .Where(x => e.employeeID == x.employeeID 
                    && (x.validEmployeeStatusID != 2
                    && x.validEmployeeStatusID != 4)
                .DefaultIfEmpty()
             select new EmployeeViewModel
             {
                 EmployeeId = e.employeeID,
                 /* set other properties*/
             });
return await Task.Run(() => new 
    ObservableCollection<EmployeeViewModel>(query));

我做错了什么?

更新:找出是什么让我因缓慢而死...每个EmployeeViewModel 都在其ctor 中调用数据库以填充一些ObservableCollections。将这些属性变成static 并添加了static bool;如果为假,则填充属性并将布尔值设置为真。因此,所有实例都对调用数据库的那些属性使用相同的数据。对于大约 4000 条记录而言,调用次数非常多。

【问题讨论】:

  • 不太清楚你想达到什么目的。应用条件后的左连接将包括员工 have* ValidEmployeeStatusId 2 或 4。那么,如果 (A) 没有相关的 EmployeeStatus 记录 (B) 有相关的,查询应该返回什么EmployeeStatus 记录 ValidEmployeeStatusId == 2` (C) there is related `EmployeeStatus` record with ValidEmployeeStatusId == 4` (D) 否则?
  • 谢谢,@IvanStoev。如果员工有状态,我们希望排除状态为 2 和 4 的员工。但获取所有其他员工。
  • 所以每个员工记录只有一个状态记录?
  • 不,员工既可以是 2 也可以是 4。别问我,这是要求 :)
  • 请参阅上面的更新,了解为什么查询如此缓慢,下面提供的答案。

标签: c# .net sql-server entity-framework linq


【解决方案1】:

您可以通过左连接获得所需的结果。

var query = (from e in context.Employees
             join es in context.EmployeeStatus
               on e.employeeID equals es.employeeID into empStatuses
             from emps in empStatuses.DefaultIfEmpty()
             where emps.validEmployeeStatusID != 2
                && emps.validEmployeeStatusID != 4
             select new EmployeeViewModel
             {
                 EmployeeId = e.employeeID,
                 /* set other properties*/
             });

【讨论】:

  • 谢谢,@dotctor。我在上面的问题中更新了列名。让我试试你的解决方案,看看...
  • 我只得到一个结果,因为只有一名员工设置了状态。大多数员工没有身份;我也想把它们拿来。我该怎么做?
  • 要成为左连接,您需要from emps in empStatuses.DefaultIfEmpty()
  • 我需要DefaultIfEmpty() 来执行左连接吗?它仍然只返回一个结果。
  • 对不起。我忘了输入DefaultIfEmpty()。固定的。 @亚历克斯
【解决方案2】:

我认为您不需要执行join

试试这个查询

var query = (from e in context.Employees
             where e.EmployeeStatus.validEmployeeStatusID != 2 
           && e.EmployeeStatus.validEmployeeStatusID != 4
         select new EmployeeViewModel
         {
             EmployeeId = e.employeeID,
             /* set other properties*/
         });

【讨论】:

  • 它不会让我在e.EmployeeStatus上选择.validEmployeeStatusID
【解决方案3】:

您可以尝试基于 !Any 的 LINQ 查询,该查询应转换为 SQL NOT EXISTS 查询,IMO 是当今连接的一个很好的替代方案。它还避免了使用联接时发生的员工记录重复。

var query = (from e in context.Employees
             where !context.EmployeeStatus.Any(s => e.employeeID == s.employeeID 
                 && (s.validEmployeeStatusID == 2 || s.validEmployeeStatusID == 4))
             select new EmployeeViewModel
             {
                 EmployeeId = e.employeeID,
                 /* set other properties*/
             });

您也可以尝试以下联接(实际上是antijoin)版本的查询:

var query = (from e in context.Employees
             join s in context.EmployeeStatus
                 .Where(x => x.validEmployeeStatusID == 2 || x.validEmployeeStatusID == 4))
             on e.employeeID equals s.employeeID into statusGroup
             from s in statusGroup.DefaultIfEmpty()
             where s == null
             select new EmployeeViewModel
             {
                 EmployeeId = e.employeeID,
                 /* set other properties*/
             });

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-14
    • 2015-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多