Search code examples
c#entity-frameworklinqentity-framework-6

Entity framework LINQ with value OR null


I have the following EF linq query to get all the employess or specific employee, in case if empId has value.

But the EF is not generating the expected query and it ignores OR condition always

from employee 
where employee.DepartmentId == depId && ((employee.Id == empId) || (employee.Id == null))
.ToList()

Expected Query

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

Generated Query by EF when value is passed

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

Generated Query by EF when value is null

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

Note: No Employee record has Id value NULL and it returns 0 instead of all employees

How to write linq for this Id=@empId OR Id IS NULL ?


Solution

  • You say this is your expected query:

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

    but i'm pretty sure that it is not, because the Id is never null (what you also say in your Note) because it is the primary key of that table. You actually mean this query:

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

    so you want to bypass the check and return all records if the parameter is NULL. Note that this is not the best way performance wise. You should use a query without filter when you don't want to filter by Id. I'm afraid this will not produce the most efficient query plan. I'd use this:

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

    So only filter if the parameter is given. Then this will only return one record.