Reputation: 2935
I'm writing some LINQ to fetch records based on an email, however, the generated SQL contains an additional IS NULL
condition which doesn't need to be there because I am checking the parameter value for null in the code prior to adding the condition to the query.
My LINQ code is:
if (email != null)
{
query = query.Where(r => r.Email == email);
}
The SQL condition generated from this is:
(([Extent1].[Email] = @p__linq__0) OR (([Extent1].[Email] IS NULL) AND (@p__linq__0 IS NULL)))
The
(([Extent1].[Email] IS NULL) AND (@p__linq__0 IS NULL))
doesn't need to be there as far as I can see.
Is there any way to get LINQ to omit it?
Upvotes: 17
Views: 2588
Reputation: 272116
In C# null == null
yields true
In ANSI SQL null = null
yields unknown, which is neither true nor false
LINQ translates C# semantics to SQL, so for this expression:
r.Email == email
it will generate a query similar to the following:
WHERE t.Email = @email OR (t.Email IS NULL AND @email IS NULL)
which produces the following truth table¹:
Email | @email | Result
foo | foo | true
null | null | true
foo | bar | false
foo | null | unknown
null | foo | unknown
which is exactly what you would expect from C#². This article explains EF null value handling in detail.
Is there any way to get LINQ to omit it?
I would not worry about it as long as (i) the query produces expected result even for null (ii) the performance is not (significantly) affected.
¹ In SQL unknown OR false
yields unknown
² For the purpose of filtering only true values are considered
Upvotes: 0
Reputation: 12855
They're there in case email
is null.
You can prevent this by setting UseDatabaseNullSemantics to true
Gets or sets a value indicating whether database null semantics are exhibited when comparing two operands, both of which are potentially nullable. The default value is false. For example (operand1 == operand2) will be translated as: (operand1 = operand2) if UseDatabaseNullSemantics is true, respectively (((operand1 = operand2) AND (NOT (operand1 IS NULL OR operand2 IS NULL))) OR ((operand1 IS NULL) AND (operand2 IS NULL))) if UseDatabaseNullSemantics is false.
There are various ways to apply this.
If you only want to apply this to a single query you can do something like this:
using(TheContext dbContext = new TheContext()) {
dbContext.Configuration.UseDatabaseNullSemantics = true;
...
if (email != null)
{
query = query.Where(r => r.Email == email);
}
}
If you want to apply this to all queries:
public class TheContext : DbContext
{
public TheContext()
{
this.Configuration.UseDatabaseNullSemantics = true;
}
}
You can also change the property to be [Required]
:
public class Model {
[Required]
public string Email { get; set; }
}
Upvotes: 28