<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>O/R Mappers</title>
        <link>http://ayende.com/Blog/category/511.aspx</link>
        <description>O/R Mappers</description>
        <language>en-US</language>
        <copyright>Ayende Rahien</copyright>
        <managingEditor>Ayende@ayende.com</managingEditor>
        <generator>Subtext Version 2.0.0.0</generator>
        <item>
            <title>Slaying relational dragons</title>
            <link>http://ayende.com/Blog/archive/2010/02/22/slaying-relational-dragons.aspx</link>
            <description>&lt;p&gt;I recently had a fascinating &lt;a href="http://nhprof.com/commercialsupport"&gt;support call&lt;/a&gt;, talking about how to optimize a &lt;em&gt;very&lt;/em&gt; big model and an access pattern that basically required to have the entire model in memory for performing certain operations.&lt;/p&gt;  &lt;p&gt;A pleasant surprise was that it &lt;em&gt;wasn’t&lt;/em&gt; horrible (when I get called, there is usually a mess), which is what made things interesting. In the space of two hours, we managed to:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Reduced number of queries by 90%.&lt;/li&gt;    &lt;li&gt;Reduced &lt;em&gt;size&lt;/em&gt; of queries by 52%.&lt;/li&gt;    &lt;li&gt;Increased responsiveness by 60%, even for data set an order of magnitude.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;My default answer whenever I am asked when to use NHibernate is: Whenever you use a relational database. &lt;/p&gt;  &lt;p&gt;My strong recommendation at the end of that support call? Don’t use a relational DB for what you are doing.&lt;/p&gt;  &lt;p&gt;The ERD just below has absolutely nothing to do with the support call, but hopefully it will help make the example. Note that I dropped some of the association tables, to make it simpler.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Slayingtherelationaldragon_A925/image_6.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; margin-left: 0px; border-top: 0px; margin-right: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Slayingtherelationaldragon_A925/image_thumb_2.png" width="706" height="511" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;And the scenario we have to deal with is this one:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Slayingtherelationaldragon_A925/image_8.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Slayingtherelationaldragon_A925/image_thumb_3.png" width="640" height="583" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;em&gt;Every &lt;/em&gt;single table in the ERD is touched by this screen.  Using a relational database, I would need something like the following to get all this data:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; * 
&lt;span class="kwrd"&gt;FROM&lt;/span&gt;   Users 
&lt;span class="kwrd"&gt;WHERE&lt;/span&gt;  Id = @UserID 

&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; * 
&lt;span class="kwrd"&gt;FROM&lt;/span&gt;   Subscriptions 
&lt;span class="kwrd"&gt;WHERE&lt;/span&gt;  UserId = @UserId 
       &lt;span class="kwrd"&gt;AND&lt;/span&gt; GETDATE() &lt;span class="kwrd"&gt;BETWEEN&lt;/span&gt; StartDate &lt;span class="kwrd"&gt;AND&lt;/span&gt; EndDate 

&lt;span class="kwrd"&gt;SELECT&lt;/span&gt;   &lt;span class="kwrd"&gt;MIN&lt;/span&gt;(CheckedBooks.CheckedAt), 
         Books.Name, 
         Books.ImageUrl, 
         &lt;span class="kwrd"&gt;AVG&lt;/span&gt;(Reviews.NumberOfStars), 
         GROUP_CONCAT(&lt;span class="str"&gt;', '&lt;/span&gt;,Authors.Name), 
         GROUP_CONCAT(&lt;span class="str"&gt;', '&lt;/span&gt;,Categories.Name) 
&lt;span class="kwrd"&gt;FROM&lt;/span&gt;     CheckedBooks 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Books 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; BookId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; BookToAuthors 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; BookId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Authors 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; AuthorId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Reviews 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; BookId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; BooksCategories 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; BookId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Categories 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; CategoryId 
&lt;span class="kwrd"&gt;WHERE&lt;/span&gt;    CheckedBooks.UserId = @UserId 
&lt;span class="kwrd"&gt;GROUP&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; BookId 

&lt;span class="kwrd"&gt;SELECT&lt;/span&gt;   Books.Name, 
         Books.ImageUrl, 
         &lt;span class="kwrd"&gt;AVG&lt;/span&gt;(Reviews.NumberOfStars), 
         GROUP_CONCAT(&lt;span class="str"&gt;', '&lt;/span&gt;,Authors.Name), 
         GROUP_CONCAT(&lt;span class="str"&gt;', '&lt;/span&gt;,Categories.Name) 
&lt;span class="kwrd"&gt;FROM&lt;/span&gt;     Books 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; BookToAuthors 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; BookId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Authors 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; AuthorId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Reviews 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; BookId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; BooksCategories 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; BookId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Categories 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; CategoryId 
&lt;span class="kwrd"&gt;WHERE&lt;/span&gt;    BookId &lt;span class="kwrd"&gt;IN&lt;/span&gt; (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; BookID 
                    &lt;span class="kwrd"&gt;FROM&lt;/span&gt;   QueuedBooks 
                    &lt;span class="kwrd"&gt;WHERE&lt;/span&gt;  UserId = @UserId) 
&lt;span class="kwrd"&gt;GROUP&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; BookId 

&lt;span class="kwrd"&gt;SELECT&lt;/span&gt;   Books.Name, 
         Books.ImageUrl, 
         &lt;span class="kwrd"&gt;AVG&lt;/span&gt;(Reviews.NumberOfStars), 
         GROUP_CONCAT(&lt;span class="str"&gt;', '&lt;/span&gt;,Authors.Name), 
         GROUP_CONCAT(&lt;span class="str"&gt;', '&lt;/span&gt;,Categories.Name) 
&lt;span class="kwrd"&gt;FROM&lt;/span&gt;     Books 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; BookToAuthors 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; BookId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Authors 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; AuthorId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Reviews 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; BookId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; BooksCategories 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; BookId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Categories 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; CategoryId 
&lt;span class="kwrd"&gt;WHERE&lt;/span&gt;    BookId &lt;span class="kwrd"&gt;IN&lt;/span&gt; (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; BookID 
                    &lt;span class="kwrd"&gt;FROM&lt;/span&gt;   RecommendedBooks 
                    &lt;span class="kwrd"&gt;WHERE&lt;/span&gt;  UserId = @UserId) 
&lt;span class="kwrd"&gt;GROUP&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; BookId 

&lt;span class="kwrd"&gt;SELECT&lt;/span&gt;   Books.Name, 
         Books.ImageUrl, 
         &lt;span class="kwrd"&gt;AVG&lt;/span&gt;(Reviews.NumberOfStars), 
         GROUP_CONCAT(&lt;span class="str"&gt;', '&lt;/span&gt;,Authors.Name), 
         GROUP_CONCAT(&lt;span class="str"&gt;', '&lt;/span&gt;,Categories.Name) 
