<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/rss2full.xsl" type="text/xsl" media="screen"?><?xml-stylesheet href="http://feeds.feedburner.com/~d/styles/itemcontent.css" type="text/css" media="screen"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Rob Conery</title><link>http://blog.wekeroad.com/</link><description>Bare Knuckle Coding</description><generator>Graffiti CMS 1.0 (build 1.0.1.963)</generator><lastBuildDate>Thu, 13 Nov 2008 19:41:38 GMT</lastBuildDate><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/wekeroad/EeKc" type="application/rss+xml" /><feedburner:emailServiceId>475290</feedburner:emailServiceId><feedburner:feedburnerHostname>http://www.feedburner.com</feedburner:feedburnerHostname><item><title>SubSonic 3.0 Repository Template Update</title><link>http://feeds.feedburner.com/~r/wekeroad/EeKc/~3/452198609/</link><pubDate>Thu, 13 Nov 2008 21:11:38 GMT</pubDate><guid isPermaLink="false">http://blog.wekeroad.com/blog/subsonic-3-0-repository-template-update/</guid><dc:creator>Rob Conery</dc:creator><slash:comments>0</slash:comments><category domain="http://blog.wekeroad.com/blog/">Blog</category><description>&lt;p&gt;Got a fun email from Will Gant today:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;Since everything else is going my way (sorta like Burger king), now comes the "can I have fries with that?" question. Would it be possible for the Add, Delete, and Update methods on the repository class to have overloads that take IEnumerable&amp;lt;T&amp;gt;?&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;And I sort of started to kick myself a bit - this should have seemed obvious, and I should have done it from the start, but I didn't and I'm not too sure why. This is the goodness that is Open Source!  &lt;p&gt;Will sent me a quick patch, and I added some spice to it and now we have a batch-updatable (read: one connection, one sql execution) Add/Update/Delete for the Repository which &lt;a href="http://www.wekeroad.com/Repository2a.zip" target="_blank"&gt;you can download here&lt;/a&gt; (I'll include this in subsequent releases). &lt;p&gt;Hopefully this underscores a bit more just how much control you have in this! &lt;p&gt;To show you how this might work, here's a quick spike using the &lt;a href="http://www.codeplex.com/ChinookDatabase" target="_blank"&gt;Chinook database&lt;/a&gt; (our new test db):&lt;pre class="csharpcode"&gt;        [TestMethod]
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Update_Should_Update_En_Masse() {

            ChinookRepository&amp;lt;Customer&amp;gt; repo = &lt;span class="kwrd"&gt;new&lt;/span&gt; ChinookRepository&amp;lt;Customer&amp;gt;();

            var customers = repo.GetAll().ToList();
            &lt;span class="kwrd"&gt;int&lt;/span&gt; index=0;
            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var c &lt;span class="kwrd"&gt;in&lt;/span&gt; customers) {
                c.Company = &lt;span class="str"&gt;"Company"&lt;/span&gt; + index.ToString();
                index++;
            }

            repo.Update(customers);
        }&lt;/pre&gt;
&lt;p&gt;Just to re-iterate, the Update() method here takes in the List&amp;lt;Customer&amp;gt; that is created from the repo.GetAll().ToList() call. This will not work if you leave it as IQueryable. I'm not sure why - but the bottom line is that I tried and the changes weren't honored as I think IQueryable doesn't allow you to assign values to it - it's just an Expression manager.&lt;/p&gt;
&lt;p&gt;The Update method will create one single SQL query and execute it as a batch - one call! I was going to wrap the ExecuteBatch() method in a transaction but decided against it for now - however if you want to do that, you can edit the templates as you need :).&lt;/p&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/RCONERY/6EB18964198954032780CF1F09B9DF98773C49A9"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/RCONERY/6EB18964198954032780CF1F09B9DF98773C49A9"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/wekeroad/EeKc?a=Lvm5lx"&gt;&lt;img src="http://feeds.feedburner.com/~a/wekeroad/EeKc?i=Lvm5lx" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=Qr48N"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=Qr48N" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=1MXTn"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=1MXTn" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=pXbwN"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=pXbwN" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/wekeroad/EeKc/~4/452198609" height="1" width="1"/&gt;</description><feedburner:origLink>http://blog.wekeroad.com/blog/subsonic-3-0-repository-template-update/</feedburner:origLink></item><item><title>SubSonic 3.0 Preview 2</title><link>http://feeds.feedburner.com/~r/wekeroad/EeKc/~3/451358965/</link><pubDate>Thu, 13 Nov 2008 02:48:35 GMT</pubDate><guid isPermaLink="false">http://blog.wekeroad.com/blog/subsonic-3-0-preview-2/</guid><dc:creator>Rob Conery</dc:creator><slash:comments>0</slash:comments><category domain="http://blog.wekeroad.com/blog/">Blog</category><description>&lt;p&gt;Over the last week I've made massive improvements and upgrades to SubSonic 3.0 and the templates that it comes with. I haven't been this obsessive and inspired since I created SubSonic in the first place, and I have to tell you I am more than stoked to see this pull together.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The Foundation&lt;br&gt;&lt;/strong&gt;I'll be really concise with this post - there's so much here ... it will be hard but I really want to keep to the point. SubSonic 3.0 is a Layer Cake which is focused on openness and transparency. Here are the layers:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;&lt;strong&gt;Core&lt;/strong&gt;: Data Access and SQL Translation. This is the part that executes commands against the database, and translates queries (SubSonic's or Linq's) into SQL.  &lt;li&gt;&lt;strong&gt;Surface&lt;/strong&gt;: Working with your database. This layer "surfaces" your database and implements "IQuerySurface" (I couldn't think of a better name). In short, it exposes every table as IQueryable&amp;lt;T&amp;gt;, every Stored Procedure as an executable method, and also provides you with Aggregation queries (Count, Sum, Min, Max, etc).  &lt;li&gt;&lt;strong&gt;Implementation&lt;/strong&gt;: Your Favorite Data Pattern. This can be Repository, ActiveRecord... whatever. I've created (with this release) an IRepository pattern for you that I think covers 99% of the needs out there (you'll see in a moment) and also allows for some nice testability.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Of these, &lt;strong&gt;the only thing that is locked down is part 1 - The Core (as part of our DLL). The rest is built using T4 templates that you add to your project&lt;/strong&gt;. So if you hear me constantly say "&lt;strong&gt;you can change this as you need&lt;/strong&gt; to in the templates" - well it's because you can. These aren't hard to learn, and are created &lt;strong&gt;using plain old C# code&lt;/strong&gt; so changing/altering as you need should be easy. &lt;img style="margin: 5px" height="212" alt="F-117_Nighthawk_Front" src="http://blog.wekeroad.com/files/media/image/WindowsLiveWriter/SubSonic3.0Preview2_DDE0/F-117_Nighthawk_Front_0fbdd12f-5ab9-4b44-a4c0-93f14f76e351.png" width="340" align="right" border="0"&gt; &lt;/p&gt; &lt;p&gt;In fact I was explaining to Steve Harman yesterday that if you wanted to create a full-blown Unit Of Work ORM, you could. You could also create an ActiveRecord pattern too. Really - it's that flexible.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The "Surface"&lt;br&gt;&lt;/strong&gt;There's probably a better name for this - but it seems to capture what I'm after: a simple, easy to understand way to work with your database. This template (called "QuerySurface" - which used to be "Provider") exposes the tables in your database as IQueryable&amp;lt;T&amp;gt; so you can work against them using Linq:&lt;/p&gt;&lt;pre class="csharpcode"&gt;            Northwind.DB db = &lt;span class="kwrd"&gt;new&lt;/span&gt; DB();
            var result = from p &lt;span class="kwrd"&gt;in&lt;/span&gt; db.Products
                         &lt;span class="kwrd"&gt;where&lt;/span&gt; p.CategoryID==5
                         select p;

            &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var item &lt;span class="kwrd"&gt;in&lt;/span&gt; result) {
                Console.WriteLine(item.ProductName);
            }&lt;/pre&gt;
&lt;p&gt;I can go off here and show you all the ways to query with Linq. But you've seen em before and hopefully you won't notice the difference with SubSonic. If you've used Linq To Sql, this will look extremely familiar to you. However know that my approach differs from Linq To Sql in that there is no change tracking and need to have a "context". The DB, in this sense, is simply a wrapper.&lt;/p&gt;
&lt;p&gt;One thing you might not have seen with Linq To Sql is the ability to run Updates and Inserts, which I've always missed and have now implemented with SubSonic 3.0:&lt;/p&gt;&lt;pre class="csharpcode"&gt;            db.Update&amp;lt;Products&amp;gt;().Set(
                x =&amp;gt; x.Discontinued == &lt;span class="kwrd"&gt;false&lt;/span&gt;, 
                x =&amp;gt; x.ReorderLevel == 100)
               .Where(x=&amp;gt;x.Category==5)
               .Execute();&lt;/pre&gt;&lt;pre class="csharpcode"&gt;        db.Insert.Into&amp;lt;Region&amp;gt;(x =&amp;gt; x.RegionID, x =&amp;gt; x.RegionDescription)
          .Values(6, &lt;span class="str"&gt;"Hawaii"&lt;/span&gt;)
          .Execute();&lt;/pre&gt;
