Calling a method within a Linq-To-Entities or Linq-To-Sql query

You may puzzled at why you cannot something as simple as this when working with Linq-To-Sql or Linq-To-Entities:

public void Spike()
{ customers.Where(c => IsRegistered(c)); }

public bool IsRegistered(Customer customer) { return customer.IsRegistered == true; }

Obviously for this to be of any use you’d need a reason for needing to centralize that logic for reuse, otherwise it’s pointless and you might as well code it inline your linq query.

What’s surprising is that this actually doesn’t work. You will get a System.NotSupportedException. What the hell? a boolean method is not supported? what’s this playing at?

well, the key is in the premise. You are not dealing with Linq-To-Objects, you are dealing with Linq-To-Sql or Linq-To-Entities or any Linq-To-Anything-Which-Is-A-Data-Store supported by IQueryable. You are connecting to an underlying data source not just filtering on an IEnumerable in-memory collection of objections.

Anything that goes in IQueryable is actually treated as what’s called an Expression which is code that is parsed and translated into SQL statements. So from that perspective, indeed, IsRegistered(Customer customer) means nothing to the SQL translator. what can it do with that? it doesn’t map to any SQL syntax it knows. Yes, it could always look inside and parse code recursively, however, that’s not how the engine works and if that happened you’d most likely notice a big degradation in performance rapidly since it’d have to compile and execute code until it found what it actually just needed to translate. who knows, maybe in the future, but not for now.

So if you are really inclined in centralizing that logic, what do you do then? Easy, just get rid of the IsRegistered method and implement your logic as an Expression instead, like this:

Expression<Func<Customer,bool>> IsRegistered = c => c.IsRegistered == true;

Obviously like said before you can stuff as much logic as you want inside that expression.

then you use it like this:

public void Spike()
{ customers.Where(IsRegistered); }

nifty, eh?

Word of caution, before you celebrate too much: you cannot add anything else to the Where statement now by using && or ||. the reason for this is a whole new other post though. This gives a good insight into it if you wanna delve that deep : http://tomasp.net/articles/dynamic-linq-queries.aspx