I've noticed that Entity Framework translates LINQ queries with negative boolean filters such that the generated query plan won't use a filtered index. For example, the query:
context.Foo.Count(f => !f.IsActive)
generates the SQL statement:
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[Foos] AS [Extent1]
WHERE [Extent1].[IsActive] <> cast(1 as bit)
) AS [GroupBy1]
Notice the WHERE
clause uses [IsActive] <> cast(1 as bit)
, rather than the more intuitive [IsActive] = 0
. This becomes an issue when using filtered indexes. The plan for the above query will not use the following index:
CREATE INDEX IX_Foo_IsActive ON Foos (IsActive) WHERE (IsActive = 0)
I suspect the reason that EF generates queries this way has something to do with DB null semantics, but this happens even with non-nullable bit fields. I've verified that writing the filtered index with EF's syntax (IsActive <> 1
) fixes the issue, but that would break any non-EF queries using the more common syntax.
Is there a better work around?
Full example program here: http://dotnetfiddle.net/3kZugt. The entity type used above is:
public class Foo
{
public int Id { get; set; }
public bool IsActive { get; set; }
}