&lt;p&gt;I know a lot of people don't like the Lambda thing - you can still use our old query tool (with structs or strings in place of these lambdas) if you like.&lt;/p&gt;
&lt;p&gt;This one's a personal favorite - deleting has become a one-line operation:&lt;/p&gt;&lt;pre class="csharpcode"&gt;            db.Delete&amp;lt;Region&amp;gt;(x =&amp;gt; x.RegionID == 6).Execute();&lt;/pre&gt;
&lt;p&gt;This next thing is what &lt;strong&gt;I consider to be a "Killer Feature" - a batch query&lt;/strong&gt; (or as NHibernate calls it, a "Future" query). One thing that always gets me about ORMs is having to manage the connections that it makes to a database. Wouldn't it be nice to lob a bunch of IQueryable queries into a batch querier and have it make only one call to the DB, in one execution step? If you think so, I have good news for you:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    db.Queue(from p &lt;span class="kwrd"&gt;in&lt;/span&gt; db.Products &lt;span class="kwrd"&gt;where&lt;/span&gt; p.CategoryID == 5 select p);
    db.Queue(from p &lt;span class="kwrd"&gt;in&lt;/span&gt; db.Products &lt;span class="kwrd"&gt;where&lt;/span&gt; p.CategoryID == 7 select p);
    db.Queue(from p &lt;span class="kwrd"&gt;in&lt;/span&gt; db.Products &lt;span class="kwrd"&gt;where&lt;/span&gt; p.CategoryID == 9 select p);
    IDataReader rdr=db.ExecuteBatch();
&lt;/pre&gt;
&lt;p&gt;With this release I've included a new "BatchQuery" class that takes either one of SubSonic's queries or an IQueryable query, parses the SQL and pulls out the parameters into one, big batched SQL statement. It then will execute as a pass-through, or return a multi-result set. Yes, I will do my best to support transactions this way in the future :).&lt;/p&gt;
&lt;p&gt;If you don't like working with DataReaders, never fear, one of the new members of SubSonic's Extension classes (DatabaseExtensions) has a new method for IDataReader called "ToList&amp;lt;T&amp;gt;()" - which will take a reader and shove the results into a "List&amp;lt;T&amp;gt;". &lt;/p&gt;
&lt;p&gt;So to complete this example (making sure to reference SubSonic.Extension.DatabaseExtensions):&lt;/p&gt;&lt;pre class="csharpcode"&gt;    db.Queue(from p &lt;span class="kwrd"&gt;in&lt;/span&gt; db.Products &lt;span class="kwrd"&gt;where&lt;/span&gt; p.CategoryID == 5 select p);
    db.Queue(from p &lt;span class="kwrd"&gt;in&lt;/span&gt; db.Products &lt;span class="kwrd"&gt;where&lt;/span&gt; p.CategoryID == 7 select p);
    db.Queue(from p &lt;span class="kwrd"&gt;in&lt;/span&gt; db.Products &lt;span class="kwrd"&gt;where&lt;/span&gt; p.CategoryID == 9 select p);

    List&amp;lt;Products&amp;gt; result1 = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
    List&amp;lt;Products&amp;gt; result2 = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
    List&amp;lt;Products&amp;gt; result3 = &lt;span class="kwrd"&gt;null&lt;/span&gt;;


    &lt;span class="kwrd"&gt;using&lt;/span&gt; (IDataReader rdr = qry.ExecuteReader()) {
        result1 = rdr.ToList&amp;lt;Products&amp;gt;();
        
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (rdr.NextResult())
            result2 = rdr.ToList&amp;lt;Products&amp;gt;();

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (rdr.NextResult())
            result3 = rdr.ToList&amp;lt;Products&amp;gt;();

    }&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;One SQL statement, one execution step, 3 typed lists. I like it :).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Believe it or not you probably shouldn't work "this close" to your database. This is where the 3rd tier comes in.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Implementation&lt;/strong&gt;&lt;br&gt;Hopefully you can see what I'm trying to do here - give YOU the power. By way of example I've created an IRepository&amp;lt;T&amp;gt; interface that's part of SubSonic:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;namespace&lt;/span&gt; SubSonic {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IRepository&amp;lt;T&amp;gt; {
    
            IQueryable&amp;lt;T&amp;gt; GetAll();
            PagedList&amp;lt;T&amp;gt; GetPaged(&lt;span class="kwrd"&gt;int&lt;/span&gt; pageIndex, &lt;span class="kwrd"&gt;int&lt;/span&gt; pageSize);
            IQueryable&amp;lt;T&amp;gt; Find(Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; expression);
            &lt;span class="kwrd"&gt;void&lt;/span&gt; Add(T item);
            &lt;span class="kwrd"&gt;int&lt;/span&gt; Update(T item);
            &lt;span class="kwrd"&gt;int&lt;/span&gt; Delete(T item);
            &lt;span class="kwrd"&gt;int&lt;/span&gt; Delete(&lt;span class="kwrd"&gt;object&lt;/span&gt; key);
            &lt;span class="kwrd"&gt;int&lt;/span&gt; Delete(Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; expression);
    
        }
    }
&lt;/pre&gt;
&lt;p&gt;One of the templates you'll see in the download below is "Repository.TT", which is an implementation of this interface that you can use right now if you like. One day I might make an ActiveRecord one as well - but for now you can use this code like this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;            NorthwindRepository&amp;lt;Region&amp;gt; repo = &lt;span class="kwrd"&gt;new&lt;/span&gt; NorthwindRepository&amp;lt;Region&amp;gt;();
            Region r = repo.Find(x =&amp;gt; x.RegionDescription == &lt;span class="str"&gt;"Hawaii"&lt;/span&gt;).SingleOrDefault();
            r.RegionDescription = &lt;span class="str"&gt;"Hawaii FIVE O"&lt;/span&gt;;
            repo.Update(r);&lt;/pre&gt;
&lt;p&gt;Again, one of my very favorites is "Delete":&lt;/p&gt;&lt;pre class="csharpcode"&gt;            NorthwindRepository&amp;lt;Region&amp;gt; repo = &lt;span class="kwrd"&gt;new&lt;/span&gt; NorthwindRepository&amp;lt;Region&amp;gt;);
            repo.Delete(x=&amp;gt;x.RegionID==6);
&lt;/pre&gt;
&lt;p&gt;You can also use the item, or a primary key:&lt;/p&gt;&lt;pre class="csharpcode"&gt;            repo.Delete(6);
            //OR
            Region r=repo.Find(x=&amp;gt;x.RegionID==6).SingleOrDefault();
            rept.Delete(r);
&lt;/pre&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;

