tabs ↹ over ␣ ␣ ␣ spaces

by Jiří {x2} Činčura

Be careful with "not" conditions and nulls in LINQ when querying databases

Published 21 Jan 2010 in Databases in general, Entity Framework, and LINQ

Today I seen a code with good chance of hard to find mysterious bugs. Let’s start with database table structure we’re going to use for demonstration.

create table NullTest(id int primary key, b bit);
insert into NullTest values (0, 1);
insert into NullTest values (1, 0);
insert into NullTest values (2, null);

If you now try to query this table via LINQ (i.e. LINQ to Entities) you may get surprising results.

foreach (var item in ent.NullTests.Where(x => x.b != true))
{
	Console.WriteLine(string.Format("ID: {0} t B: {1}", item.id, item.b));
}
Console.WriteLine("===");
foreach (var item in ent.NullTests.AsEnumerable().Where(x => x.b != true))
{
	Console.WriteLine(string.Format("ID: {0} t B: {1}", item.id, item.b));
}

If you run this code, you’ll get different results.

ID: 1    B: False
===
ID: 1    B: False
ID: 2    B:

What happened? Is the database engine doing something wrong? Or is there a bug in LINQ? Neither of those. In fact both results are correct. The second one (evaluated in .NET on client) is obvious why it’s as is. But what happened in processing of first one (evaluated on database side)? The devil is in NULL logic. Every operation with NULL results in NULL or false if it’s a boolean operation. And this exactly explains the inconsistent result. In .NET null != true is true but in databases it’s false (because of the NULL rules described above).

Thus if you’re writing LINQ query for database, although the impedance mismatch should be hidden from you when using LINQ, you need to take into account different NULL handling in database engines and in .NET (or any common programming language).

Remember the DBNull.Value? That was explicit solution for this “problem”.