Entity Framework Pitfalls: Null Semantics
Imagine you have a simple class:
public class MyEntity
{
public int Id { get; set; }
public string Name { get; set; }
}
You may want to query it:
string name = ...;
var entities = ctx
.MyEntities
.Where(x => x.Name == name)
.ToList();
Entity Framework generates a query such as this:
SELECT [Extent1].[Id] AS Id, [Extent1].[Name] AS Name
FROM [dbo].[MyEntities] AS [Extent1]
WHERE ([Extent1].[Name] = @p__linq__0)
OR (([Extent1].[Name] IS NULL) AND (@p__linq__0 IS NULL))
Meaning: return all records from the MyEntities table if
-
The Name column is identical to the name variable or
-
Both the Name column and the name variable are NULL
Seems excessively complex, doesn’t it? Well, this is to account for the case where the name parameter is null. In that case, a simple COLUMN = VALUE comparison won’t work, because in SQL, NULL = NULL returns FALSE! The syntax for comparing with NULL is COLUMN IS NULL. By generating this kind of query, Entity Framework is playing safe. Mind you, this only happens if you do not use the literal null, if you do, Entity Framework is smart enough to generate a simpler query:
var entities = ctx
.MyEntities
.Where(x => x.Name == null)
.ToList();
Results in:
SELECT [Extent1].[Id] AS Id, [Extent1].[Name] AS Name
FROM [dbo].[MyEntities] AS [Extent1]
WHERE ([Extent1].[Name] IS NULL)
However, there is a configuration setting, UseDatabaseNullSemantics (the opposite of the old UseCSharpNullComparisonBehavior of ObjectContext), that can be used to control this behavior. If set to true (the opposite of the default):
ctx.Configuration.UseDatabaseNullSemantics = true;
It generates all SQL queries as the unsafe version:
SELECT [Extent1].[Id] AS Id, [Extent1].[Name] AS Name
FROM [dbo].[MyEntities] AS [Extent1]
WHERE ([Extent1].[Name] = @p__linq__0)
The result is, even if you have a record whose Name column is NULL, it won’t be returned: remember that in SQL, by default, NULL <> NULL!
Therefore, if you are not 100% sure that the parameter that you will be using in the LINQ query will never be null, do not mess with UseDatabaseNullSemantics even if it generates somewhat poorer SQL.
Of course, if you are using SQL Server, you can set ANSI_NULLS to OFF, and the problem goes away; in that case, NULL = NULL.