Mehfuz's WebLog

Live crazy, think different!

Sponsors

News

Passionate about cutting edge technologies and facinated by the modern web and phone revolution.Currently working at Telerik Corporation, the leading .net component vendor.
Follow me


Articles


Projects

How to delegate Queryable.Single calls in Custom LINQ provider

When creating custom LINQ provider , despite of looping query items, it is sometimes needed that we need to get the first , last, single or more specific items from the query result.

LINQ runtime creates Queryable instance of the query expression.Although, Queryable has a Single method defined , there is no such member in either IQueryable / IQueryProvider.  Therefore, for the following query like

var query = from ph in context.Photos
             where ph.Id == PhotoId
             select ph;

Photo photo = query.Single<Photo>();

We need to have a mechanism, that forwards the call to our custom defined Single method.

To easily , implement that , in LINQ.Flickr provider, I have created an Custom interface called IPhotoList ,that looks like

    public interface IPhotoList<T>
    {
       ...........
        T Single();
        T First();
        T Last();
       ............
       ...........
    }

This interface is implemented in FlickrQuery, which also implementes IQueryable interface.

Now as for

Photo photo = query.Single<Photo>();

This method in FlickrQuery is called by system.

public object Execute(System.Linq.Expressions.Expression expression)

Therefore, the concept here, we will check if the expression is MethodCallExpression, if so , then we will further check if the return type is the one we are looking for , in this case Photo. Finally, we will need to reflect the method of the current class and compare that with the method for which the Execute is invoked, if both match, then we need to invoke the local equivalent for that and return the value back.

Code for that

MethodCallExpression mCallExp = (MethodCallExpression)expression;
// when first , last or single is called 
if (mCallExp.Method.ReturnType == typeof(Photo))
{
    Type itemType = this.GetType();
    string methodName = mCallExp.Method.Name;

    MethodInfo[] mInfos = itemType.GetMethods();
    foreach (MethodInfo mInfo in mInfos)
    {
        if (string.Compare(methodName, mInfo.Name, false) == 0)
        {
           return itemType.InvokeMember(methodName, BindingFlags.InvokeMethod, null, this, null);   
        }
    }
}

Hope this is useful,

kick it on DotNetKicks.com

Posted: Nov 11 2007, 12:07 AM by mehfuzh | with 4 comment(s) |
Filed under: ,

Comments

Joe Chung said:

Photo photo = (from ph in context.Photos where ph.Id == PhotoId select ph).Single<Photo>();

or

Photo photo = context.Photos.Where<Photo>(ph => ph.Id == PhotoId).Single<Photo>();

# November 10, 2007 4:28 PM

mehfuzh said:

That's right , either  for

Photo photo = (from ph in context.Photos where ph.Id == PhotoId select ph).Single<Photo>();

or

Photo photo = context.Photos.Where<Photo>(ph => ph.Id == PhotoId).Single<Photo>();

the expresstion tree will be the same, therefore, it will get the same result.

# November 11, 2007 11:04 AM