Entity Framework LINQ与值或null的比较

3
我有以下EF linq查询,用于获取所有员工或特定员工(如果empId具有值)。
但是EF没有生成预期的查询,并且它始终忽略OR条件。
from employee 
where employee.DepartmentId == depId && ((employee.Id == empId) || (employee.Id == null))
.ToList()

期望查询

SELECT * FROM Employee
WHERE DepartmentId = @DepId AND (Id=@empId OR Id IS NULL)

传递值时EF生成的查询

SELECT * FROM Employee
WHERE DepartmentId = @DepId AND (Id=@empId)

当值为空时,EF生成的查询

SELECT * FROM Employee
WHERE DepartmentId = @DepId AND (Id IS NULL)

注意:没有ID值为空的员工记录,而是返回0而不是所有员工记录

如何编写与此Id=@empId OR Id IS NULL相对应的linq代码?


你期望的查询只返回匹配的ID或者那些为NULL的ID(根据你在“注意事项”中所说的是不可能的)。那么你实际上想要什么呢?我猜你想要在值为null时绕过检查,但这与你的SQL查询所做的是不同的。 - Tim Schmelter
你的Employee表中有任何Idnull的行对我来说似乎很奇怪。这不是该表的主键吗?如果不是,你可能需要考虑重新命名它。 - DavidG
Id是一个Id,所以它不能为null,我非常确定你的模型将其设置为不可为空public int Id {get; set; },这就是为什么EF生成了那个查询。 - Gianpiero
@DavidG 没有空值的数值。通常我会使用SQL来过滤特定数据或所有数据,使用(Column=@value OR Column IS NULL)的语法。我尝试了同样的方法在EF中,但对我来说没有起作用。 - Developer
2个回答

6

您说这是您预期的查询:

SELECT * FROM Employee
WHERE DepartmentId = @DepId AND (Id=@empId OR Id IS NULL)

但我很确定这不是问题,因为Id从来不会为空(你在Note中也提到过),因为它是该表的主键。你实际上想要的查询是:

SELECT * FROM Employee
WHERE DepartmentId = @DepId AND (Id=@empId OR @empId IS NULL)

如果参数为NULL,您希望绕过检查并返回所有记录。请注意,从性能角度来看,这不是最佳方法。当您不想按Id进行筛选时,应使用没有筛选器的查询。恐怕这将无法产生最有效的查询计划。我建议使用以下查询:

IQueryable<Employee> allDepartmentEmployees = 
    from employee in ...
    where employee.DepartmentId == depId;
    select employee;

if(empId.HasValue) // presuming it's a nullable type
{
    allDepartmentEmployees = allDepartmentEmployees.Where(e => e.Id == empId.Value);     
}

List<Employee> employeeList = allDepartmentEmployees.ToList();

所以只有在给定参数的情况下才进行过滤。这样将只返回一条记录。

谢谢,看起来很不错,我现在正在尝试。实际上,我通过一个表的示例简化了我的问题。实际情况是,我连接了多个表,并且在where条件中需要应用此额外的过滤器。让我试试你的代码,看看EF如何应用where条件。 - Developer

0

LINQ to SQL 的翻译简化了您的查询逻辑。它们在功能上是等效的。

您不应该尝试以某种方式编写 LINQ,使其生成您期望的特定 SQL。您正在编写 LINQ 来执行特定操作。如果生成的查询与您的期望不符,请尝试理解原因。

当您的比较为 (Id=@empId OR Id IS NULL)

  • 如果 @empId 始终为 NULL,则 (Id IS NULL) 是一个功能等效的简化
  • 如果 @empId 是一个值或可能为空,则 (Id=@empId) 是一个功能等效的简化

您没有说明使用 Entity Framework 时使用哪个 DB / DB 驱动程序,但您可以验证与 NULL 进行比较始终为 false:

SELECT CASE WHEN NULL = NULL THEN 1 ELSE 0 END

这个查询在 MS SQL Server 中返回 0。因此,NULL 不等于 NULL。

数据库引擎通常会以与 C# 的 null 处理略有不同的方式来解释和处理 NULL。NULL 是“未知”的,而不是“未设置”的。在 MS SQL Server 中,使用 IS NULL 来与 NULL 进行比较,而不是使用 =!=<>

对于 MS SQL Server,请参见 NULL 和 UNKNOWN


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接