&lt;span class="kwrd"&gt;FROM&lt;/span&gt;     Books 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; BookToAuthors 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; BookId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Authors 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; AuthorId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Reviews 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; BookId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; BooksCategories 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; BookId 
         &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Categories 
           &lt;span class="kwrd"&gt;ON&lt;/span&gt; CategoryId 
&lt;span class="kwrd"&gt;WHERE&lt;/span&gt;    Books.Name &lt;span class="kwrd"&gt;LIKE&lt;/span&gt; @&lt;span class="kwrd"&gt;search&lt;/span&gt; 
          &lt;span class="kwrd"&gt;OR&lt;/span&gt; Categories.Name &lt;span class="kwrd"&gt;LIKE&lt;/span&gt; @&lt;span class="kwrd"&gt;search&lt;/span&gt; 
          &lt;span class="kwrd"&gt;OR&lt;/span&gt; Reviews.Review &lt;span class="kwrd"&gt;LIKE&lt;/span&gt; @&lt;span class="kwrd"&gt;search&lt;/span&gt; 
&lt;span class="kwrd"&gt;GROUP&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; BookId&lt;/pre&gt;
&lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;

&lt;p&gt;Yes, this is a fairly simplistic approach, without de-normalization, and I would never perform searches in this manner, but… notice how complex things are getting. For bonus points, look at the forth query, the queued books are &lt;em&gt;ordered&lt;/em&gt;, try to figure out how we can get the order in a meaningful way. I shudder to thing about the execution plan of this set of queries. Even if we ignore the last one that does full text searching in the slowest possible way. And this is just for bringing the data for a single screen, assuming that magically it will show up (you need to do a &lt;em&gt;lot &lt;/em&gt;of manipulation at the app level to make this happen). &lt;/p&gt;

&lt;p&gt;The problem is simple, our data access pattern and the data storage technology that we use are at odds with one another. While relational modeling dictate normalization, our actual data usage means that we don’t really deal with a single-row entity, with relatively rare access to associations, which is the best case for OLTP. Nor are we dealing with set based logic, which is the best case for OLAP / Relational based queries.&lt;/p&gt;

&lt;p&gt;Instead, we are dealing an aggregate that spans multiple tables, mostly because we have no other way to express lists and many to many associations in a relational database.&lt;/p&gt;

&lt;p&gt;Let us see how we could handle things if we were using a document or key/value database. We would have two aggregates, User and Book. &lt;/p&gt;

&lt;p&gt;GetUser(userId) –&amp;gt; would result in:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Slayingtherelationaldragon_A925/image_12.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Slayingtherelationaldragon_A925/image_thumb_5.png" width="224" height="546" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;We can now issue another query, to bring the associated books. GetBooks(153, 1337) would result in:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Slayingtherelationaldragon_A925/image_16.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Slayingtherelationaldragon_A925/image_thumb_7.png" width="248" height="514" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Note that the entire data structure is different, we haven’t just copied the normalized relational model, we have a totally different model. An aggregate (similar to DDD’s aggregate) is a single entity that &lt;em&gt;contains&lt;/em&gt; anything except other aggregates. References to other aggregates are allowed (from user to all the books), but most of the entity’s data is stored as a single value.&lt;/p&gt;

&lt;p&gt;That has several interesting implications. First, we need two queries to get the data for the screen. One to get the user’s data, and the second to get the books that we need to display. Reducing remote calls is something that you &lt;em&gt;really&lt;/em&gt; care about, and simplifying the queries to mere query by ids is going to have a significant effect as well.&lt;/p&gt;

&lt;p&gt;By changing the data storage technology, we also enforced a very rigid aggregate boundary. Transactions becomes much simpler as well, since most transactions will now modify only a single aggregate, which is a single operation, no matter how many actual operations we perform on that aggregate. And by tailoring the data structure that we use to match our needs, we have natural aggregate boundaries.&lt;/p&gt;

&lt;p&gt;The end result is a &lt;em&gt;far&lt;/em&gt; simpler method of working with the data. It may mean that we have to do more work upfront, but look at the type of work we would have to do in order to try to solve our problems using the relational model. I know what model &lt;em&gt;I&lt;/em&gt; would want for this sort of a problem.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/11323.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2010/02/22/slaying-relational-dragons.aspx</guid>
            <pubDate>Mon, 22 Feb 2010 08:00:00 GMT</pubDate>
            <wfw:comment>http://ayende.com/Blog/comments/11323.aspx</wfw:comment>
            <comments>http://ayende.com/Blog/archive/2010/02/22/slaying-relational-dragons.aspx#feedback</comments>
            <slash:comments>79</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/11323.aspx</wfw:commentRss>
        </item>
        <item>
            <title>If you are way off in the deep end, there is only so much that tooling can do for you</title>
            <link>http://ayende.com/Blog/archive/2010/02/05/if-you-are-way-off-in-the-deep-end-there.aspx</link>
            <description>&lt;p&gt;I get a lot of requests for what I term, the regex problem. Why the regex problem?&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;em&gt;Some people, when confronted with a problem, think "I know, I’ll use regular expressions." Now they have two problems.&lt;/em&gt; — &lt;a href="ttp://jwz.livejournal.com"&gt;Jamie Zawinski&lt;/a&gt; in comp.lang.emacs.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;A case in point, which comes up repeatedly, is this question:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Can you show us an example for loading collections of collections.     &lt;br /&gt;How would you write a query and avoid a Cartesian product multiple levels deep ?&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;In this case, we have someone who wants to load a blog, all its posts, and all its comments, and do it in the most efficient manner possible. At the same time, they want to have the tool handle that for them. &lt;/p&gt;  &lt;p&gt;Let us take a look at how two different OR/Ms handle this task, then discuss what an optimal solution is.&lt;/p&gt;  &lt;p&gt;First, Entity Framework, using this code:&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre class="csharpcode"&gt;db.Blogs
    .Include(&lt;span class="str"&gt;"Posts"&lt;/span&gt;)
    .Include(&lt;span class="str"&gt;"Posts.Comments"&lt;/span&gt;)
    .Where(x =&amp;gt; x.Id == 1)
    .ToList();&lt;/pre&gt;
  &lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;&lt;/blockquote&gt;

