Writing custom LINQ provider
In this post, I will show how to create a sample LINQ provider.Creating LINQ provider can be far more complex, but here I will demonstrate the very basic one to start.
This sample is done by using VS2008 Beta 2. I finished of this is post by creating a fictious Person query provider that in turn the gives a glimpse of creating custom LINQ provider for pulling data from source, in a more descriptive and convenient way, rather calling out boring GetBy methods.
So,my fist task , is to declare an entity class.
For simplicity, It contains only three properties ID, Name and Age. The properties are created using Automatic property feature of .net 3.0, That means , i don't need to declare anymore private variable and put them under get / set block. It's now more like declaring property in an interface, the only different is that framework does the rest of the work for me.
Now, To make , custom LINQ provider , a class must implement two interface. IQueryable and IQueryProvider.
IQueryable is the interface that make objects queryable in a LINQ expression. Without it , it is not possible to use objects in queries like this
IQueryProvider is the interface that is pointed to by IQueryable , which is also responsible for creating and executing expressions. IQueryable is also a member of IEnumerable, which enables the query result to be used inside a loop.
Now, in the sample Provider, i have created a PersonConext class that implements the IQueryable <T> (in this case IQueryable <Person>) and IQueryProvider . IQueryable has some IEnumarable implements but the most important implementation is the providver creation and type initialization.
As, i have implemented the provider in the same class that implements IQueryable interface, therefore , PersonContext's provider points to itself(this). But we can move the provider to a different class, in that case the framework need to keep instances of two class, one for IQueryable class and another for IQueryProvider class.So, i guess the solution, is to have them in same class.Next, ElmentType is the item , we are dealing with (in this case Person) and Expression.Constant(this), tells the framework that the expression which is used are with constant values.
IQueryProvider, only have two sets of method , Create<S> that returns IQueryable pointer (this is the entry point for expression intialization) and Execute<TResult> that basically uses the Expression instance to query and extract result out of LINQ query.
IQueryProvider.Execute method is called during the iteration of IEnumerables (query), therefore, provider calls an external source or db to get its result during iterateration process only.
Basically, when we do a LINQ query , internally it does methods calls, so inside Execute method, the expression type will be of MethodCallExpression. and for each arguments of MethodcallExpression(which is also a type of Expression), it needs to be evaluated , untill the leaf is reached.
Now, Each MethodCallExpression, generally starts with an UnaryExpression and ends with an BinaryExpression (If the query has a where clause ) or ParameterExpression (If the query is simple select <something>). In between, there is LamdaExpression ( ex . { p = > p.age > 20 } ), to get the next expression we need to call LamdaExpression.Body in this case, where LamdaExpression.Body in most of the case is BinaryExpression.
BinaryExpression can be of various type ,like, ExpressionType.LessThan , ExpressionType.Equal, etc.
Inside ProcessExpression of the sample provider.This shows an idea about how to parse expressions at different states.
Finally, the right part of the BinaryExpression is of ConstantExpression Type (in this case), but it can be of Unary or Parameter Expression, in more complex situations. In this case, we just need to extract the constant value (age/name/id) to filter Person.
Though, in the end the query graph could much more complex , which is beyond the scope of this post, still the basic structure remains the same. Finally, I have added the sample provider code to download. Feel free to download, hope this will give some pointers to custom providers.
To build custom providers with pleasure use LinqExetender (www.codeplex.com/linqextender). The only toolkit that enables you to do it in style.