<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Jb in a nutshell: An elegant LINQ to db4o provider, and a few LINQ tricks</title>
    <link>http://evain.net/blog/articles/2008/02/06/an-elegant-linq-to-db4o-provider-and-a-few-linq-tricks</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description></description>
    <item>
      <title>An elegant LINQ to db4o provider, and a few LINQ tricks</title>
      <description>&lt;p&gt;&lt;a href="http://www.flickr.com/photos/jbevain/2193338507/" title="Statue by Jb Evain, on Flickr"&gt;&lt;img src="http://farm3.static.flickr.com/2398/2193338507_89ef6f1a30.jpg" width="500" height="333" style="border: 2px solid black" alt="Statue" /&gt;&lt;/a&gt;&lt;/p&gt;


	&lt;p&gt;Last year, when I was working at &lt;a href="http://www.db4o.com/"&gt;db4objects&lt;/a&gt; on &lt;a href="http://developer.db4o.com/"&gt;db4o&lt;/a&gt;, I insisted on the need for db4o to act as a &lt;span class="caps"&gt;LINQ&lt;/span&gt; provider, and with that in mind, prototyped one. I&amp;#8217;am happy today to see a &lt;span class="caps"&gt;LINQ&lt;/span&gt; provider making it to &lt;a href="https://source.db4o.com/db4o/trunk/db4o.net/Db4objects.Db4o.Linq/"&gt;db4o&amp;#8217;s &lt;span class="caps"&gt;SVN&lt;/span&gt;&lt;/a&gt;,  especially as I had the chance to influence its design, as I was also researching &lt;span class="caps"&gt;LINQ&lt;/span&gt; for Mono. For that matters, I find &lt;span class="caps"&gt;LINQ&lt;/span&gt; to db4o&amp;#8217;s design particularly elegant.&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;ll use that occasion to describe a few &lt;span class="caps"&gt;LINQ&lt;/span&gt; tricks. Hopefully, the folks at db4o won&amp;#8217;t mind if I steal the show. Actually I think it will even unburden my good friend Rodrigo, who&amp;#8217;s apparently tired of blogging.&lt;/p&gt;


	&lt;h3&gt;Making a type queryable with &lt;span class="caps"&gt;LINQ&lt;/span&gt;&lt;/h3&gt;


	&lt;p&gt;Let&amp;#8217;s take db4o&amp;#8217;s example. What you do first is getting an IObjectContainer, with the idea to store and retrieve objects.&lt;/p&gt;


&lt;pre&gt;
using (var container = Db4oFactory.OpenFile ("data.db4o")) {
    // ...
}
&lt;/pre&gt;

	&lt;p&gt;So the goal was to be able to write somethings either like:&lt;/p&gt;


&lt;pre&gt;
var peoples = from container.Query&amp;lt;Person&amp;gt; ()
             where p.Name == "jb" &amp;#38;&amp;#38; p.Age == 25
             select p
&lt;/pre&gt;

	&lt;p&gt;or like:&lt;/p&gt;


&lt;pre&gt;
var peoples = from Person p in container
             where p.Name == "jb" &amp;#38;&amp;#38; p.Age == 25
             select p
&lt;/pre&gt;

	&lt;p&gt;There&amp;#8217;s a few things that we didn&amp;#8217;t like with the first method. First an IObjectContainer already have a Query&amp;lt;T&amp;gt; method, which is used for native queries, and secondly, aesthetically, it doesn&amp;#8217;t look as good as the second one.&lt;/p&gt;


	&lt;p&gt;So we went for the second possibility. The issue is that IObjectContainer doesn&amp;#8217;t implement any interface that the compiler could use to perform &lt;span class="caps"&gt;LINQ&lt;/span&gt; queries on it.&lt;/p&gt;


	&lt;p&gt;The trick here is that when the compiler encounters the form:&lt;/p&gt;


&lt;pre&gt;
from Person p in container
&lt;/pre&gt;

	&lt;p&gt;It will try to compile it as:&lt;/p&gt;


&lt;pre&gt;
container.Cast&amp;lt;Person&amp;gt; ()
&lt;/pre&gt;

	&lt;p&gt;And expect that this Cast&amp;lt;T&amp;gt; returns an IEnumerable&amp;lt;T&amp;gt;, on which he can perform &lt;span class="caps"&gt;LINQ&lt;/span&gt; query. The good news is that this Cast method can very well be an extension method.&lt;/p&gt;


	&lt;p&gt;With that in mind, the entry point of &lt;span class="caps"&gt;LINQ&lt;/span&gt; to db4o is really simple:&lt;/p&gt;