&lt;p&gt;This code will generate:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt;   [Project2].[Id]             &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Id],
         [Project2].[Title]          &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Title],
         [Project2].[Subtitle]       &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Subtitle],
         [Project2].[AllowsComments] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [AllowsComments],
         [Project2].[CreatedAt]      &lt;span class="kwrd"&gt;AS&lt;/span&gt; [CreatedAt],
         [Project2].[C1]             &lt;span class="kwrd"&gt;AS&lt;/span&gt; [C1],
         [Project2].[C4]             &lt;span class="kwrd"&gt;AS&lt;/span&gt; [C2],
         [Project2].[Id1]            &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Id1],
         [Project2].[Title1]         &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Title1],
         [Project2].[Text]           &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Text],
         [Project2].[PostedAt]       &lt;span class="kwrd"&gt;AS&lt;/span&gt; [PostedAt],
         [Project2].[BlogId]         &lt;span class="kwrd"&gt;AS&lt;/span&gt; [BlogId],
         [Project2].[UserId]         &lt;span class="kwrd"&gt;AS&lt;/span&gt; [UserId],
         [Project2].[C3]             &lt;span class="kwrd"&gt;AS&lt;/span&gt; [C3],
         [Project2].[C2]             &lt;span class="kwrd"&gt;AS&lt;/span&gt; [C4],
         [Project2].[Id2]            &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Id2],
         [Project2].[Name]           &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Name],
         [Project2].[Email]          &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Email],
         [Project2].[HomePage]       &lt;span class="kwrd"&gt;AS&lt;/span&gt; [HomePage],
         [Project2].[Ip]             &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Ip],
         [Project2].[Text1]          &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Text1],
         [Project2].[PostId]         &lt;span class="kwrd"&gt;AS&lt;/span&gt; [PostId]
&lt;span class="kwrd"&gt;FROM&lt;/span&gt;     (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; [Extent1].[Id]             &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Id],
                 [Extent1].[Title]          &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Title],
                 [Extent1].[Subtitle]       &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Subtitle],
                 [Extent1].[AllowsComments] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [AllowsComments],
                 [Extent1].[CreatedAt]      &lt;span class="kwrd"&gt;AS&lt;/span&gt; [CreatedAt],
                 1                          &lt;span class="kwrd"&gt;AS&lt;/span&gt; [C1],
                 [Project1].[Id]            &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Id1],
                 [Project1].[Title]         &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Title1],
                 [Project1].[Text]          &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Text],
                 [Project1].[PostedAt]      &lt;span class="kwrd"&gt;AS&lt;/span&gt; [PostedAt],
                 [Project1].[BlogId]        &lt;span class="kwrd"&gt;AS&lt;/span&gt; [BlogId],
                 [Project1].[UserId]        &lt;span class="kwrd"&gt;AS&lt;/span&gt; [UserId],
                 [Project1].[Id1]           &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Id2],
                 [Project1].[Name]          &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Name],
                 [Project1].[Email]         &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Email],
                 [Project1].[HomePage]      &lt;span class="kwrd"&gt;AS&lt;/span&gt; [HomePage],
                 [Project1].[Ip]            &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Ip],
                 [Project1].[Text1]         &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Text1],
                 [Project1].[PostId]        &lt;span class="kwrd"&gt;AS&lt;/span&gt; [PostId],
                 &lt;span class="kwrd"&gt;CASE&lt;/span&gt; 
                   &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; ([Project1].[C1] &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;) &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="kwrd"&gt;CAST&lt;/span&gt;(&lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt;)
                   &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;CASE&lt;/span&gt; 
                          &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; ([Project1].[Id1] &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;) &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="kwrd"&gt;CAST&lt;/span&gt;(&lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt;)
                          &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; 1
                        &lt;span class="kwrd"&gt;END&lt;/span&gt;
                 &lt;span class="kwrd"&gt;END&lt;/span&gt; &lt;span class="kwrd"&gt;AS&lt;/span&gt; [C2],
                 &lt;span class="kwrd"&gt;CASE&lt;/span&gt; 
                   &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; ([Project1].[C1] &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;) &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="kwrd"&gt;CAST&lt;/span&gt;(&lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt;)
                   &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; &lt;span class="kwrd"&gt;CASE&lt;/span&gt; 
                          &lt;span class="kwrd"&gt;WHEN&lt;/span&gt; ([Project1].[Id1] &lt;span class="kwrd"&gt;IS&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt;) &lt;span class="kwrd"&gt;THEN&lt;/span&gt; &lt;span class="kwrd"&gt;CAST&lt;/span&gt;(&lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;AS&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt;)
                          &lt;span class="kwrd"&gt;ELSE&lt;/span&gt; 1
                        &lt;span class="kwrd"&gt;END&lt;/span&gt;
                 &lt;span class="kwrd"&gt;END&lt;/span&gt; &lt;span class="kwrd"&gt;AS&lt;/span&gt; [C3],
                 [Project1].[C1]            &lt;span class="kwrd"&gt;AS&lt;/span&gt; [C4]
          &lt;span class="kwrd"&gt;FROM&lt;/span&gt;   [dbo].[Blogs] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Extent1]
                 &lt;span class="kwrd"&gt;LEFT&lt;/span&gt; &lt;span class="kwrd"&gt;OUTER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; [Extent2].[Id]       &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Id],
                                         [Extent2].[Title]    &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Title],
                                         [Extent2].[Text]     &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Text],
                                         [Extent2].[PostedAt] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [PostedAt],
                                         [Extent2].[BlogId]   &lt;span class="kwrd"&gt;AS&lt;/span&gt; [BlogId],
                                         [Extent2].[UserId]   &lt;span class="kwrd"&gt;AS&lt;/span&gt; [UserId],
                                         [Extent3].[Id]       &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Id1],
                                         [Extent3].[Name]     &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Name],
                                         [Extent3].[Email]    &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Email],
                                         [Extent3].[HomePage] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [HomePage],
                                         [Extent3].[Ip]       &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Ip],
                                         [Extent3].[Text]     &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Text1],
                                         [Extent3].[PostId]   &lt;span class="kwrd"&gt;AS&lt;/span&gt; [PostId],
                                         1                    &lt;span class="kwrd"&gt;AS&lt;/span&gt; [C1]
                                  &lt;span class="kwrd"&gt;FROM&lt;/span&gt;   [dbo].[Posts] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Extent2]
                                         &lt;span class="kwrd"&gt;LEFT&lt;/span&gt; &lt;span class="kwrd"&gt;OUTER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; [dbo].[Comments] &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Extent3]
                                           &lt;span class="kwrd"&gt;ON&lt;/span&gt; [Extent2].[Id] = [Extent3].[PostId]) &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Project1]
                   &lt;span class="kwrd"&gt;ON&lt;/span&gt; [Extent1].[Id] = [Project1].[BlogId]
          &lt;span class="kwrd"&gt;WHERE&lt;/span&gt;  1 = [Extent1].[Id]) &lt;span class="kwrd"&gt;AS&lt;/span&gt; [Project2]
&lt;span class="kwrd"&gt;ORDER&lt;/span&gt; &lt;span class="kwrd"&gt;BY&lt;/span&gt; [Project2].[Id] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;,
         [Project2].[C4] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;,
         [Project2].[Id1] &lt;span class="kwrd"&gt;ASC&lt;/span&gt;,
         [Project2].[C3] ASC&lt;/pre&gt;
  &lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;&lt;/blockquote&gt;

&lt;p&gt;If you’ll look closely, you’ll see that it generate a join between Blogs, Posts and Comments, essentially creating a Cartesian product between all three. &lt;/p&gt;

