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.