Reputation: 487
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
?
Upvotes: 3
Views: 6150
Reputation: 9217
The LINQ to SQL translation simplified your query logic. They are functionally equivalent.
You should not try to write LINQ in a way that it generates a specific SQL you expect. You are writing LINQ to do a specific operation. If the resulting query does not match your expectation, try to understand why.
When your comparison is (Id=@empId OR Id IS NULL)
@empId
is always NULL, then (Id IS NULL)
is a functionally equivalent simplification@empId
is a value or may be null then (Id=@empId)
is a functionally equivalent simplificationYou did not say which DB / DB driver you use with Entity Framework, but you can verify that comparing against NULL is always false:
SELECT CASE WHEN NULL = NULL THEN 1 ELSE 0 END
MS SQL Server returns 0
for this query. So NULL is not equal to NULL.
Database Engines typically interpret and handle NULL a bit differently than C# does null. NULL is unknown rather than unset. In MS SQL Server IS NULL
is used to compare against NULL rather than =
, !=
or <>
.
For MS SQL Server see NULL and UNKNOWN
Upvotes: 0
Reputation: 460018
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.
Upvotes: 6