&lt;pre&gt;
public static IDb4oLinqQuery&amp;lt;T&amp;gt; Cast&amp;lt;T&amp;gt;(this IObjectContainer container)
{
    return new Db4oQuery&amp;lt;T&amp;gt;(container);
}
&lt;/pre&gt;

	&lt;p&gt;Now comes the question of what is this IDb4oLinqQuery&amp;lt;T&amp;gt;.&lt;/p&gt;


	&lt;h3&gt;Implementing a lightweight &lt;span class="caps"&gt;LINQ&lt;/span&gt; provider&lt;/h3&gt;


	&lt;p&gt;&lt;span class="caps"&gt;LINQ&lt;/span&gt; is still a pretty new technology, so it&amp;#8217;s not always easy to find good advices from people that are already experienced in the fine art of writing &lt;span class="caps"&gt;LINQ&lt;/span&gt; providers. If I don&amp;#8217;t have the pretension to be one of those experienced guys, I know of at least one folk who used the following trick, and which is happy with it.&lt;/p&gt;


	&lt;p&gt;So today, the standard way of writing a &lt;span class="caps"&gt;LINQ&lt;/span&gt; provider seems to be implementing the interface System.Linq.IQueryable&lt;T&gt;, and to implement a full fledged &lt;span class="caps"&gt;LINQ&lt;/span&gt; provider. &lt;a href="http://blogs.msdn.com/mattwar/"&gt;Matt Warren&lt;/a&gt; have written an excellent &lt;a href="http://blogs.msdn.com/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx"&gt;series of posts&lt;/a&gt; about it. &lt;span class="caps"&gt;LINQ&lt;/span&gt; to db4o uses some code from his posts. &lt;a href="http://community.bartdesmet.net/blogs/bart/"&gt;Bart de Smet&lt;/a&gt; also wrote &lt;a href="http://community.bartdesmet.net/blogs/bart/archive/2007/04/05/the-iqueryable-tales-linq-to-ldap-part-0.aspx"&gt;a nice one&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;My very first prototype was also following this path, but at that time, we changed it quickly for an excellent reason.&lt;/p&gt;


	&lt;p&gt;Thing is that the IQueryable path is an all or nothing solution. It keeps building an expression tree, until you decide to work on its result, either by calling GetEnumerator, or by calling AsEnumerable on it.&lt;/p&gt;


	&lt;p&gt;Another thing is that db4o is only able to optimize a (comparatively with something like &lt;span class="caps"&gt;LINQ&lt;/span&gt; to &lt;span class="caps"&gt;SQL&lt;/span&gt;) very little subset of the possible &lt;span class="caps"&gt;LINQ&lt;/span&gt; operations. Actually, it can really optimize only Where, Count, OrderBy and ThenBy.&lt;/p&gt;


	&lt;p&gt;And again, here comes the magic of the extension methods. All &lt;span class="caps"&gt;LINQ&lt;/span&gt; operations are actually extension methods on IEnumerable&amp;lt;T&amp;gt;, or on a child of it, like IQueryable&amp;lt;T&amp;gt;.&lt;/p&gt;


	&lt;p&gt;The trick here, was simply to re-define the supported &lt;span class="caps"&gt;LINQ&lt;/span&gt; operations, on a custom interface. And that&amp;#8217;s what the IDb4oLinqQuery interface we talked before is. It&amp;#8217;s simply a marker interface:&lt;/p&gt;


&lt;pre&gt;
public interface IDb4oLinqQuery&amp;lt;T&amp;gt; : IEnumerable&amp;lt;T&amp;gt;
{
}
&lt;/pre&gt;

	&lt;p&gt;And thanks to the C#3 magic, we can redefine the &lt;span class="caps"&gt;LINQ&lt;/span&gt; operations on it:&lt;/p&gt;


&lt;pre&gt;
public static class Db4oLinqQueryExtensions
{
    public static IDb4oLinqQuery&amp;lt;TSource&amp;gt; Where&amp;lt;TSource&amp;gt;(this IDb4oLinqQuery&amp;lt;TSource&amp;gt; self, Expression&amp;lt;Func&amp;lt;TSource, bool&amp;gt;&amp;gt; expression)
    {
        // ..
    }

    public static int Count&amp;lt;TSource&amp;gt;(this IDb4oLinqQuery&amp;lt;TSource&amp;gt; self)
    {
        // ..
    }
}
&lt;/pre&gt;

	&lt;p&gt;The major advantage of this solution, is that it allows the &lt;span class="caps"&gt;LINQ&lt;/span&gt; query to fallback to &lt;span class="caps"&gt;LINQ&lt;/span&gt; to Objects, anytime a &lt;span class="caps"&gt;LINQ&lt;/span&gt; operations is not supported. So by default, is something cannot be optimized, the &lt;span class="caps"&gt;LINQ&lt;/span&gt; to db4o will return all the types for a certain type, and as we fall back to &lt;span class="caps"&gt;LINQ&lt;/span&gt; to Objects, the user will at least get the result it wanted, even if it doesn&amp;#8217;t run at full speed. I think it&amp;#8217;s something that makes this solution really elegant.&lt;/p&gt;


	&lt;p&gt;Let&amp;#8217;s take a detailed example:&lt;/p&gt;