&lt;p&gt;What about NHibernate? The following code:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="csharpcode"&gt;var blogs = s.CreateQuery(
    &lt;span class="str"&gt;@"from Blog b 
        left join fetch b.Posts p 
        left join fetch p.Comments 
    where b.Id = :id"&lt;/span&gt;)
    .SetParameter(&lt;span class="str"&gt;"id"&lt;/span&gt;, 1)
    .List&amp;lt;Blog&amp;gt;();&lt;/pre&gt;
  &lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;&lt;/blockquote&gt;

&lt;p&gt;Will generate a much saner statement: &lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;select&lt;/span&gt; blog0_.Id             &lt;span class="kwrd"&gt;as&lt;/span&gt; Id7_0_,
       posts1_.Id            &lt;span class="kwrd"&gt;as&lt;/span&gt; Id0_1_,
       comments2_.Id         &lt;span class="kwrd"&gt;as&lt;/span&gt; Id2_2_,
       blog0_.Title          &lt;span class="kwrd"&gt;as&lt;/span&gt; Title7_0_,
       blog0_.Subtitle       &lt;span class="kwrd"&gt;as&lt;/span&gt; Subtitle7_0_,
       blog0_.AllowsComments &lt;span class="kwrd"&gt;as&lt;/span&gt; AllowsCo4_7_0_,
       blog0_.CreatedAt      &lt;span class="kwrd"&gt;as&lt;/span&gt; CreatedAt7_0_,
       posts1_.Title         &lt;span class="kwrd"&gt;as&lt;/span&gt; Title0_1_,
       posts1_.Text          &lt;span class="kwrd"&gt;as&lt;/span&gt; Text0_1_,
       posts1_.PostedAt      &lt;span class="kwrd"&gt;as&lt;/span&gt; PostedAt0_1_,
       posts1_.BlogId        &lt;span class="kwrd"&gt;as&lt;/span&gt; BlogId0_1_,
       posts1_.UserId        &lt;span class="kwrd"&gt;as&lt;/span&gt; UserId0_1_,
       posts1_.BlogId        &lt;span class="kwrd"&gt;as&lt;/span&gt; BlogId0__,
       posts1_.Id            &lt;span class="kwrd"&gt;as&lt;/span&gt; Id0__,
       comments2_.Name       &lt;span class="kwrd"&gt;as&lt;/span&gt; Name2_2_,
       comments2_.Email      &lt;span class="kwrd"&gt;as&lt;/span&gt; Email2_2_,
       comments2_.HomePage   &lt;span class="kwrd"&gt;as&lt;/span&gt; HomePage2_2_,
       comments2_.Ip         &lt;span class="kwrd"&gt;as&lt;/span&gt; Ip2_2_,
       comments2_.Text       &lt;span class="kwrd"&gt;as&lt;/span&gt; Text2_2_,
       comments2_.PostId     &lt;span class="kwrd"&gt;as&lt;/span&gt; PostId2_2_,
       comments2_.PostId     &lt;span class="kwrd"&gt;as&lt;/span&gt; PostId1__,
       comments2_.Id         &lt;span class="kwrd"&gt;as&lt;/span&gt; Id1__
&lt;span class="kwrd"&gt;from&lt;/span&gt;   Blogs blog0_
       &lt;span class="kwrd"&gt;left&lt;/span&gt; &lt;span class="kwrd"&gt;outer&lt;/span&gt; &lt;span class="kwrd"&gt;join&lt;/span&gt; Posts posts1_
         &lt;span class="kwrd"&gt;on&lt;/span&gt; blog0_.Id = posts1_.BlogId
       &lt;span class="kwrd"&gt;left&lt;/span&gt; &lt;span class="kwrd"&gt;outer&lt;/span&gt; &lt;span class="kwrd"&gt;join&lt;/span&gt; Comments comments2_
         &lt;span class="kwrd"&gt;on&lt;/span&gt; posts1_.Id = comments2_.PostId
&lt;span class="kwrd"&gt;where&lt;/span&gt;  blog0_.Id = 1 /* @p0 */&lt;/pre&gt;
  &lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;&lt;/blockquote&gt;

&lt;p&gt;While this is a saner statement, it will also generate a Cartesian product. There are no two ways about it, this is &lt;em&gt;bad bad bad bad&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;And the way to do that is quite simple, don’t try to do it in a single query, instead, we can break it up into multiple queries, each loading just a part of the graph and rely on the Identity Map implementation to stitch the graph together.  You can read the &lt;a href="http://ayende.com/Blog/archive/2010/01/16/eagerly-loading-entity-associations-efficiently-with-nhibernate.aspx"&gt;post about it here&lt;/a&gt;. Doing this may require more work on your part, but it will end up being much faster, and it is also something that would be much easier to write, maintain and work with.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/11304.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2010/02/05/if-you-are-way-off-in-the-deep-end-there.aspx</guid>
            <pubDate>Fri, 05 Feb 2010 10:00:00 GMT</pubDate>
            <wfw:comment>http://ayende.com/Blog/comments/11304.aspx</wfw:comment>
            <comments>http://ayende.com/Blog/archive/2010/02/05/if-you-are-way-off-in-the-deep-end-there.aspx#feedback</comments>
            <slash:comments>23</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/11304.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Designing the Entity Framework 2nd level cache</title>
            <link>http://ayende.com/Blog/archive/2010/01/13/designing-the-entity-framework-2nd-level-cache.aspx</link>
            <description>&lt;p&gt;One of the things that I am working on is another commercial extension to EF, a 2nd level cache. At first, I thought to implement something similar to the way NHibernate does this, that is, to create two layers of caching, one for entity data and the second for query results where I would store only scalar information and ids.&lt;/p&gt;  &lt;p&gt;That turned out to be &lt;em&gt;quite&lt;/em&gt; hard. In fact, it turned out to be hard enough that I almost gave up on that. Sometimes I feel that extending EF is like hitting your head against the wall, eventually you either collapse or the wall fall down, but either way you are left with a headache.&lt;/p&gt;  &lt;p&gt;At any rate, I eventually figured out a way to get EF to tell me about entities in queries and now the following works:&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// will hit the DB&lt;/span&gt;
&lt;span class="kwrd"&gt;using&lt;/span&gt; (var db = &lt;span class="kwrd"&gt;new&lt;/span&gt; Entities(conStr))
{
    db.Blogs.Where(x =&amp;gt; x.Title.StartsWith(&lt;span class="str"&gt;"The"&lt;/span&gt;)).FirstOrDefault();
}

&lt;span class="rem"&gt;// will NOT hit the DB, will use cached data for that&lt;/span&gt;
&lt;span class="kwrd"&gt;using&lt;/span&gt;(var db = &lt;span class="kwrd"&gt;new&lt;/span&gt; Entities(conStr))
{
   db.Blogs.Where(x =&amp;gt; x.Id == 1).FirstOrDefault();
}&lt;/pre&gt;
  &lt;style type="text/css"&gt;&lt;![CDATA[
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }]]&gt;&lt;/style&gt;&lt;/blockquote&gt;

