Daniel Hoelbling-Inzko talks about programming

Linq provider differences do affect implementation

Posted by Daniel Hölbling on February 26, 2009

After having done some Linq to objects when working with NHibernate I discovered a major flaw in the whole abstraction when using Linq to Sql today.

Imagine the following code:

IQueryable<string> strings = new List<string> {"test", "Test2"}.AsQueryable();
var result = strings.Where(p => p.Contains("test"));

It works perfectly in a Linq to Sql setting since Sqlmetal will translate the contains call to a LIKE operation, and the query will return two results (since LIKE has no case sensitivity).

It simply won’t if you query objects in memory since the standard Contains operation is case sensitive and you will only get one result.

The only way I found to query case insensitive is with IndexOf() like this:

IQueryable<string> strings = new List<string> {"test", "Test2"}.AsQueryable();
var result = strings.Where(p => p.IndexOf("test", StringComparison.OrdinalIgnoreCase) > -1);

Note the StringComparison.OrdinalIgnoreCase that makes this ignore casing.
Now, the catch here is that Sqlmetal (the thing that magically generates Sql from the expression tree), can’t translate IndexOf into Sql and you’ll get an exception.

So, we’re screwed right? :)
Yes! We are, since Contains is not marked as virtual we can’t just subclass List<string> and override the behavior of Contains (assuming we could interfere with the objects creation through some factory). We are bound to write different code for querying Linq2Sql and Linq2Objects. That’s what I call a rather leaky abstraction.

Filed under net, programmierung
comments powered by Disqus

My Photography business


dynamic css for .NET