&lt;pre&gt;
var peoples = from Person p in container
             where p.Name == "jb" 
             orderby p.Age
             select new { p.Age }
&lt;/pre&gt;

	&lt;p&gt;The compiler here sees four steps.&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;First it use the first Cast trick, that creates an IDb4oLinqQuery of T,&lt;/li&gt;
		&lt;li&gt;Secondly, it call the Where methods defined for IDb4oLinqQuery,&lt;/li&gt;
		&lt;li&gt;Then it does the same for OrderBy, which can be optimized,&lt;/li&gt;
		&lt;li&gt;And then only, as db4o cannot optimize the creation of an anonymous type, it will fall back to &lt;span class="caps"&gt;LINQ&lt;/span&gt; to Objects, but only for the select part, while the two first parts run completely optimized, and almost as fast as the db4o low level query mechanism.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;That&amp;#8217;s really nice if you ask me.&lt;/p&gt;


	&lt;h3&gt;Using an expression tree as a dictionary key&lt;/h3&gt;


	&lt;p&gt;That one is simple.&lt;/p&gt;


	&lt;p&gt;&lt;span class="caps"&gt;LINQ&lt;/span&gt; to db4o caches how a query is created, depending on the expression tree it gets. Thing is that System.Linq.Expression doesn&amp;#8217;t override Equals and GetHashCode, and as the compiler re-creates a whole new tree every time it sees one, hence Expressions are poor candidate for being keys in Dictionary. The trick here is simply to have an IEqualityComparer for Expressions. It&amp;#8217;s seems that it&amp;#8217;s not trivial to implement, but they managed to get a pretty nice one.&lt;/p&gt;


	&lt;h3&gt;Analyzing properties body&amp;#8217;s&lt;/h3&gt;


	&lt;p&gt;This trick is also a simple one, and it&amp;#8217;s the same one that db4o uses for its Native Query functionality, &lt;span class="caps"&gt;LINQ&lt;/span&gt; to db4o uses the Cecil.FlowAnalysis library to read the body of the properties, so they know which fields are impacted by the &lt;span class="caps"&gt;LINQ&lt;/span&gt; query.&lt;/p&gt;


	&lt;h3&gt;That&amp;#8217;s all folks&lt;/h3&gt;


	&lt;p&gt;Kuddos to db4o for such a nice addition, hopefully it&amp;#8217;ll run on Mono soon!&lt;/p&gt;</description>
      <pubDate>Wed, 06 Feb 2008 18:30:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:d3d950a5-0288-462d-b979-8881e8afbe1a</guid>
      <author>Jb Evain</author>
      <link>http://evain.net/blog/articles/2008/02/06/an-elegant-linq-to-db4o-provider-and-a-few-linq-tricks</link>
      <category>db4o</category>
      <trackback:ping>http://evain.net/blog/articles/trackback/472</trackback:ping>
    </item>
    <item>
      <title>"An elegant LINQ to db4o provider, and a few LINQ tricks" by Anat Gafni</title>
      <description>&lt;p&gt;very nice, and an evidence that designing with &amp;#8220;elegance&amp;#8221; can save effort/time and is not always just &amp;#8220;creeping&amp;#8221;...&lt;/p&gt;</description>
      <pubDate>Wed, 06 Feb 2008 22:37:01 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:710bb268-3713-4cdb-b694-e66ec0d7624d</guid>
      <link>http://evain.net/blog/articles/2008/02/06/an-elegant-linq-to-db4o-provider-and-a-few-linq-tricks#comment-475</link>
    </item>
    <item>
      <title>"An elegant LINQ to db4o provider, and a few LINQ tricks" by Jb Evain</title>
      <description>&lt;p&gt;Thanks Keith, I corrected it. Sorry Matt :)&lt;/p&gt;</description>
      <pubDate>Wed, 06 Feb 2008 20:15:01 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:ccdfcd01-3c26-437a-81ff-fcd67873d416</guid>
      <link>http://evain.net/blog/articles/2008/02/06/an-elegant-linq-to-db4o-provider-and-a-few-linq-tricks#comment-474</link>
    </item>
    <item>
      <title>"An elegant LINQ to db4o provider, and a few LINQ tricks" by Keith J. Farmer</title>
      <description>&lt;p&gt;The name is &amp;#8220;Matt Warren&amp;#8221;, not &amp;#8220;Matt Wayward&amp;#8221; :)&lt;/p&gt;</description>
      <pubDate>Wed, 06 Feb 2008 20:02:31 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:0bc2446b-d028-46d1-ae0f-3e99698dfe1e</guid>
      <link>http://evain.net/blog/articles/2008/02/06/an-elegant-linq-to-db4o-provider-and-a-few-linq-tricks#comment-473</link>
    </item>
  </channel>
</rss>