&lt;p&gt;The ability to handle such scenarios is an important part of what makes the 2nd level cache useful, since it means that you aren’t limited to just caching a query, but can perform far more sophisticated caching. It means better cache freshness and a &lt;em&gt;lot&lt;/em&gt; less unnecessary cache cleanups.&lt;/p&gt;

&lt;p&gt;Next, I need to handle partially cached queries, cached query invalidation and a bunch of other minor details, but the main hurdle seems to be have been dealt with (I am willing to lay odds that I &lt;em&gt;will&lt;/em&gt; regret this statement).&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/11284.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2010/01/13/designing-the-entity-framework-2nd-level-cache.aspx</guid>
            <pubDate>Wed, 13 Jan 2010 14:31:00 GMT</pubDate>
            <wfw:comment>http://ayende.com/Blog/comments/11284.aspx</wfw:comment>
            <comments>http://ayende.com/Blog/archive/2010/01/13/designing-the-entity-framework-2nd-level-cache.aspx#feedback</comments>
            <slash:comments>15</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/11284.aspx</wfw:commentRss>
        </item>
        <item>
            <title>NHibernate vs. Entity Framework 4.0</title>
            <link>http://ayende.com/Blog/archive/2010/01/05/nhibernate-vs.-entity-framework-4.0.aspx</link>
            <description>&lt;p&gt;This is a question that I get &lt;em&gt;very&lt;/em&gt; frequently, and I always tried to dodged the bullet, but I get it so much that I feel that I have to provide an answer. Obviously, I am (not so) slightly biased toward NHibernate, so while you read it, please keep it in mind.&lt;/p&gt;  &lt;p&gt;EF 4.0 has done a lot to handle the issues that were raised with the previous version of EF. Thinks like transparent lazy loading, POCO classes, code only, etc. EF 4.0 is a much nicer than EF 1.0. &lt;/p&gt;  &lt;p&gt;The problem is that it is still a very young product, and the changes that were added only touched the surface. I already &lt;a href="http://ayende.com/Blog/archive/2009/05/29/why-defer-loading-in-entity-framework-isnrsquot-going-to-work.aspx"&gt;talked about some of my problems with the POCO model in EF&lt;/a&gt;, so I won’t repeat that, or &lt;a href="http://ayende.com/Blog/archive/2009/10/14/what-is-up-with-the-entity-framework-vnext.aspx"&gt;my reservations with the Code Only model&lt;/a&gt;. But basically, the major problem that I have with those two is that there seems to be a wall between what experience of the community and what Microsoft is doing. Both of those features shows much of the same issues that we have run into with NHibernate and Fluent NHibernate. Issues that were addressed and resolved, but show up in the EF implementations.&lt;/p&gt;  &lt;p&gt;Nevertheless, even ignoring my reservations about those, there are other indications that NHibernate’s maturity makes itself known. I run into that several times while I was writing the guidance for &lt;a href="http://efprof.com"&gt;EF Prof&lt;/a&gt;, there are things that you simple can’t do with EF, that are a natural part of NHibernate.&lt;/p&gt;  &lt;p&gt;I am &lt;em&gt;not&lt;/em&gt; going to try to do a point by point list of the differences, but it is interesting to look where we do find major differences between the capabilities of NHibernate and EF 4.0. Most of the time, it is in the ability to fine tune what the framework is actually doing. Usually, this is there to allow you to gain better performance from the system without sacrificing the benefits of using an OR/M in the first place.&lt;/p&gt;  &lt;p&gt;Here is a small list:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Write batching – NHibernate can be configured to batch all writes to the database so that when you need to write several statements to the database, NHibernate will only make a single round trip, instead of going to the database per each statement. &lt;/li&gt;    &lt;li&gt;Read batching / multi queries / futures – NHibernate allows to batch several queries into a single round trip to the database, instead of separate roundtrip per each query. &lt;/li&gt;    &lt;li&gt;Batched collection loads – When you lazy load a collection, NHibernate can find other collections of the same type that weren’t loaded, and load all of them in a single trip to the database. This is a great way to avoid having to deal with SELECT N+1. &lt;/li&gt;    &lt;li&gt;Collection with lazy=”extra” – Lazy extra means that NHibernate adapts to the operations that you might run on top of your collections. That means that blog.Posts.Count will &lt;em&gt;not&lt;/em&gt; force a load of the entire collection, but rather would create a “select count(*) from Posts where BlogId = 1” statement, and that blog.Posts.Contains() will likewise result in a single query rather than paying the price of loading the entire collection to memory. &lt;/li&gt;    &lt;li&gt;Collection filters and paged collections  - this allows you to define additional filters (including paging!) on top of your entities collections, which means that you can easily page through the blog.Posts collection, and not have to load the entire thing into memory. &lt;/li&gt;    &lt;li&gt;2nd level cache – managing the cache is &lt;em&gt;complex&lt;/em&gt;, &lt;a href="http://ayende.com/Blog/archive/2009/04/24/nhibernate-2nd-level-cache.aspx"&gt;I touched on why this is important before&lt;/a&gt;, so I’ll skip if for now. &lt;/li&gt;    &lt;li&gt;Tweaking – this is something that is critical whenever you need something that is just a bit beyond what the framework provides. With NHibernate, in nearly all the cases, you have an extension point, with EF, you are completely and utterly blocked. &lt;/li&gt;    &lt;li&gt;Integration &amp;amp; Extensibility – NHibernate has a &lt;em&gt;lot&lt;/em&gt; of extension projects, such as NHibernate Search, NHibernate Validator, NHibernate Shards, etc. Such projects not only do not exists for EF, but they cannot be written, for the most part, because EF has no extension points to speak of.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;On the other side, however:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;EF 4.0 has a better Linq provider than the current NHibernate implementation. This is something being actively worked on and the NH 3.0 will fix this gap. &lt;/li&gt;    &lt;li&gt;EF is from Microsoft.&lt;/li&gt; &lt;/ul&gt;&lt;img src="http://ayende.com/Blog/aggbug/11268.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2010/01/05/nhibernate-vs.-entity-framework-4.0.aspx</guid>
            <pubDate>Tue, 05 Jan 2010 10:00:00 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2010/01/05/nhibernate-vs.-entity-framework-4.0.aspx#feedback</comments>
            <slash:comments>75</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/11268.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Responding to how EF is better NH commentary&amp;hellip;</title>
            <link>http://ayende.com/Blog/archive/2009/12/25/responding-to-how-ef-is-better-nh-commentaryhellip.aspx</link>
            <description>&lt;p&gt;My &lt;a href="http://ayende.com/Blog/archive/2009/12/24/what-can-ef-4.0-do-that-nhibernate-canrsquot.aspx"&gt;last post&lt;/a&gt; caused quite a bit of furor, and I decided that I wanted to respond to all the comments in a single place.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;strong&gt;EF has a designer, NHibernate does not.&lt;/strong&gt;      &lt;br /&gt;This is actually false, NHibernate has multiple designers available for it. &lt;a href="http://altinoren.com/activewriter/"&gt;Active Writer&lt;/a&gt; (Free, OSS, integrated into VS), &lt;a href="http://www.slyce.com/"&gt;Visual NHibernate&lt;/a&gt; (Commercial, Beta) and &lt;a href="http://LLBLGen.com"&gt;LLBLGen&lt;/a&gt; (Commercial, forthcoming in early 2010). I would say that using a designer with NHibernate isn’t something that is very common, most people tend to either code gen the entire model and tweak that (minority) or hand craft the model &amp;amp; mapping. That isn’t for lack of options, it is because it is simply more efficient to do so in most cases.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;EF is from Microsoft.       &lt;br /&gt;&lt;/strong&gt;Yes, it is. That is a good point, because it reflect on support &amp;amp; documentation. Unfortunately, the fact that this was one of the most prominent reasons quoted in the replies is also interesting. It says a lot about the relative quality of the products themselves. Another issue with a data access framework from Microsoft is that history teaches us that few data access methods from Microsoft survive the 2 years mark, and none survive the 5 years mark. RDO, ADO, ADO.Net, Object Spaces, Linq To Sql, Entity Framework – just to name a few.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;Downstream integration.&lt;/strong&gt;      &lt;br /&gt;That was mentioned a few times, as in integration with data services, WCF RIA, etc. I want to divide my comment to that into two parts. First, everything that exists right now &lt;em&gt;can&lt;/em&gt; be use with NHibernate. Second, EF is supposed to come with reporting / BI tools in the future. Currently, everything that came up was easily usable with NHibernate, so I am not really worried about it.&lt;/li&gt;    &lt;li&gt;&lt;strong&gt;In the Future it will be awesome.       &lt;br /&gt;&lt;/strong&gt;Some people pointed out that Microsoft is able to allocate more resources for EF than an OSS project can. That is true to a point. One of the problems that Microsoft is facing is that it has to pay a huge amount of taxes in the way to create a releasable product. That means that it is typically easier for an OSS project to release faster than a comparable Microsoft project. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;So far, I find it &lt;em&gt;really&lt;/em&gt; interesting that no one came up with any concrete feature that EF can do that NHibernate can’t. I am going to let you in on a secret, when EF was announced, there were exactly two things that it could do that NHibernate could not. Both were fixed before EF 1.0 shipped, just because that fact annoyed me.&lt;/p&gt;  &lt;p&gt;Are you telling me that no such thing exists for the new version?&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/11266.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2009/12/25/responding-to-how-ef-is-better-nh-commentaryhellip.aspx</guid>
            <pubDate>Fri, 25 Dec 2009 13:07:00 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2009/12/25/responding-to-how-ef-is-better-nh-commentaryhellip.aspx#feedback</comments>
            <slash:comments>67</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/11266.aspx</wfw:commentRss>
        </item>
        <item>
            <title>What can EF 4.0 do that NHibernate can&amp;rsquo;t?</title>
            <link>http://ayende.com/Blog/archive/2009/12/24/what-can-ef-4.0-do-that-nhibernate-canrsquot.aspx</link>
            <description>&lt;p&gt;I am trying to formulate my formal response to “NH vs. EF” question, and while I have a pretty solid draft ready, I found out that my response is pretty biased. I am not happy with that, so I wanted to pose this as a real question.&lt;/p&gt;  &lt;p&gt;So far, I came up with: &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;EF 4.0 has a better Linq provider than the current NHibernate implementation. This is something being actively worked on and the NH 3.0 will fix this gap. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;My sense of fairness says that this can’t be it, so please educate me.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/11265.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2009/12/24/what-can-ef-4.0-do-that-nhibernate-canrsquot.aspx</guid>
            <pubDate>Thu, 24 Dec 2009 07:00:00 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2009/12/24/what-can-ef-4.0-do-that-nhibernate-canrsquot.aspx#feedback</comments>
            <slash:comments>60</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/11265.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Chasing the SQL Injection that never was</title>
            <link>http://ayende.com/Blog/archive/2009/11/11/chasing-the-sql-injection-that-never-was.aspx</link>
            <description>&lt;p&gt;So, I am sitting there quietly trying to get EF Prof to work in a way that I actually &lt;em&gt;like&lt;/em&gt;, when all of a sudden I realize that I am missing something very important, I can’t see the generated queries parameters in the profiler. &lt;/p&gt;  &lt;p&gt;Looking closely, I started investigating what appear to be a possible SQL injection issue with EF. My issue was that this query:&lt;/p&gt;  &lt;blockquote&gt;   &lt;div id="codeSnippetWrapper"&gt;     &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;entities.Posts.Where(x=&amp;gt;x.Title == “hello”)&lt;/pre&gt;

    &lt;br /&gt;&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Generated the following SQL:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div id="codeSnippetWrapper"&gt;
    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;&lt;br /&gt;1 &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [C1],&lt;br /&gt;[Extent1].[Id] &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [Id],&lt;br /&gt;[Extent1].[Title] &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [Title],&lt;br /&gt;[Extent1].[Text] &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [Text],&lt;br /&gt;[Extent1].[PostedAt] &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [PostedAt],&lt;br /&gt;[Extent1].[BlogId] &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [BlogId],&lt;br /&gt;[Extent1].[UserId] &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [UserId]&lt;br /&gt;&lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt; [dbo].[Posts] &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [Extent1]&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt; N&lt;span style="color: #006080"&gt;'hello'&lt;/span&gt; = [Extent1].[Title]&lt;/pre&gt;

    &lt;br /&gt;&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;It literally drove me crazy. Eventually I tried &lt;em&gt;this&lt;/em&gt; query:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div id="codeSnippetWrapper"&gt;
    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;var hello = &lt;span style="color: #006080"&gt;"hello"&lt;/span&gt;;&lt;br /&gt;entities.Posts.Where(x=&amp;gt;x.Title==hello);&lt;br /&gt;&lt;/pre&gt;

    &lt;br /&gt;&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;Which generated:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div id="codeSnippetWrapper"&gt;
    &lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;span style="color: #0000ff"&gt;SELECT&lt;/span&gt;&lt;br /&gt;1 &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [C1],&lt;br /&gt;[Extent1].[Id] &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [Id],&lt;br /&gt;[Extent1].[Title] &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [Title],&lt;br /&gt;[Extent1].[Text] &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [Text],&lt;br /&gt;[Extent1].[PostedAt] &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [PostedAt],&lt;br /&gt;[Extent1].[BlogId] &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [BlogId],&lt;br /&gt;[Extent1].[UserId] &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [UserId]&lt;br /&gt;&lt;span style="color: #0000ff"&gt;FROM&lt;/span&gt; [dbo].[Posts] &lt;span style="color: #0000ff"&gt;AS&lt;/span&gt; [Extent1]&lt;br /&gt;&lt;span style="color: #0000ff"&gt;WHERE&lt;/span&gt; [Extent1].[Title] = @p__linq__1&lt;/pre&gt;

    &lt;br /&gt;&lt;/div&gt;