&lt;p&gt;&lt;strong&gt;Let's Watch a Video!&lt;/strong&gt;&lt;br&gt;A lot of people have asked for a "Rob special" video, and not to disappoint I've created one to show you how to get started (props to whomever knows the tune). It's 4 minutes and covers how to use SubSonic 3.0 (and its templates) with a Console App. You can also use this with any other app EXCEPT for a Web Site - for some reason T4 doesn't like those:&lt;/p&gt;
&lt;p&gt;(Double-click for full screen, or you can &lt;a href="http://silverlight.services.live.com/58326/SubSonic%203%20Setup/video.wmv" target="_blank"&gt;download the WMV here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;iframe style="width: 650px; height: 450px" src="http://silverlight.services.live.com/invoke/58326/SubSonic%203%20Setup/iframe.html" frameborder="0" scrolling="no"&gt;&lt;/iframe&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Download&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.wekeroad.com/SubSonic3_P2.zip" target="_blank"&gt;You can download Preview 2 here&lt;/a&gt;. I've fixed/tweaked/changed a lot of stuff, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fixed an issue with Columns not generating. I think this was because I wasn't closing connections properly, and some databases were case-sensitive. I've tested this on 2008 and 2005 and it works well.&lt;/li&gt;
&lt;li&gt;Made every class Partial&lt;/li&gt;
&lt;li&gt;Changed tables from Fields to Properties&lt;/li&gt;
&lt;li&gt;Fixed a paging bug with the Linq translator&lt;/li&gt;
&lt;li&gt;Renamed some TT files. Provider has become "QuerySurface" and Connection.TT is now called "_Utility.tt".&lt;/li&gt;
&lt;li&gt;Renamed the no-code, required TT files to have underscore&lt;/li&gt;
&lt;li&gt;Implemented MANY of the changes &lt;a href="http://biasecurities.com/blog/2008/updated-subsonic-3-templates-version-1/" target="_blank"&gt;suggested in this post by jguerts&lt;/a&gt; (thanks!)&lt;br&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;As always- if you have any questions please let me know. If they're long ones, please email me at microsoft (robcon) or my full name at Gmail.&lt;/p&gt;
&lt;p&gt;Cheers!&lt;/p&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/RCONERY/ECB6F0D70360B2E2703C3B1EEB6E9928DDE8337D"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/RCONERY/ECB6F0D70360B2E2703C3B1EEB6E9928DDE8337D"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/wekeroad/EeKc?a=fE3IeF"&gt;&lt;img src="http://feeds.feedburner.com/~a/wekeroad/EeKc?i=fE3IeF" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=r9r3N"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=r9r3N" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=XISfn"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=XISfn" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=uKHON"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=uKHON" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/wekeroad/EeKc/~4/451358965" height="1" width="1"/&gt;</description><feedburner:origLink>http://blog.wekeroad.com/blog/subsonic-3-0-preview-2/</feedburner:origLink></item><item><title>SubSonic 3.0 Preview 1: Linq Has Landed</title><link>http://feeds.feedburner.com/~r/wekeroad/EeKc/~3/446115806/</link><pubDate>Sat, 08 Nov 2008 02:51:40 GMT</pubDate><guid isPermaLink="false">http://blog.wekeroad.com/blog/subsonic-3-0-preview-1-linq-has-landed/</guid><dc:creator>Rob Conery</dc:creator><slash:comments>0</slash:comments><category domain="http://blog.wekeroad.com/blog/">Blog</category><description>&lt;p&gt;I've been working a lot over the last few months on our next rev of SubSonic, and I think I have something that's good enough to issue as a preview. Please understand that this is a preview in every sense of the word, and may shatter into a zillion pieces and make you want to pour your Red Bull over my head. This is bleeding edge edge crazy talk. It's everything bad that wakes you up screaming at night, and quite possibly is the coolest thing I've ever made... or somewhere in between. Just know that if you download and play with it, you're in for a ride... maybe. Or maybe it will shine like a million suns at the dawn of man...&lt;/p&gt; &lt;p&gt;&lt;strong&gt;SubSonic 3.0 Is...&lt;br&gt;&lt;/strong&gt;A complete rewrite. The culmination of the things I've learned over the last year as I've (once again) &lt;img style="margin: 5px" height="182" alt="subferrari" src="http://blog.wekeroad.com/files/media/image/WindowsLiveWriter/SubSonic3.0Preview1_CF20/subferrari_15767f5f-6547-42d2-bb2d-7888aec6c3be.jpg" width="340" align="right" border="0"&gt;Changed Everything and shared some wonderful Koolaid with my Alt.NET buddies :). Seriously - I've ripped everything out and redone it, with a focus on:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Simpler&lt;/li&gt; &lt;li&gt;Lighter&lt;/li&gt; &lt;li&gt;Simpler&lt;/li&gt; &lt;li&gt;Meaner&lt;/li&gt; &lt;li&gt;Simpler&lt;/li&gt; &lt;li&gt;Better&lt;/li&gt; &lt;li&gt;Faster&lt;/li&gt; &lt;li&gt;Simpler&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;(Not in that order - but generally I've placed an emphasis on simplicity). I've installed interfaces everywhere, and focused on making everything lightweight, testable, and injectable. I hope. We'll see.&lt;/p&gt; &lt;p&gt;Overall I've had exactly 5 false starts. I literally have 6 folders on my hard drive right now, each named "SubSonic 3.0 [X]" where "X" is the iteration number. Sometimes it's a swear word - but I won't go there now. Linq is hard - &lt;a href="http://ayende.com/Blog/archive/2008/11/01/developing-linq-to-nhibernate.aspx" target="_blank"&gt;no really - just ask Ayende.&lt;/a&gt; It's not a matter of smarts - it's just really hard to try to fit Linq in... trust me. I was hoping originally that I could just create an Expression parser and build stuff using our core bits... but umm... that didn't happen. &lt;/p&gt; &lt;p&gt;One of the blogger people I've been following as I've been working through all of this is Matt Warren, the Zeus of Linq To Sql. He has &lt;a href="http://blogs.msdn.com/mattwar/archive/2008/07/14/linq-building-an-iqueryable-provider-part-xi.aspx" target="_blank"&gt;a great series of posts&lt;/a&gt; on how to implement IQueryable, and when he got to post number 9 I began to think I should just use his code wholesale (yes, I know it's cheap of me). He's now on post number 11, and I asked him a while back if I could just steal all of his code - and this is why Matt Warren is my personal Santa Claus - he said "yes - it's all under MS-PL anyway. Just forward the license".&amp;nbsp; &lt;/p&gt; &lt;p&gt;So there it is - the SubSonic.Linq namespace is 99.999999% Matt Warren's code. I've tweaked it a touch to work with our core Query stuff, but everything else is him and his large brain. Thank him for this and &lt;a href="http://blogs.msdn.com/mattwar/archive/2008/07/14/linq-building-an-iqueryable-provider-part-xi.aspx" target="_blank"&gt;have a read on what you get&lt;/a&gt; with this provider.&lt;/p&gt; &lt;p&gt;My philosophy while developing SubSonic 3.0 is this:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;I really dig Linq as a language feature - I want to include it as a query tool&lt;/li&gt; &lt;li&gt;I don't like all the extra "shmekt" that we have right now for things like Code Generation and figuring out how to rename bad table names&lt;/li&gt; &lt;li&gt;I want to change our Provider Model - this can be much simpler&lt;/li&gt; &lt;li&gt;I want to give you a lot more power to make code you want to use&lt;/li&gt; &lt;li&gt;I want to use POCOs&lt;/li&gt; &lt;li&gt;I want Linq to work where it should, SubSonic to work where it should, and seemlessly make them work together&lt;/li&gt; &lt;li&gt;If I do this right, you can build on top of SubSonic, to do what YOU want to do.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;There it is. &lt;strong&gt;And I want it to be stupid simple&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;SubSonic 3.0 Is Not...&lt;/strong&gt;&lt;br&gt;I think this is as important as what I want to do. So, what I don't want to do is:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Take over as the new Linq To Sql. I know this is weird timing, given the latest grumblings happening in .NET space, but believe me Linq is scarey, and translating Expressions to SQL is not easy. It's really, really hard (see below) and if I didn't like Linq so much (and IQueryable) I would have kicked it to the curb.&lt;/li&gt; &lt;li&gt;Create another ORM. SubSonic's not an ORM believe it or not. There is no "mapping" ability really - I spose you can say it's "ORM-y". It's a data access tool for sure - I'll leave the mapping to you, which is why I decided to use Linq cause it makes is very simple.&lt;/li&gt; &lt;li&gt;Suggest in any way that we're done. There's some work to do here :) so this is for you to play with sort of like a sleeping cat (which could scratch you) or a pocket full of kryptonite. It's preview and may splode.&lt;/li&gt; &lt;li&gt;Backwards Compatible. Yes I know this will bum a lot of people out but it's the only way I can really rev this thing properly. Eric and I stressed over this, but the issue is that language/tooling features are letting us do something completely different and if it helps trim the API, bloat, and footprint than that's what we do. Very sorry about this.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Onward! To Some Code!&lt;/p&gt; &lt;p&gt;&lt;strong&gt;The Setup&lt;br&gt;&lt;/strong&gt;To use SubSonic 3.0 you'll need to do exactly 3 things (assuming you're using .NET 3.5, which is required):&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Create project references to SubSonic, System.Data, and System.Core (if you don't have it already)&lt;/li&gt; &lt;li&gt;Make sure you have a connection string (at least one), with the providerName set appropriately (usually it's System.Data.SqlClient)&lt;/li&gt; &lt;li&gt;Drop in the T4 templates, edit the connection string in "Connection.tt", and watch it generate your action.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;No providers, no funkiness. That's it! &lt;/p&gt; &lt;p&gt;&lt;strong&gt;Generated Code&lt;br&gt;&lt;/strong&gt;There are fiveT4 templates as of right now (this will probably change), and they are:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;Connection.tt - this is a non-code template (utility) that gets included with the other templates and does things like connect to your DB to get a list of tables and SPs, etc.&lt;/li&gt; &lt;li&gt;Classes.tt - this T4 template generates 1 class per table in your DB using POCOs&lt;/li&gt; &lt;li&gt;Provider.tt - this class wraps your Database in a class and adds IQueryable&amp;lt;T&amp;gt; fields as well as some factory methods for SubSonic queries (more below).&lt;/li&gt; &lt;li&gt;SPs.tt - wraps your Stored Procedures and "appends" them to your provider class so you can call them as methods&lt;/li&gt; &lt;li&gt;Structs.tt - wraps the columns and tables in your database so you can refer to them without using strings.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;There's a lot more you can do here - and that leads me to the next thought...&lt;/p&gt; &lt;p&gt;&lt;strong&gt;This Aint No ORM Disco&lt;/strong&gt;&lt;br&gt;The "Big Guy" ORMs (NHibernate, EF, Linq To Sql) keep track of an object's state and interacts with the DB in what's known as a "Unit of Work". This can be great sometimes, a PITA others. I've realized that ORMs are a slippery slope in this regard, and no one can really agree on what they should really do, when, and why.&lt;/p&gt; &lt;p&gt;So I've decided to focus one step below and try to make data access and manipulation silly simple. That way, in the future, maybe I (or you!) can work up some cool ORM templates to sit on top of the core SubSonic bits, and we can all share and have a party.&lt;/p&gt; &lt;p&gt;Just know that my focus, for right now, is to make working with the DB bloody crazy simple. The more complicated stuff can come later (eager loading, unit of work, etc) in the form of T4 templates.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Enough Already - Show Me Some Code!&lt;/strong&gt;&lt;br&gt;The meat of the system is worked up by Provider.tt. This is a "wrapper" for your database and allows you to work with IQueryable and SubSonic at the same time:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; Northwind{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; DB{
    
        &lt;span class="kwrd"&gt;public&lt;/span&gt; IDataProvider DataProvider = &lt;span class="kwrd"&gt;new&lt;/span&gt; DbDataProvider(&lt;span class="str"&gt;"Northwind"&lt;/span&gt;);
        &lt;span class="kwrd"&gt;public&lt;/span&gt;  DbQueryProvider provider;

        &lt;span class="kwrd"&gt;public&lt;/span&gt; Query&amp;lt;CustomerDemographics&amp;gt; CustomerDemographics;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Query&amp;lt;Region&amp;gt; Region;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Query&amp;lt;Employees&amp;gt; Employees;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Query&amp;lt;Categories&amp;gt; Categories;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Query&amp;lt;Customers&amp;gt; Customers;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Query&amp;lt;Shippers&amp;gt; Shippers;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Query&amp;lt;Suppliers&amp;gt; Suppliers;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Query&amp;lt;EmployeeTerritories&amp;gt; EmployeeTerritories;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Query&amp;lt;Order_Details&amp;gt; Order_Details;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Query&amp;lt;CustomerCustomerDemo&amp;gt; CustomerCustomerDemo;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Query&amp;lt;Territories&amp;gt; Territories;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Query&amp;lt;Orders&amp;gt; Orders;
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Query&amp;lt;Products&amp;gt; Products;        
        
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Select Select() {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Select(DataProvider);
        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Insert Insert() {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Insert(DataProvider);
        }        
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Update&amp;lt;T&amp;gt; Update&amp;lt;T&amp;gt;() &lt;span class="kwrd"&gt;where&lt;/span&gt; T:&lt;span class="kwrd"&gt;new&lt;/span&gt;(){
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Update&amp;lt;T&amp;gt;(DataProvider);
        }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Delete Delete(){
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; Delete(DataProvider);
        }
&lt;/pre&gt;
&lt;p&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;
There's more that's generated here - but I'll get to that in a second. To use IQueryable, you do what you normally do with Linq To Sql:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    Northwind.DB db = &lt;span class="kwrd"&gt;new&lt;/span&gt; Northwind.DB();
    var products = from p &lt;span class="kwrd"&gt;in&lt;/span&gt; db.Products
                   &lt;span class="kwrd"&gt;where&lt;/span&gt; p.CategoryID == 5
                   select p;
    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var p &lt;span class="kwrd"&gt;in&lt;/span&gt; products) {
        Console.WriteLine(p.ProductName);
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;

&lt;p&gt;Which produces what you might think (using delayed execution):&lt;/p&gt;
&lt;p&gt;&lt;img style="margin: 5px" height="114" alt="results1" src="http://blog.wekeroad.com/files/media/image/WindowsLiveWriter/SubSonic3.0Preview1_CF20/results1_659c9144-7cd7-4b1d-9c28-8f6fd75d8150.png" width="292" border="0"&gt; &lt;/p&gt;
&lt;p&gt;Nothing really extraordinary about this - we've seen it before :). Most things are covered using the Linq provider that Matt started, but I'm sure there are some things missing - the good news there is that you have SubSonic's query tool to back you up if you get stuck (which is a lot of fun since you're not locked into one way of doing things now):&lt;/p&gt;&lt;pre class="csharpcode"&gt;    var products2 = db.Select.From&amp;lt;Northwind.Products&amp;gt;()
        .Where(Northwind.ProductsTable.CategoryID)
        .IsEqualTo(5)
        .ExecuteTypedList&amp;lt;Northwind.Products&amp;gt;();
&lt;/pre&gt;
&lt;p&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;
&lt;em&gt;Note that you can also just use a string in the Where() statement.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;And if you really get stuck, we've got your back so you can avoid all of the "Proprietary Object Noise" (with apologies to Jeff Atwood):&lt;/p&gt;&lt;pre class="csharpcode"&gt;    var products3 = &lt;span class="kwrd"&gt;new&lt;/span&gt; CodingHorror(&lt;span class="str"&gt;"SELECT * FROM Products WHERE CategoryID=@id"&lt;/span&gt;, 5)
        .ExecuteTypedList&amp;lt;Northwind.Products&amp;gt;();
    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var p &lt;span class="kwrd"&gt;in&lt;/span&gt; products2) {
        Console.WriteLine(p.ProductName);
    }
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;I Like Lambdas&lt;/strong&gt;&lt;br&gt;I've tried to rethink everything in terms of how the bits are put together so we can flex the changes in the language. To that end I've included lambdas where appropriate to add some type-safety etc. I know some people don't like em, but they're optional, as always.&lt;/p&gt;&lt;pre class="csharpcode"&gt;    db.Insert.Into&amp;lt;Northwind.Region&amp;gt;(x =&amp;gt; x.RegionID, x =&amp;gt; x.RegionDescription)
        .Values(6, &lt;span class="str"&gt;"Hawaii"&lt;/span&gt;).Execute();&lt;/pre&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;
