LinqExtender

The greatest capability for LINQ is extensibility, My Linq.Flickr api shows how to create , add and quey photos from flickr , without knowing a bit of complexity that is underlying. But, there can be many other need for custom query providers like, Linq to facebook, Linq to youtube, etc. So, creating all these , could be very easy and fun, if there is a common framework that will sit between core Linq and custom provider and let developers to focus only on the application specific logic, not on the query internals and thus it will help developers to make their own providers up and running, in no time.

This is where, it comes a toolkit called LinqExtender  that will gear you up for creating custom provider, with zero complexity.

To start off with LinqExtender, you can either use the VSI installer or  LinqExtender.dll.zip, both of which are referenced in release page of the project.Also, following lines will show , what is needed to start developing custom providers.

--

Create a query object, on which the query will be made , by inheriting QueryObjectBase and overriding the IsNew property , which is used to track , if the object is newly added to the collection or not and this will be tracked during , add/ update of query obejcts,

For example, for the following code , the IsNew property will have value "true"

MyProvider context = new MyProvider ();

context.Add(MyObject);

context.SubmitChange();

Code sample of CustomQuery object, in this case MyObject

public class MyObject : QueryObjectBase
{
    public override bool IsNew
    {
        get
        {
            //TOOD : Add your own Is New logic.
            return true;
        }
    }

}

Now, Create the custom query provider by inheriting Query<T> and overriding some methods of it. In this case the code sample looks like

public class MyProvider : Query<MyObject>
{
    protected override void AddItem(MyObject item)
    {
        // TOOD : Implenment data access logic, 
        //  Sample
        // IFlickr flickr = new DataAccess();
        // flicrk.Add(item);
    }

    protected override void RemoveItem(MyObject item)
    {
        // TODO : Implement data access logic
        //Sample
        // IFlickr flickr = new DataAccess();
        // flicrk.Delete(item);

    }
    protected override void Process(LinqExtender.Interface.IQuery<MyObject> items, 
    MyObject bucket, int itemsToTake, int itemsToSkip, bool isParamCall)
    {
        // TODO :  populate collection on basis of bucket object.

        // Sample
        // IFlickr flickr = new DataAccess();
        // IList<Photo> list =  flicrk.SearchPhoto(bucket.SearchText, bucket.User, itemsToSkip, ItemsToTake);
        // items.AddRange (list);
    }
}

Here to note that bucket variable in Process method, is filled up the query value that is made by user . In the case of Linq.Flickr , when user does a photo query in the following way

var query = (from ph in context.Photos
             where ph.User =="jcl"&& ph.PhotoSize == PhotoSize.Medium 
             && ph.SearchText == "pocketpc" 
             select ph).Take(10).Skip(0);

Inside Process the bucket will have the following values

bucket.SearchText = "pocketpc"
bucket.PhotoSize = PhotoSize.Medium
bucket.User = jcl

In the query you can also see that for Take and Skip , itemsToTake and ItemsToSkip will be filled up respectively and IsParamCall = true , if the query has no Where cause.At the end of the method items variable, needs to be filled up with the result, in this case, list of photos. Therefore, at the end of Process , items.AddRange or items.Add should be used to reflect the result back to query.

Finally, The AddItem/ RemoveItem method is called , when user adds / removes an item, then make SubmitChanges() call.

--

This is a short introduction to LinqExtender, in coming weeks, I will write more walkthroughs with working sample. For now, to see the real implementation , take a look at Linq.Flickr project.

Enjoy!

Starting with 1.1 version rather working with main object refernce in AddItem , RemoveItem and Process , a new wrapper name Bucket is introduced to deal with query parameters to have a unified and extensible way of dealing with user query details. Please check the codeplex project page for more Info. Also, see the prograssion of posts made with this blog as well.

kick it on DotNetKicks.com