&lt;/blockquote&gt;

&lt;p /&gt;

&lt;p /&gt;

&lt;p&gt;This was more like it. &lt;/p&gt;

&lt;p&gt;It seems (and &lt;a href="http://thedatafarm.com"&gt;Julie Lerman&lt;/a&gt; confirmed it) that EF is sticking constant expressions directly into the SQL, and treating parameters differently. &lt;/p&gt;

&lt;p&gt;I am not quite sure &lt;em&gt;why&lt;/em&gt;, but from security standpoint, it is obviously not a problem if it does so for constants. It have a lot less hair now, though.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/11203.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2009/11/11/chasing-the-sql-injection-that-never-was.aspx</guid>
            <pubDate>Wed, 11 Nov 2009 10:00:00 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2009/11/11/chasing-the-sql-injection-that-never-was.aspx#feedback</comments>
            <slash:comments>9</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/11203.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Entity Framework Profiler</title>
            <link>http://ayende.com/Blog/archive/2009/11/06/entity-framework-profiler.aspx</link>
            <description>&lt;p&gt;I was sitting with &lt;a href="http://thedatafarm.com/blog/"&gt;Julie Lerman&lt;/a&gt; today, and we got into a discussion on how to provide more information to EF users. It appears that there is much need for that. &lt;/p&gt;  &lt;p&gt;This is what I do, more or less, so we decided to tackle that problem in the bar. Some drinks later, we had a working version of EF Prof that was actually able to intercept all queries coming from the Entity Framework. Initial testing also shows that I’ll be able to provide much more information about EF than I’ll be able to do with Linq to SQL.&lt;/p&gt;  &lt;p&gt;Unfortunately, the current way of intercepting EF traffic is extremely invasive, and I don’t really like it. I consider it a good proof of concept, but I am going to spend some of next week trying to figure out a less invasive approach.&lt;/p&gt;  &lt;p&gt;In the meanwhile, take a look (not the final look &amp;amp; feel): &lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/EntityFrameworkProfiler_670E/image_4.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/EntityFrameworkProfiler_670E/image_thumb_1.png" width="979" height="314" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/EntityFrameworkProfiler_670E/image_6.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/EntityFrameworkProfiler_670E/image_thumb_2.png" width="725" height="464" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;And here is the project that we profile:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/EntityFrameworkProfiler_670E/image_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/EntityFrameworkProfiler_670E/image_thumb.png" width="888" height="553" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p /&gt;  &lt;p /&gt;  &lt;p&gt;It supports all the usual niceties, so you get stack trace support, tracking selects (including lazy loading), updates, inserts &amp;amp; deletes. And I tested it on both EF 3.5 and EF 4.0.&lt;/p&gt;  &lt;p&gt;I expect to have a private beta starting next week…&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/11197.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2009/11/06/entity-framework-profiler.aspx</guid>
            <pubDate>Fri, 06 Nov 2009 10:00:00 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2009/11/06/entity-framework-profiler.aspx#feedback</comments>
            <slash:comments>17</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/11197.aspx</wfw:commentRss>
        </item>
        <item>
            <title>What is up with the Entity Framework vNext?</title>
            <link>http://ayende.com/Blog/archive/2009/10/14/what-is-up-with-the-entity-framework-vnext.aspx</link>
            <description>&lt;p&gt;Every now and then I do a quick check on the EF blog, just to see what there status is. My &lt;a href="http://blogs.msdn.com/efdesign/archive/2009/10/12/code-only-further-enhancements.aspx"&gt;latest peek&lt;/a&gt; had caused me to gulp. I am not sure where the EF is going with things, I just know that I don’t really like it.&lt;/p&gt;  &lt;p&gt;For a start, take a look at the follow sample from their Code Only mapping (basically Fluent NHibernate):&lt;/p&gt;  &lt;blockquote&gt;   &lt;div id="codeSnippetWrapper"&gt;     &lt;pre id="codeSnippet" class="csharpcode"&gt;.Case&amp;lt;Employee&amp;gt;(&lt;br /&gt;    e =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; {&lt;br /&gt;      manager = e.Manager.Id&lt;br /&gt;      thisIsADiscriminator = “E”&lt;br /&gt;    }&lt;br /&gt;) &lt;br /&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are several things wrong here: “manager” and “thisIsADiscriminator” are strings for all intent and purposes. The compiler isn’t going to check them, they aren’t there to &lt;em&gt;do&lt;/em&gt; something, they are just there to avoid being a literal string. But they &lt;em&gt;are&lt;/em&gt; strings.&lt;/p&gt;