&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;object&lt;/span&gt; avg = db.Avg&amp;lt;Northwind.Products&amp;gt;(x =&amp;gt; x.ProductID);
&lt;/pre&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;

&lt;p&gt;The latter example here is why I love lambdas so much - they can (if implemented properly) "terse up" your code nicely. You could use Linq on db.Products for this as well - but I like the terseness of this one line :).&lt;/p&gt;
&lt;p&gt;All of our aggregates are now reachable from the db wrapper class:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    db.Avg&amp;lt;Northwind.Products&amp;gt;(x =&amp;gt; x.ProductID);
    db.Sum&amp;lt;Northwind.Products&amp;gt;(x =&amp;gt; x.ProductID);
    db.Count&amp;lt;Northwind.Products&amp;gt;(x =&amp;gt; x.ProductID);
    db.Min&amp;lt;Northwind.Products&amp;gt;(x =&amp;gt; x.ProductID);
    db.Max&amp;lt;Northwind.Products&amp;gt;(x =&amp;gt; x.ProductID);
    db.Variance&amp;lt;Northwind.Products&amp;gt;(x =&amp;gt; x.ProductID);
    db.StandardDeviation&amp;lt;Northwind.Products&amp;gt;(x =&amp;gt; x.ProductID);&lt;/pre&gt;
