Blair Conrad

Select May Not be Broken, But it's Bent

Earlier this week at the day job I ran into an interesting problem working with a DataTable. A view that's supposed to show a subset of the table's rows showed nothing. I dropped into the debugger and became even more confused.

Visually inspecting the DataTable showed that there was a row that matched the filter the view was using, but running Select still returned nothing. I didn't bring work's code home, but here's some code that reproduces the problem:

Console.Out.WriteLine("0th book's Library:\t{0}", books[0].Library);
Console.Out.WriteLine("# WPL books by Select:\t{0}", library.Books.Select("Library = 'WPL'").Length);
Console.Out.WriteLine("# WPL books by LINQ:\t{0}", library.Books.Count(book => book.Library == "WPL"));

And the output:

0th book's Library:     WPL
# WPL books by Select:  0
# WPL books by LINQ:    1

So, the table contains at least one book from WPL, Selecting for that library doesn't find the book, yet iterating over all the rows and Counting them does find it.

Just in case you think there's some whitespace trickery going on or something, debug with me:

How is this happening? The row's Library property is actually DBNull, but the dataset defines both DefaultValue and NullValue:

So even though there was DBNull in the row, whenever I examined the Library property, via code (such as the LINQ statements) or visually in the debugger, it appeared to be "WPL".

Select, however, wasn't fooled. It knew the value was DBNull and wouldn't match.

I'm of two minds about this. It's arguably correct behaviour, as the stored value is not "WPL", but I'm not sure that it's desirable to be able to configure the table to present data in a way that's not supported by the query.