&lt;p&gt;Worse, “thisIsADiscriminator” is a &lt;em&gt;magic&lt;/em&gt; string. &lt;/p&gt;

&lt;p&gt;Second, and far more troubling, I am looking at this class definition and I cringe:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;div id="codeSnippetWrapper"&gt;
    &lt;pre id="codeSnippet" class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Category{&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; ID {get;set;}&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name {get;set;}&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; List&amp;lt;Product&amp;gt; Products {get;set;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;The problem is quite simple, this class has &lt;em&gt;no&lt;/em&gt; hooks for lazy loading. You &lt;em&gt;have&lt;/em&gt; to load everything here in one go. Worse, you probably need to load the &lt;em&gt;entire graph&lt;/em&gt; in one go. That is scaring me on many levels.&lt;/p&gt;

&lt;p&gt;I am not sure how the EF is going to handle it, but short of IL Rewrite techniques, which I don’t think the EF is currently using, this is a performance nightmare waiting to happen.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/11175.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2009/10/14/what-is-up-with-the-entity-framework-vnext.aspx</guid>
            <pubDate>Wed, 14 Oct 2009 00:24:00 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2009/10/14/what-is-up-with-the-entity-framework-vnext.aspx#feedback</comments>
            <slash:comments>53</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/11175.aspx</wfw:commentRss>
        </item>
        <item>
            <title>Answer: The lazy loaded inheritance many to one association OR/M conundrum</title>
            <link>http://ayende.com/Blog/archive/2009/09/03/answer-the-lazy-loaded-inheritance-many-to-one-association-orm.aspx</link>
            <description>&lt;p&gt;
&lt;b&gt;Update:&lt;/b&gt; It appears that I am wrong, and NHibernate can support this functionality by eagerly loading the association at load time. You can do by specifying lazy="false" (and optionally, outer-join="true") on the many to one association.
&lt;/p&gt;

&lt;p&gt;Yesterday I presented an interesting problem that pop up with &lt;em&gt;any &lt;/em&gt;OR/M that supports inheritance and lazy loading.&lt;/p&gt;  &lt;p&gt;Let us say that we have the following entity model:&lt;/p&gt;  &lt;p&gt;&lt;a href="file:///C:/Users/Administrator/AppData/Local/Temp/WindowsLiveWriter-429641856/supfiles16D41AF1/image[2].png"&gt;&lt;img title="image_thumb" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="205" alt="image_thumb" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/AnswerThelazyloadedinheritancemanytoonea_920D/image_thumb_c7c82a62-151a-4ce3-8b54-d349df353ae0.png" width="619" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Backed by the following data model:&lt;/p&gt;  &lt;p&gt;&lt;a href="file:///C:/Users/Administrator/AppData/Local/Temp/WindowsLiveWriter-429641856/supfiles16D41AF1/image[8].png"&gt;&lt;img title="image_thumb[2]" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="152" alt="image_thumb[2]" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/AnswerThelazyloadedinheritancemanytoonea_920D/image_thumb%5B2%5D_4951dbf3-ef01-4202-ae6c-80578a67f756.png" width="498" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;As you can see, we map the Animal hierarchy to the Animals table, and we have a polymorphic association between Animal Lover and his/her animal. Where does the problem starts?&lt;/p&gt;  &lt;p&gt;Well, let us say that we want to load the animal lover. We do that using the following SQL:&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre&gt;&lt;a style="color: #0000ff" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=SELECT&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;SELECT&lt;/a&gt; Name,
	 Animal,
	 Id
&lt;a style="color: #0000ff" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=FROM&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;FROM&lt;/a&gt; AnimalLover
&lt;a style="color: #0000ff" href="http://search.microsoft.com/default.asp?so=RECCNT&amp;amp;siteid=us%2Fdev&amp;amp;p=1&amp;amp;nq=NEW&amp;amp;qu=WHERE&amp;amp;IntlSearch=&amp;amp;boolean=PHRASE&amp;amp;ig=01&amp;amp;i=09&amp;amp;i=99"&gt;WHERE&lt;/a&gt; Id = 1 &lt;span style="color: #008000"&gt;/* @p0 */&lt;/span&gt;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;And now we have an animal lover instance:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre&gt;var animalLover = GetAnimalLoverById(1);
var isDog = animalLover.Animal &lt;span style="color: #0000ff"&gt;is&lt;/span&gt; Dog;
var isCat = animalLover.Animal &lt;span style="color: #0000ff"&gt;is&lt;/span&gt; Cat;&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Can you guess what would be the result of this code?&lt;/p&gt;

&lt;p&gt;The answer is that both isDog nor isCat would be… &lt;em&gt;false&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;But how is that?&lt;/p&gt;

&lt;p&gt;To answer that question, let us take a look at the SQL that was used to load the animal lover, and let us take a look at a typical example of hydrating entities. I am using &lt;a href="http://davybrion.com/blog/2009/08/build-your-own-data-access-layer-series/"&gt;Davy’s DAL&lt;/a&gt; here to show off the problem, because the code is simple and it demonstrate that the problem is not unique to a particular OR/M, but is shared among all of them (Davy’s DAL doesn’t even &lt;em&gt;support&lt;/em&gt; inheritance, for example).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre&gt;&lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; SetReferenceProperties&amp;lt;TEntity&amp;gt;(
	TableInfo tableInfo, 
	TEntity entity, 
	IDictionary&amp;lt;&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;object&lt;/span&gt;&amp;gt; values)
{
	&lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var referenceInfo &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; tableInfo.References)
	{
		&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (referenceInfo.PropertyInfo.CanWrite == &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;)
			&lt;span style="color: #0000ff"&gt;continue&lt;/span&gt;;
		
		&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; foreignKeyValue = values[referenceInfo.Name];

		&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (foreignKeyValue &lt;span style="color: #0000ff"&gt;is&lt;/span&gt; DBNull)
		{
			referenceInfo.PropertyInfo.SetValue(entity, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;);
			&lt;span style="color: #0000ff"&gt;continue&lt;/span&gt;;
		}

		var referencedEntity = sessionLevelCache.TryToFind(
			referenceInfo.ReferenceType, foreignKeyValue);
			
		&lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(referencedEntity == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)
			referencedEntity = CreateProxy(tableInfo, referenceInfo, foreignKeyValue);
								   
		referenceInfo.PropertyInfo.SetValue(entity, referencedEntity, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;);
	}
}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;Take a look at what the code is doing, we are currently processing the Aminal property on the AnimalLover class. And we try to find an Animal that was loaded with a primary key matching to the value of the Animal column in the AnimalLovers table.&lt;/p&gt;

&lt;p&gt;When we can’t find it, we have to create a lazy loading proxy for the referenced entity. And here is where the conundrum kicks into play. When we have inheritance, we have a real problem here. What &lt;em&gt;is&lt;/em&gt; the type of the referenced entity? &lt;/p&gt;

&lt;p&gt;From the model, we know that it must be a derivation of Animal of some sort, and we have its PK, but we have no way of knowing &lt;em&gt;which&lt;/em&gt; without going to the database for it.&lt;/p&gt;

&lt;p&gt;So what are we going to do? Because we don’t have enough information to create a lazy loading proxy of the appropriate type, we actually generate a lazy loading proxy of the type that we &lt;em&gt;do &lt;/em&gt;know about, Animal.&lt;/p&gt;

&lt;p&gt;But what about when it &lt;em&gt;is&lt;/em&gt; being loaded?&lt;/p&gt;

&lt;p&gt;Well, that is where the lack of &lt;a href="http://gbracha.blogspot.com/2009/07/miracle-of-become.html"&gt;#become&lt;/a&gt; in .NET becomes painful, we already have an instance, and we can’t change its types. And we can’t replace the reference on the AnimalLover because someone might have grab a reference to the animal before the lazy load.&lt;/p&gt;

&lt;p&gt;The way to handle it is by turning the lazy loading proxy into a real one. We load a &lt;em&gt;new&lt;/em&gt; instance that represent the entity, now with the correct type, since we query the DB to find out what it is (along with the rest of the entity’s data).&lt;/p&gt;

&lt;p&gt;And the lazy loading proxy that we originally used is now loaded, and any call made on it will be forwarded to the new instance that was loaded.&lt;/p&gt;

&lt;p&gt;animalLover.Animal stays an AnimalProxy, and cannot be cast to a Dog or a Cat, even if the actual row it is pointing to &lt;em&gt;is&lt;/em&gt; a Dog or a Cat.&lt;/p&gt;&lt;img src="http://ayende.com/Blog/aggbug/11068.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Ayende Rahien</dc:creator>
            <guid>http://ayende.com/Blog/archive/2009/09/03/answer-the-lazy-loaded-inheritance-many-to-one-association-orm.aspx</guid>
            <pubDate>Thu, 03 Sep 2009 07:04:00 GMT</pubDate>
            <comments>http://ayende.com/Blog/archive/2009/09/03/answer-the-lazy-loaded-inheritance-many-to-one-association-orm.aspx#feedback</comments>
            <slash:comments>56</slash:comments>
            <wfw:commentRss>http://ayende.com/Blog/comments/commentRss/11068.aspx</wfw:commentRss>
        </item>
    </channel>
</rss>