12 Comments

  • Good Post MehfuQ, sorry Mehfuz.

  • It looks like from this implementation I will have to make a DAL. So, if I have to use a DAL in order to serve data, why do I use Linq to SQL then? Isn't the purpose of using Linq to SQL is to eliminate the need for a DAL?

  • Yes it is true that "LINQ to sql" is to replace dataaccess. But, to be more precise LinqExtender is not be included directly in to DAL(Data access layer). It is meant to make your own provider , which you will add to your dataaccess , and then write query like stuffs. let's say , you create a LINQToMySql library on LinqExtender.
    Now, as you write a query like
    var query = from p in Producs
    &nbsp; &nbsp;where p.purchased = 1
    &nbsp; &nbsp;select &nbsp;p;
    Product product = query.First&lt;Product&gt;();
    This will generate the mysql query run it a for given db context and return the result. The generating of query and running it in a db is the task of the developer, who will be writing the LINQMysql library, then after it is distributed and someone else &nbsp;will download it and just refrence it to his dataaccess to do sql like queries in C#/VB.
    As , you know LINQ to Sql itself is a provider , that does the query generation on your behalf.So when you referece System.Data.Linq to you project , you reference the sql provider framework as well, along with core linq features. In addition, VS2008 enables you to create dbml that will genenrate the objects and query wrapper for you that implements the core LINQToSql framwork.
    Finally, What Linqextender does,it gives easy interface and hides the expression tree parsing and other internals from you, but creating the provider still is on your own creativity.
    Also, LINQExtender is not here to replace the main buiit-in LINQToSql that comes with .net 3.5, but it will give developers more option for creating providers like LinqToFlickr, LinqtoFacebook or LINQtOMySql, easily without knowing much of expression trees, and as it is Generic typed, any object can go through it, with rule that i have described.
    Hope this helps

  • I found your LinqExtender is very useful. I have thought to make somekind DAL provider with your library. but I found that this library still have some lack of features something like projected types, grouping.
    Do you have plan to extend the functionality of LinqExtender ?

  • Thanks for the comment, sure, i do have plan for extending it. Also, i have just released 1.01 version of it, please check it out. It has now, orderby support, also i have created a tiny LinqtoSql provider on top of it, that supports select, insert, delete and order and stands on EntLib 3.0.

    Hope this helps

  • Very nice component... I read your articles about LINQ provider and expression trees and I don't have a problem understanding any of the concept, but the extender saves soooooo much coding!

    One thing though... the extender is failing on the projected query when an anonymous type is provided in the select/projection query... is there anything I should or should not be doing?

  • Did you tried the latest release ?

  • I did try the latest version... I thouhgt the problem was an anonymous type, but it turns out to be the uses of joins.. for example...
    var innerJoinQuery =
    &nbsp; &nbsp;(from mbi in _memberInfoData
    &nbsp; &nbsp; &nbsp; &nbsp;join mh in _mailingHistoryData
    &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;on mbi.MemberID equals mh.MemberID
    &nbsp; &nbsp; &nbsp;where mbi.EntityID == 152
    &nbsp; &nbsp; &nbsp;select new {
    MemberID = mbi.MemberID, EntityID = mbi.EntityID, MailBatch = mh.MailBatch });
    I am getting an invalid cast exception on the third entry to the CreateQuery&lt;S&gt; method
    return (IQueryable&lt;S&gt;)projectedQuery;
    I know you never mentioned any support for joins... and the problem is coming up because the projectdQuery object has an anonymous type which does not implement the QueryBaseObject interface?...
    I would be able to handle the joins passed this point.

  • Thanks, Jorge for the comment, infact i do want to support join in LinqExtender and will keep you posted :-)

    How about the following in the meantime.

    from mbi in _memberInfoData
    select new MemberInfo
    {
    MemberId = value,
    ...
    ...
    MemberHistory = (from mbh in _memberHistory
    where mbh.MemberId = MemberId
    select mbh).Single()),
    ..
    ..
    }

  • Good work on the Extender.

    One major thing that would be very usful is Joins.
    Do you have an Status updated on them?


    Thanks
    Patrick

  • Yes, you will get it soon :-)

  • If you want to contribute just send email from project page or send me your user id at codeplex.

Comments have been disabled for this content.