&lt;p&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;
The best part is that if you don't like any of this, just change your template! It's all right there for you to tweak and alter to fit your project, which is a major goal of mine here: I want to give you the power to use SubSonic as you please. And if you do it better than us (which I'm sure you will) - perhaps you'll share. My focus is on the engine - you guys can hop it up with chrome and neon.&lt;/p&gt;
&lt;p&gt;The biggest support issue we've had is with regards to our generated stuff. Specifically how we name objects. Our code generation is now completely transparent so if you don't like it - you can change the name of that table to be what you like!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Using System.Data.Common&lt;/strong&gt;&lt;br&gt;At the core of the flexibility we now have is our use of System.Data.Common and the DataFactory pattern. If you don't know what this is, &lt;a href="http://msdn.microsoft.com/en-us/library/t9f29wbk.aspx" target="_blank"&gt;have a read here&lt;/a&gt;. The idea behind System.Data.Common is that we shouldn't have to rewrite all of our data access stuff if we happen to change database platforms. To that end the DataFactory pattern was created so that ADO data provider developers could write against a common API, and you could benefit.&lt;/p&gt;
&lt;p&gt;We've used that to our advantage with SubSonic 3.0. So if you need to switch your DB provider, for instance, you can change from this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;connectionStrings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="Northwind"&lt;/span&gt; &lt;br&gt;        &lt;span class="attr"&gt;connectionString&lt;/span&gt;&lt;span class="kwrd"&gt;="server=.\SQLExpress;Integrated Security=true;database=northwind;"&lt;/span&gt; 
        &lt;span class="attr"&gt;providerName&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Data.SqlClient"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;connectionStrings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;

&lt;p&gt;To this (provided you have the DLL in your /bin):&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;connectionStrings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="Northwind"&lt;/span&gt; &lt;br&gt;        &lt;span class="attr"&gt;connectionString&lt;/span&gt;&lt;span class="kwrd"&gt;="server=localhost;user id=root;pwd=HAHA?;database=northwind;"&lt;/span&gt; 
        &lt;span class="attr"&gt;providerName&lt;/span&gt;&lt;span class="kwrd"&gt;="MySql.Data.MySqlClient"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;connectionStrings&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;

&lt;p&gt;There is no other setting - no "provider tweaks", no jiggity dances and prayers. The only assumption here is that you have the same DB on your target platform (which I do - I've ported Northwind to MySQL) and run:&lt;/p&gt;
&lt;p&gt;&lt;img style="margin: 5px" height="211" alt="results2" src="http://blog.wekeroad.com/files/media/image/WindowsLiveWriter/SubSonic3.0Preview1_CF20/results2_a2bb5bfc-e6cb-450c-ba7e-d82318bd7e6e.gif" width="440" border="0"&gt; &lt;/p&gt;
&lt;p&gt;Most database providers support ADO.NET 2.0 and the Data Factory. Some off the top of my head that I know of are MySQL, Oracle, and SqlLite and I'm sure there are others - I just don't know.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://wekeroad.com/SubSonic3_P1.zip" target="_blank"&gt;You can download SubSonic 3.0, Preview 1 here.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We're still actively working on it and I'm sure you'll encounter bugs, etc. Feel free to send me an email (see the README) and please try to let me know what you were doing in the context of Northwind, so I can repro the issue.&lt;/p&gt;
&lt;p&gt;As always, please be patient.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Epilogue: SubSonic.Sugar is now SubSonic.Extensions&lt;/strong&gt;.&lt;br&gt;Wanna have some fun? Have a look at the SubSonic.Extension methods that I've ported from the Sugar class and turned into applicable extensions. To use them, you'll need to make sure you reference the appropriate namespace:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;using&lt;/span&gt; SubSonic.Extensions.Strings;
    &lt;span class="kwrd"&gt;using&lt;/span&gt; SubSonic.Extensions.Dates;
    &lt;span class="kwrd"&gt;using&lt;/span&gt; SubSonic.Extensions.Files;
    &lt;span class="kwrd"&gt;using&lt;/span&gt; SubSonic.Extensions.Linq;
    &lt;span class="kwrd"&gt;using&lt;/span&gt; SubSonic.Extensions.Numbers;
    &lt;span class="kwrd"&gt;using&lt;/span&gt; SubSonic.Extensions.Objects
    &lt;span class="kwrd"&gt;using&lt;/span&gt; SubSonic.Extensions.Validation;&lt;/pre&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;

&lt;p&gt;In there is some fun, and some damn handy utilities. Things like Date math, file creation and text loading, string pluralization, regex validation and matching (Validation's "Is" functions rock - things like "IsValidEmail" and "IsCreditCard" are super groovy).&lt;/p&gt;
&lt;p&gt;I mention them last as they are, literally, sugar utilities to help you through your day, and help us with SubSonic. They're not the main point at all.&lt;/p&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/RCONERY/4549E828CD469F4484D9171C801D23E1C7279657"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/RCONERY/4549E828CD469F4484D9171C801D23E1C7279657"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/wekeroad/EeKc?a=9A73C0"&gt;&lt;img src="http://feeds.feedburner.com/~a/wekeroad/EeKc?i=9A73C0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=HBFwN"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=HBFwN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=kCRpn"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=kCRpn" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=E7AbN"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=E7AbN" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/wekeroad/EeKc/~4/446115806" height="1" width="1"/&gt;</description><feedburner:origLink>http://blog.wekeroad.com/blog/subsonic-3-0-preview-1-linq-has-landed/</feedburner:origLink></item><item><title>One Year At Microsoft</title><link>http://feeds.feedburner.com/~r/wekeroad/EeKc/~3/441794555/</link><pubDate>Tue, 04 Nov 2008 06:38:04 GMT</pubDate><guid isPermaLink="false">http://blog.wekeroad.com/blog/one-year-at-microsoft/</guid><dc:creator>Rob Conery</dc:creator><slash:comments>0</slash:comments><category domain="http://blog.wekeroad.com/blog/">Blog</category><description>&lt;p&gt;I just got my notice that it's been one year here at the Blue Monster. Interesting, that. It's made me think about a lot of things with respect to my job - probably some things a typical one-year blue badge might not think. &lt;/p&gt; &lt;p&gt;&lt;strong&gt;My Boss Is a Rock Star&lt;br&gt;&lt;/strong&gt;This is probably the biggest surprise for me. No, I'm not sucking up, though it may seem that way. I&lt;img style="margin: 5px" height="255" alt="ironman_l" src="http://blog.wekeroad.com/files/media/image/WindowsLiveWriter/OneYearAtMicrosoft_120FB/ironman_l_03715fad-241a-4985-977d-7c877bacc02b.jpg" width="340" align="right" border="0"&gt;t's just not... me to suck up to anyone :) and it's one reason I really like &lt;a href="http://blogs.msdn.com/sburke/" target="_blank"&gt;Shawn&lt;/a&gt; :).&amp;nbsp; There are no "brown-nose" the boss kind of games with him, no power trips and no weird ego games. Hands-down he's the best boss I've ever worked for and believe it or not I didn't expect it when I was hired. Not because of him - but because of the caliber of people that Microsoft hires.&lt;/p&gt; &lt;p&gt;And he runs Iron Mans and is one hell of an athlete. I thought he'd be one of "those guys" - you know the super-athletic boss guys who eat rice cakes and don't drink and think video games are for fat girly-men. He's not any of those and, it turns out, I have less body-fat than he does - isn't that strange? :).&lt;/p&gt; &lt;p&gt;During my interview we had a very thoughtful conversation that roamed from Fibonacci numbers, to Kona Iron Mans, and then off to Public Enemy songs. I was pleasantly surprised to find that not only was Shawn a very engaging person, but he was really into what I wanted to do at Microsoft, and why. I don't know why I find that weird (in a good way). Turns out that most other people have a similar experience with their managers - and that's just the way it is there. I think that's groovy.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Culture as Concept&lt;br&gt;&lt;/strong&gt;I work remotely, at my home office, and I don't get to involve myself regularly in the "cultural" things that happen at the company. Sometimes this is a good thing - other times it's bad. I'm able to retain the sense of "who I am" and really feel like I have my own voice. Other times I really feel like I'm missing out.&lt;/p&gt; &lt;p&gt; The neat things is that all I have to do is remote in to the network and cruise &lt;img style="margin: 5px" height="423" alt="xkcdEffect" src="http://blog.wekeroad.com/files/media/image/WindowsLiveWriter/OneYearAtMicrosoft_120FB/xkcdEffect_85d88756-6d0b-45ae-99e2-6d985ee827bf.png" width="340" align="left" border="0"&gt; the intranet, or start up an IM with my compadres. Video conversations are easy, and everyone will make time to chat with you - even if they have no idea who you are.&lt;/p&gt; &lt;p&gt;Right now I'm working on getting an old computer setup in Phil's office with a permanent vide feed to my desk here. That way I'll be Phil's virtual office-mate and any time someone wants to drop by, they can. Seriously!&lt;/p&gt; &lt;p&gt;I get to fly out to Redmond every other month and every time I'm there I can't believe I work for a company that's this open, this exciting, and this much fun. Yes, the Koolaid is lovely, thank you. Believe it or not I actually mean this :).&lt;/p&gt; &lt;p&gt;Seriously, there is so much going on at a given time - so many decisions and ideas and personalities - that I literally giggle every time I swipe my badge at Building 42.&lt;/p&gt; &lt;p&gt;A feeling of smallness takes you over - seriously. I'm not an egotist and I hope you don't think I'm sitting here trying to name-drop, but it's really how I feel. Walking by a nameplate that says "Scott Guthrie" and having him wave as you walk by is ... well it's ridiculous. And it makes me laugh.&lt;/p&gt; &lt;p&gt;If I was there every day I might get used to it - rubbing shoulders with guys like ScottGu, Nikhil, Brad Abrams, Phil, and especially Eilon. But I'm not - so when I visit I feel like a kid visiting his big brothers off at college...&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Contributing&lt;/strong&gt;&lt;br&gt;Microsoft has a really cool way of allowing you to do what you do - it's called "here's your rope, how much you want?". I was told shortly after I was hired to "tell, don't ask and see if it flies" - and that's what I've been doing. Most everyone is receptive, but I've found that they look to you to just do what you do, and excel as you see fit. There is no "well let's see what so and so says" - they kind of want to see results first. If you fail - which I've done - people are quick to pull together to find out what went wrong and how to fix it.&lt;/p&gt; &lt;p&gt;I love that. I know that a lot of companies work that way - I've just never experienced it. Success and Failure usually means attribution to your boss in some form, and also making sure you align it with his boss's stuff - your typical Survivor politics. &lt;img style="margin: 5px" height="253" alt="Cat3IF1203_468x324" src="http://blog.wekeroad.com/files/media/image/WindowsLiveWriter/OneYearAtMicrosoft_120FB/Cat3IF1203_468x324_a8d9346c-f804-411b-843d-b29494fa482b.jpg" width="340" align="right" border="0"&gt;That doesn't work here, and I'm grateful for it.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Assessment&lt;br&gt;&lt;/strong&gt;I feel like I've done well my first year. It's not an easy company to work for and that's not because of any weird authoritarian management policy or ticking off goals on a list. As I've mentioned -&amp;nbsp; it's 100% up to me to succeed or fail, and I have to what it takes, completely, to navigate the waters and succeed.&lt;/p&gt; &lt;p&gt;What makes this particularly challenging is that I'm working with guys like Hanselman and Brad Wilson. Jon Lam, Jesse Liberty and Glenn Block. Eilon Lipton! People I greatly respect and whom I have to measure myself against (how do you do that?). I don't come to confidence easy, and I have a really hard time telling myself I belong here. But here I am indeed, and it's "do, or do not - there is no try". &lt;/p&gt; &lt;p&gt;I can safely say it's the best job I've ever had. You might have your opinions on my being "borged" and that's OK. I like the challenge. Ask Phil sometime how "borged" I am :), he'll tell you that I've passed my Koolaid off to him :).&lt;/p&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/RCONERY/258837999FDBFC7E2022BD1D32B07B4A95BDE850"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/RCONERY/258837999FDBFC7E2022BD1D32B07B4A95BDE850"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/wekeroad/EeKc?a=dSnC04"&gt;&lt;img src="http://feeds.feedburner.com/~a/wekeroad/EeKc?i=dSnC04" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=7KBYN"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=7KBYN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=zFX7n"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=zFX7n" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=QfvuN"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=QfvuN" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/wekeroad/EeKc/~4/441794555" height="1" width="1"/&gt;</description><feedburner:origLink>http://blog.wekeroad.com/blog/one-year-at-microsoft/</feedburner:origLink></item><item><title>Crazy Talk: Reducing ORM Friction</title><link>http://feeds.feedburner.com/~r/wekeroad/EeKc/~3/441648793/</link><pubDate>Tue, 04 Nov 2008 03:08:28 GMT</pubDate><guid isPermaLink="false">http://blog.wekeroad.com/blog/crazy-talk-reducing-orm-friction/</guid><dc:creator>Rob Conery</dc:creator><slash:comments>0</slash:comments><category domain="http://blog.wekeroad.com/blog/">Blog</category><description>&lt;p&gt;Let's get this out of the way: I know you're going to think I'm nuts as you read this. You may "pfft" to what you're about to read - know that I know you're "pfft"-ing me. All I ask is that you consider what I'm about to suggest...&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Development Friction&lt;img height="218" alt="orm-d900" src="http://blog.wekeroad.com/files/media/image/WindowsLiveWriter/CrazyTalkEliminatingORMCoDependency_D713/orm-d900_ebfb1535-e17c-46cd-b46f-d2085f97d091.jpg" width="274" align="right" border="0"&gt;&lt;/strong&gt;&lt;br&gt;The term "friction" gets thrown around a lot in terms of development. It's what it sounds like: something you do or a process you undertake that slows you down as you crank out code. If you think on this for a second - &lt;strong&gt;when you're building an application what's the number one thing that slows you down&lt;/strong&gt; (technically speaking. &lt;a href="http://stevenharman.net/" target="_blank"&gt;Running out of Red Bull&lt;/a&gt; doesn't count)?&lt;/p&gt; &lt;p&gt;For me it's the database "stuff". It's why I made SubSonic - I was tired of thinking about it and I wanted something faster and easier.&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;Tangent&lt;/strong&gt;&lt;br&gt;This whole post (and thing I'm about to dive into) was dreamt up during a bike ride to the store. I thought a fun post idea was to "send a post back in time" and entitle it "Greetings from the Year 2012", and I would laugh at all the silly stuff I did in 2008. The top of that list, for me, is the continuing struggle we have with persisting data "properly". After 10+ years, the marriage of web and database is still arguing over the same old stuff. Can't we move on? Shouldn't this be easier by now?&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;You might have other sources of friction, or you might be saying "&lt;strong&gt;dude [MY ORM] roolz! LOLZ at U&lt;/strong&gt;". I'll bet it does - but you still need to work with it (and your database) as you build out your site. Even if it takes you 1 minute to "update and regen" - you still have to mess with the DB and mess with mapping (if you do that). &lt;/p&gt; &lt;p&gt;I've talked with a lot of people over the last few weeks about this and &lt;strong&gt;asked them the same question&lt;/strong&gt;:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;strong&gt;In 5 years what do you think will finally be changed?&lt;/strong&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;strong&gt;The answer&lt;/strong&gt;, every single time, is a variation on "&lt;strong&gt;ORM's will finally work properly&lt;/strong&gt;". What if I told you that &lt;strong&gt;you don't need to wait for 5 years for this&lt;/strong&gt;? What if I told you to ditch your ORM and your database and focus on what's the most important thing: your application?&lt;/p&gt; &lt;p&gt;&lt;strong&gt;How Do You Do What You Do?&lt;/strong&gt;&lt;br&gt;There are generally two camps of developers:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;The guys who create a database and then build the app, and then update the database, and then change the app, etc.&lt;/li&gt; &lt;li&gt;The guys who write tests, create a model, update their database and remap their ORM, rinse and repeat.&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;If you're a TDD fan (or want to be) you might be interested in Domain-Driven Development (DDD). Yes, it's another one of those buzz-words but you might actually be a DDD person right now, and not even know it. Check it out:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;"What it's all about is creating as simple a model as possible, one that still captures what's important for the domain of the application. During development the process could really be described as knowledge-crunching by the developers and domain experts together. The knowledge that is gained is put into the model."&lt;br&gt;(Nilsson, Applying Domain-driven Design and Patterns)&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;strong&gt;&lt;img height="320" alt="skull_of_orm" src="http://blog.wekeroad.com/files/media/image/WindowsLiveWriter/CrazyTalkEliminatingORMCoDependency_D713/skull_of_orm_6aae7d6f-5ebf-4c19-844b-2b119f7b517f.jpg" width="234" align="left" border="0"&gt;&lt;/strong&gt;Yes, I'm quoting a DDD book. I've been absorbed :). The point here is that most of us have always worked this way - working closely with clients to understand their business, and making sure what we build is focused.&lt;/p&gt; &lt;p&gt; The split comes in with what system you work from: the database or the tests? Which is more appropriate in terms of building out an application domain? I'm hoping to convince you, today, to toss your database as you don't need it. Not yet anyway. Focus on your tests and your domain and I think you'll see that you can move a lot faster.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Database YAGNI (or the Database as a Feature)&lt;/strong&gt;&lt;br&gt;&lt;a href="http://c2.com/xp/YouArentGonnaNeedIt.html" target="_blank"&gt;YAGNI is the principle of "You Aint Gonna Need It",&lt;/a&gt; which essentially means "don't add it unless requirements/testing make you add it" and is one of the main drivers of TDD. It keeps code light and manageable, and keeps cruft out of your application. &lt;/p&gt; &lt;p&gt;I think this should apply to architectures as well - why implement, design, and build a database (with data access code) when the application doesn't need it? And yes, this is where the Crazy Talk kicks in.&lt;/p&gt; &lt;p&gt;&amp;lt;CrazyTalk&amp;gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;Databases are pretty heavy information organization and retrieval systems. Even the lighter-weight ones are capable of powering some pretty high-level querying at very rapid speeds.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;Do you need this when you're developing? Do you need to play "ORM-Catch up"? Probably not.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;What if, in 10 years, the platform could just translate your model for you and save it properly without you thinking about it?&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;What if I told you that you can do that now? Well you can - and this is where you're gonna say "PFFT" and tell me I'm crazy. But as I said - I know you're going to say it... so just pretend I can hear you...&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&amp;lt;/CrazyTalk&amp;gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;Off The Reservation with OODBs&lt;br&gt;&lt;/strong&gt;&lt;a href="http://en.wikipedia.org/wiki/ODBMS" target="_blank"&gt;Object Databases&lt;/a&gt; have been around for a long, long time. If you've never heard of these things, well they basically crumple your object up into binary (by serialization) and save it to disk for you to access later. If you'd like to read more, &lt;a href="http://www.kuro5hin.org/?op=displaystory;sid=2001/5/3/32853/11281" target="_blank"&gt;this is a great post on OODBs, what they are, and how they work&lt;/a&gt;. To summarize:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;An OODBMS is the result of combining object oriented programming principles with database management principles. Object oriented programming concepts such as encapsulation, polymorphism and inheritance are enforced as well as database management concepts such as the &lt;/em&gt;&lt;a href="http://www.orafaq.com/glossary/faqglosa.htm"&gt;&lt;em&gt;ACID properties&lt;/em&gt;&lt;/a&gt;&lt;em&gt; (Atomicity, Consistency, Isolation and Durability) which lead to system integrity, support for an ad hoc query language and secondary storage management systems which allow for managing very large amounts of data. The Object Oriented Database Manifesto [Atk 89] specifically lists the following features as mandatory for a system to support before it can be called an OODBMS; &lt;/em&gt;&lt;a href="http://www.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/node3.html#SECTION00021000000000000000"&gt;&lt;em&gt;Complex objects&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a href="http://www.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/node4.html#SECTION00022000000000000000"&gt;&lt;em&gt;Object identity&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a href="http://www.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/node5.html#SECTION00023000000000000000"&gt;&lt;em&gt;Encapsulation&lt;/em&gt;&lt;/a&gt;&lt;em&gt; , &lt;/em&gt;&lt;a href="http://www.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/node6.html#SECTION00024000000000000000"&gt;&lt;em&gt;Types and Classes&lt;/em&gt;&lt;/a&gt;&lt;em&gt; ,&lt;/em&gt;&lt;a href="http://www.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/node7.html#SECTION00025000000000000000"&gt;&lt;em&gt;Class or Type Hierarchies&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a href="http://www.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/node8.html#SECTION00026000000000000000"&gt;&lt;em&gt;Overriding,overloading and late binding&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt;&lt;a href="http://www.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/node9.html#SECTION00027000000000000000"&gt;&lt;em&gt;Computational completeness&lt;/em&gt;&lt;/a&gt;&lt;em&gt; , &lt;/em&gt;&lt;a href="http://www.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/node10.html#SECTION00028000000000000000"&gt;&lt;em&gt;Extensibility&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a href="http://www.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/node11.html#SECTION00029000000000000000"&gt;&lt;em&gt;Persistence&lt;/em&gt;&lt;/a&gt;&lt;em&gt; , &lt;/em&gt;&lt;a href="http://www.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/node12.html#SECTION000210000000000000000"&gt;&lt;em&gt;Secondary storage management&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a href="http://www.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/node13.html#SECTION000211000000000000000"&gt;&lt;em&gt;Concurrency&lt;/em&gt;&lt;/a&gt;&lt;em&gt;, &lt;/em&gt;&lt;a href="http://www.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/node14.html#SECTION000212000000000000000"&gt;&lt;em&gt;Recovery&lt;/em&gt;&lt;/a&gt;&lt;em&gt; and an &lt;/em&gt;&lt;a href="http://www.cs.cmu.edu/People/clamen/OODBMS/Manifesto/htManifesto/node15.html#SECTION000213000000000000000"&gt;&lt;em&gt;Ad Hoc Query Facility&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;&lt;strong&gt;Here's my thought for you: What if you used an OODB for development ONLY and implemented SQL Server later, when you know what you need to create.&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;You can't ditch your RDBMS entirely - never. However I will suggest that &lt;strong&gt;working on two systems at once&lt;/strong&gt;, when you don't need to, &lt;strong&gt;is silly&lt;/strong&gt;. You can do a lot more in terms of RAD development right now - and port to SQL later.&lt;/p&gt; &lt;p&gt;Doesn't it make more sense to create the database when, and only when, you need it? Hold that thought - I'm coming back to it.&lt;/p&gt; &lt;p&gt;&lt;strong&gt;DB4O - A Free OSS Object Database&lt;br&gt;&lt;/strong&gt;I've been using DB4O a lot over the last few months and I really like it. The tutorials are very easy and getting up to speed is no problem at all. First, however, I'd like to go over some things you might be wondering about.&lt;/p&gt; &lt;p&gt;Let's say I have three objects in my model:&lt;/p&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Product {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; Supplier Supplier { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; IList&amp;lt;Review&amp;gt; Reviews { get; set; }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Review {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; AuthorEmail { get; set; }
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Body { get; set; }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Supplier {
        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Name { get; set; }

    }&lt;/pre&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;

&lt;p&gt;You might be wondering about how these objects are persisted, and how integrity might be enforced. It's actually required that they enforce many of the same concepts as an RDBMS so that you don't make a mess out of your model storage.&lt;/p&gt;
&lt;p&gt;For instance, if I create a Supplier for a Product, it will be stored as an independent Supplier that I can then assign to another Product. If I change that Supplier's name, it will get changed for both. It's a single object, and the OODB works with the idea of "pointers" in the same way that a regular database does. The thing here, however, is that there is no joining - the relationships implicit and understood. In this way, an OODB can actually (and often do) outperform their RDBMS counterparts.&lt;/p&gt;
&lt;p&gt;But I'm not here to talk about &lt;strong&gt;perf and scaling - it doesn't matter for what I'm suggesting&lt;/strong&gt; :).&lt;/p&gt;
&lt;p&gt;If you're curious and want to play along at home, &lt;a href="http://developer.db4o.com/files/" target="_blank"&gt;go and download DB4O from their website&lt;/a&gt; and install it. To use it you have to make a few references in your application (specifically Db4objects.Db4o.dll). You then need to write some wrapper code - but I've got that covered for you:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Db4objects.Db4o;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Web;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.IO;

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; DB4O {

    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; padlock = &lt;span class="kwrd"&gt;new&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt;();

    &lt;span class="rem"&gt;// static object container variable &lt;/span&gt;
    &lt;span class="kwrd"&gt;static&lt;/span&gt; IObjectContainer _db = &lt;span class="kwrd"&gt;null&lt;/span&gt;;

    &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; _dbPath = System.Configuration.ConfigurationManager.ConnectionStrings[&lt;span class="str"&gt;"ObjectStore"&lt;/span&gt;].ConnectionString;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; DBPath {
        get {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; _dbPath;
        }
        set {
            _dbPath = &lt;span class="kwrd"&gt;value&lt;/span&gt;;
        }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IObjectContainer Container {
        get {
            &lt;span class="kwrd"&gt;lock&lt;/span&gt; (padlock) {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (_db == &lt;span class="kwrd"&gt;null&lt;/span&gt;) {

                    &lt;span class="rem"&gt;//check to see if this is pointing to data directory&lt;/span&gt;
                    &lt;span class="rem"&gt;//change as you need btw&lt;/span&gt;
                    &lt;span class="kwrd"&gt;if&lt;/span&gt; (_dbPath.Contains(&lt;span class="str"&gt;"|DataDirectory|"&lt;/span&gt;)) {

                        &lt;span class="rem"&gt;//we know, then, that this is a web project&lt;/span&gt;
                        &lt;span class="rem"&gt;//and HttpContext is hopefully not null...&lt;/span&gt;

                        _dbPath = _dbPath.Replace(&lt;span class="str"&gt;"|DataDirectory|"&lt;/span&gt;, &lt;span class="str"&gt;""&lt;/span&gt;);
                        &lt;span class="kwrd"&gt;string&lt;/span&gt; appDir = HttpContext.Current.Server.MapPath(&lt;span class="str"&gt;"~/App_Data/"&lt;/span&gt;);
                        _dbPath = Path.Combine(appDir, _dbPath);
                    }

                    _db = Db4oFactory.OpenFile(_dbPath);
                }
                &lt;span class="kwrd"&gt;return&lt;/span&gt; _db;
            }
        }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CloseContainer() {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (_db != &lt;span class="kwrd"&gt;null&lt;/span&gt;) {
            _db.Close();
        }
        _db = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
    }&lt;/pre&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;This code assumes that you&lt;/p&gt;
&lt;p&gt;Have an App_Data directory and that you have a connection string in your Web.config like this one:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="ObjectStore"&lt;/span&gt; &lt;span class="attr"&gt;connectionString&lt;/span&gt;&lt;span class="kwrd"&gt;="|DataDirectory|ObjectStore.yap"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt; &lt;/pre&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;

&lt;p&gt;&lt;strong&gt;Yes, that's a singleton you see there&lt;/strong&gt;, and yes I know it's probably making you cringe. The reason we need to use a singleton is that the IObjectContainer locks the binary file where the data is kept. File locking and singletons might not sit well with you right now, but in this case is that the way I have this setup here is for a single user - ME - because I'm developing against it. If this were a live app I would be able to set a bunch of settings to make this thread-safe etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;But it's not production - it's development only (have I mentioned this yet?) so you don't need to worry about singletons, perf, and scaling&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Great, so now that we have our container, let's store an object. This isn't really a test, but you've read a lot more crazy stuff so far, so this won't surprise you much. Consider this a spike please - or maybe pretend I'm asserting something:&lt;/p&gt;&lt;pre class="csharpcode"&gt;[TestMethod]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ObjectRepo_Should_Store_Product() {
    Product p = &lt;span class="kwrd"&gt;new&lt;/span&gt; Product();
    p.Name = &lt;span class="str"&gt;"test product"&lt;/span&gt;;
    p.Supplier=&lt;span class="kwrd"&gt;new&lt;/span&gt; Supplier(&lt;span class="str"&gt;"Test supplier"&lt;/span&gt;);
    DB.Container.Store(p);
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;

&lt;p&gt;Yes, it's that easy. But that's not the best part. I can add a DLL to the project that DB4O just released, called "&lt;strong&gt;Db4objects.Db4o.Linq&lt;/strong&gt;" and it does what you might imagine, which is exremely cool:&lt;/p&gt;&lt;pre class="csharpcode"&gt;[TestMethod]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ObjectRepo_Should_Return_Product() {
    var result = from Product p &lt;span class="kwrd"&gt;in&lt;/span&gt; DB.Container
                 &lt;span class="kwrd"&gt;where&lt;/span&gt; p.Name == &lt;span class="str"&gt;"test product"&lt;/span&gt;
                 select p;

    Assert.AreEqual(1, result.Count());
}&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Yes, that would be LINQ, working with an OODB container&lt;/strong&gt;. We can also query a bit deeper, with no problems:&lt;/p&gt;&lt;pre class="csharpcode"&gt;[TestMethod]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ObjectRepo_Should_Return_Product_By_Supplier() {
    var result = from Product p &lt;span class="kwrd"&gt;in&lt;/span&gt; DB.Container
                 &lt;span class="kwrd"&gt;where&lt;/span&gt; p.Supplier.Name == &lt;span class="str"&gt;"Test supplier"&lt;/span&gt;
                 select p;

    Assert.AreEqual(1, result.Count());
}&lt;/pre&gt;
&lt;p&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;
And to illustrate my point above about object independence and integrity, I can also get the Supplier, independent of the Product:&lt;/p&gt;&lt;pre class="csharpcode"&gt;[TestMethod]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ObjectRepo_Should_Return_Supplier() {
    var result = from Supplier s &lt;span class="kwrd"&gt;in&lt;/span&gt; DB.Container
                 select s;

    Assert.AreEqual(1, result.Count());
}&lt;/pre&gt;
&lt;p&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;
This, literally, is the tip of the iceberg. DB4O has support for transactions, indexing, and many different ways of querying to improve performance and usage. &lt;strong&gt;But I'm not talking about perf here :) - it doesn't matter, this is only for development&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Also it's worth noting that &lt;strong&gt;if I change the properties of Product around, it won't break&lt;/strong&gt;. The changed property just won't get loaded - but everything else will. So you can change and alter as required and nothing breaks!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Real-World Application&lt;br&gt;&lt;/strong&gt;What I'm suggesting is that you can create a IRepository&amp;lt;T&amp;gt; and then implement a nice ObjectRepository&amp;lt;T&amp;gt; to work with in your application. It's very simple - and yes, here's some more code for you:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq.Expressions;

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IRepository&amp;lt;T&amp;gt; {

    IQueryable&amp;lt;T&amp;gt; GetAll();
    PagedList&amp;lt;T&amp;gt; GetPaged(&lt;span class="kwrd"&gt;int&lt;/span&gt; pageIndex, &lt;span class="kwrd"&gt;int&lt;/span&gt; pageSize);
    IQueryable&amp;lt;T&amp;gt; Find(Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; expression);
    &lt;span class="kwrd"&gt;void&lt;/span&gt; Save(T item);
    &lt;span class="kwrd"&gt;void&lt;/span&gt; Delete(T item);

}&lt;/pre&gt;
&lt;p&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;
Now, you can implement this quite nicely with DB4O:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;
&lt;span class="kwrd"&gt;using&lt;/span&gt; Db4objects.Db4o.Linq;


&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ObjectRepository&amp;lt;T&amp;gt; : IRepository&amp;lt;T&amp;gt; &lt;span class="kwrd"&gt;where&lt;/span&gt; T: &lt;span class="kwrd"&gt;class&lt;/span&gt; {

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Returns all T records in the repository&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; GetAll() {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; (from T items &lt;span class="kwrd"&gt;in&lt;/span&gt; DB4O.Container
                select items).AsQueryable();
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Returns a PagedList of items&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;param name="pageIndex"&amp;gt;zero-based index to be used for lookup&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;param name="pageSize"&amp;gt;the size of the paged items&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; PagedList&amp;lt;T&amp;gt; GetPaged(&lt;span class="kwrd"&gt;int&lt;/span&gt; pageIndex, &lt;span class="kwrd"&gt;int&lt;/span&gt; pageSize) {
        var query=(from T items &lt;span class="kwrd"&gt;in&lt;/span&gt; DB4O.Container
                select items).AsQueryable();
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; PagedList&amp;lt;T&amp;gt;(query,pageIndex,pageSize);        }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Finds an item using a passed-in expression lambda&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; Find(System.Linq.Expressions.Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; expression) {
         &lt;span class="kwrd"&gt;return&lt;/span&gt; GetAll().Where(expression);
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Saves an item to the database&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;param name="item"&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Save(T item) {
        DB4O.Container.Store(item);
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Deletes an item from the database&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;param name="item"&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Delete(T item) {
        DB4O.Container.Delete(item);
    }

}
&lt;/pre&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;

&lt;p&gt;If you're wondering what a "PagedList" is - &lt;a href="http://blog.wekeroad.com/2007/12/10/aspnet-mvc-pagedlistt/" target="_blank"&gt;you can find out more here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ORM Selection Made Easy&lt;/strong&gt;&lt;br&gt;Suppose you didn't need to worry about your database as you build your application. Better yet, &lt;strong&gt;suppose you didn't need to worry about your ORM&lt;/strong&gt;! This latter thought is actually a critical, critical item. When I suggested that you could wait until you're about to launch to actually implement a database, a friend of mine asked me "well &lt;strong&gt;if you do that, you might back yourself into such a complex model that your ORM won't handle it&lt;/strong&gt;. What do you do then?".&lt;/p&gt;
&lt;p&gt;And I said "&lt;strong&gt;BINGO&lt;/strong&gt;".&lt;/p&gt;
&lt;p&gt;Put another way, what you're getting by not worrying about your ORM (until you need it) is the &lt;strong&gt;freedom to develop your app without influence from your database&lt;/strong&gt;. It is true that you can make a model that's too complex for your favorite ORM - but doesn't that mean &lt;strong&gt;your favorite ORM probably wasn't up to the task anyway&lt;/strong&gt;? Isn't it much nicer to find that out the easy way?&lt;/p&gt;
&lt;p&gt;In most cases you can probably just jump over to SQL very simply, just by replacing the reference to ObjectRepository to something like SqlRepository (this code is using Linq To Sql - but you can change this out with EF in the future&amp;nbsp; - I'll try to update this later):&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; System;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Collections;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Data.Linq;
&lt;span class="kwrd"&gt;using&lt;/span&gt; System.Linq;

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SqlRepository&amp;lt;T&amp;gt; : IRepository&amp;lt;T&amp;gt; &lt;span class="kwrd"&gt;where&lt;/span&gt; T: &lt;span class="kwrd"&gt;class&lt;/span&gt; {

    NorthwindDB.DB _db = &lt;span class="kwrd"&gt;null&lt;/span&gt;;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; SqlRepository(){
        _db=&lt;span class="kwrd"&gt;new&lt;/span&gt; NorthwindDB.DB();
    }
    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Gets the table provided by the type T and returns for querying&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;private&lt;/span&gt; Table&amp;lt;T&amp;gt; Table {
        get { &lt;span class="kwrd"&gt;return&lt;/span&gt; _db.GetTable&amp;lt;T&amp;gt;(); }
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Returns all T records in the repository&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; GetAll() {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; Table;
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Returns a PagedList of items&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;param name="pageIndex"&amp;gt;zero-based index to be used for lookup&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;param name="pageSize"&amp;gt;the size of the paged items&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; PagedList&amp;lt;T&amp;gt; GetPaged(&lt;span class="kwrd"&gt;int&lt;/span&gt; pageIndex, &lt;span class="kwrd"&gt;int&lt;/span&gt; pageSize) {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; PagedList&amp;lt;T&amp;gt;(Table, pageIndex, pageSize);           
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Finds an item using a passed-in expression lambda&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; IQueryable&amp;lt;T&amp;gt; Find(System.Linq.Expressions.Expression&amp;lt;Func&amp;lt;T, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt;&amp;gt; expression) {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; Table.Where(expression);
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Saves an item to the database&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;param name="item"&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Save(T item) {

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!Table.Contains(item)) {
            Table.InsertOnSubmit(item);
        }
        _db.SubmitChanges();
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Deletes an item from the database&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;param name="item"&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Delete(T item) {
        Table.DeleteOnSubmit(item);
        _db.SubmitChanges();
    }

}
&lt;/pre&gt;
&lt;style type="text/css"&gt;.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; }
&lt;/style&gt;

&lt;p&gt;Since we're wrapping everything in IRepository&amp;lt;T&amp;gt;, you can swap parts as needed. I'll be you were wondering why you might want to develop this way (I know I was a long time ago - who really ever swaps components anyway?) - but this is a good example of why you might want to decouple your system as much as possible. &lt;/p&gt;
&lt;p&gt;Swapping out data stores like this is equivalent to turning your minivan into a ferrari if you want to drive the Autobahn, and back again when you need to get the kids from Soccer.&lt;/p&gt;
&lt;p&gt;Am I nuts? If you think I am - please give me some details as I think this would make for an interesting discussion. Just don't tell the Alt.NET guys yet :).&lt;/p&gt;&lt;p&gt;&lt;a target="_blank" href="http://theloungenet.com/feeds/redirect/DOTNETRSS/RCONERY/D4A6F6343FBA93C2A3B2A23AF273346AE157110D"&gt;&lt;img src="http://theloungenet.com/feeds/img/DOTNETRSS/RCONERY/D4A6F6343FBA93C2A3B2A23AF273346AE157110D"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feeds.feedburner.com/~a/wekeroad/EeKc?a=oeeEkq"&gt;&lt;img src="http://feeds.feedburner.com/~a/wekeroad/EeKc?i=oeeEkq" border="0"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=Y7CIN"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=Y7CIN" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=L8JHn"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=L8JHn" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/wekeroad/EeKc?a=i2EfN"&gt;&lt;img src="http://feeds.feedburner.com/~f/wekeroad/EeKc?i=i2EfN" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/wekeroad/EeKc/~4/441648793" height="1" width="1"/&gt;</description><feedburner:origLink>http://blog.wekeroad.com/blog/crazy-talk-reducing-orm-friction/</feedburner:origLink></item></channel></rss>
