<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>codeface</title>
	<atom:link href="http://blog.markrendle.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.markrendle.net</link>
	<description>on making software</description>
	<lastBuildDate>Fri, 17 Feb 2012 15:28:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='blog.markrendle.net' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>codeface</title>
		<link>http://blog.markrendle.net</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://blog.markrendle.net/osd.xml" title="codeface" />
	<atom:link rel='hub' href='http://blog.markrendle.net/?pushpress=hub'/>
		<item>
		<title>Learn Simple.Data &amp; Nancy at SkillsMatter</title>
		<link>http://blog.markrendle.net/2012/02/17/learn-simple-data-nancy-at-skillsmatter/</link>
		<comments>http://blog.markrendle.net/2012/02/17/learn-simple-data-nancy-at-skillsmatter/#comments</comments>
		<pubDate>Fri, 17 Feb 2012 11:36:46 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[C#]]></category>
		<category><![CDATA[Nancy]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[Simple.Data]]></category>
		<category><![CDATA[Training]]></category>
		<category><![CDATA[nancyfx]]></category>
		<category><![CDATA[simpledata]]></category>
		<category><![CDATA[skillsmatter]]></category>
		<category><![CDATA[training]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=275</guid>
		<description><![CDATA[I should have blogged about this ages ago, but I’ve been unbelievably busy. Still, better late-but-not-too-late than never-or-not-soon-enough. Following the well-received half-day Introduction to Nancy and Simple.Data that I presented with Steven Robbins (@Grumpydev) at the Progressive .NET Tutorials 2011, Wendy at SkillsMatter approached me and asked if I’d be interested in doing a full [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=275&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I should have blogged about this ages ago, but I’ve been unbelievably busy. Still, better late-but-not-too-late than never-or-not-soon-enough.</p>
<p>Following the well-received half-day <a href="http://skillsmatter.com/podcast/open-source-dot-net/introduction-to-nancy-and-simple-data">Introduction to Nancy and Simple.Data</a> that I presented with Steven Robbins (<a href="https://twitter.com/#!/Grumpydev">@Grumpydev</a>) at the Progressive .NET Tutorials 2011, Wendy at <a href="http://skillsmatter.com/">SkillsMatter</a> approached me and asked if I’d be interested in doing a full two-day course. I’ve always been very impressed with the courses they offer, so I jumped at the chance to get involved. So you can now sign up for <a href="http://skillsmatter.com/course/open-source-dot-net/mark-rendles-web-app-development-with-nancy-and-simple-data">a full-on, two day deep dive into building web applications with minimal code</a>.</p>
<p>The course will quickly cover the basics, such as View Engines, Dependency Injection, Nancy’s TDD/BDD test helpers and Simple.Data’s built-in data mocking functionality, then move on to more interesting things like: security, authentication (including OAuth) and authorisation; building RESTful web APIs (<a href="http://kellabyte.com/2011/09/04/clarifying-rest/">proper ones, not just HTTP web services</a>); using different data stores with Simple.Data; and different methods for validating data.</p>
<p>It’ll be a heavily interactive couple of days. You can either turn up with an idea for a web application that you want to get started on, or you can work on an app I’ve designed to exercise the skills you’ll be learning. Either way, at the end of the course, that code is yours to take away and use as a starting-off point or a useful reference.</p>
<p>The first instance of the course is on the 12th and 13th of March, and there are still places available. Lots of places. All of them, in fact. So <a href="https://skillsmatter.com/register-online/course/2429">go sign up for it</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/275/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/275/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/275/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/275/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/275/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/275/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/275/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/275/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/275/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/275/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/275/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/275/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/275/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/275/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=275&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2012/02/17/learn-simple-data-nancy-at-skillsmatter/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>Simple.Data 1.0.0-beta1</title>
		<link>http://blog.markrendle.net/2012/02/16/simple-data-1-0-0-beta1/</link>
		<comments>http://blog.markrendle.net/2012/02/16/simple-data-1-0-0-beta1/#comments</comments>
		<pubDate>Thu, 16 Feb 2012 22:23:02 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[Simple.Data]]></category>
		<category><![CDATA[simpledata]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=266</guid>
		<description><![CDATA[At last It’s taken me so much longer to get here than I originally expected, but I’ve released the first 1.0 beta version of Simple.Data. If this post is the first you’ve heard of Simple.Data, then head over to the GitHub page and browse back through previous posts to find out more. New features I [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=266&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h2>At last</h2>
<p>It’s taken me so much longer to get here than I originally expected, but I’ve released the first 1.0 beta version of Simple.Data.</p>
<p>If this post is the first you’ve heard of Simple.Data, then head over to <a href="http://github.com/markrendle/simple.data">the GitHub page</a> and browse back through previous posts to find out more.</p>
<h2>New features</h2>
<p>I didn’t do a post for the 0.14 release, so I’ll cover the changes from that as well as what’s new in the 1.0 beta.</p>
<h3>Eager-loading with With</h3>
<p>Since very early on, Simple.Data has supported lazy-loading when you reference a joined property from the dynamic record type. There were two issues with that: firstly, if you assigned the record to a static type, the joined properties were not hydrated; secondly, multiple selects do not make DBAs happy, and should be avoided if possible.</p>
<p>Now you can use the <strong>With</strong> method to load the joined data at the same time as the main record.</p>
<pre class="code"><span style="color:blue;">var </span>db = <span style="color:#2b91af;">DatabaseHelper</span>.Open();
<span style="color:#2b91af;">Customer </span>actual = db.Customers.FindAllByCustomerId(1).WithOrders().FirstOrDefault();
</pre>
<p>This uses a single SQL select statement to pull all the Customer rows, plus the Order detail rows, and groups the data in-memory; generally, that’s more efficient than running two select operations. When the record is converted to the Customer type, it sets the ICollection&lt;Order&gt; property at the same time, either creating a new instance of List&lt;Order&gt;, or populating an existing instance if the property is readonly.</p>
<p>The inverse works too:</p>
<pre class="code"><span style="color:blue;">var </span>db = <span style="color:#2b91af;">DatabaseHelper</span>.Open();
<span style="color:#2b91af;">Order </span>actual = db.Orders.FindAllByOrderId(1).WithCustomer().FirstOrDefault();
</pre>
<p>If the property name is not the same as the database table name, you can use an alias to tweak it:</p>
<pre class="code"><span style="color:blue;">var </span>db = <span style="color:#2b91af;">DatabaseHelper</span>.Open();
<span style="color:blue;">var </span>actual = db.Orders.FindAllByOrderId(1).With(db.Orders.OrderItems.As("Items"));
</pre>
<p>And if there’s no referential integrity in the database, you can specify an explicit join separately:</p>
<pre class="code"><span style="color:blue;">dynamic </span>manager;
<span style="color:blue;">var </span>q = _db.Employees.All()
    .OuterJoin(_db.Employees.As(<span style="color:#a31515;">"Manager"</span>), <span style="color:blue;">out </span>manager)
    .On(Id: _db.Employees.ManagerId)
    .With(manager);
</pre>
<p>&nbsp;</p>
<p>(Oh, yeah, and check out the <strong>OuterJoin</strong> method. Finally.)</p>
<p>Of course, if there’s no referential integrity, it’s hard for Simple.Data to work out whether the joined property is a collection or a complex object, so you can specify <strong>WithOne</strong> or <strong>WithMany</strong> to help it out:</p>
<pre class="code"><span style="color:blue;">dynamic </span>manager;
<span style="color:blue;">var </span>q = _db.Employees.All()
    .OuterJoin(_db.Employees.As(<span style="color:#a31515;">"Manager"</span>), <span style="color:blue;">out </span>manager)
    .On(Id: _db.Employees.ManagerId)
    .WithOne(manager);
</pre>
<p>&nbsp;</p>
<p>And of course, you can mix and match all these. This test gives you a good idea of some of the heavy lifting that’s going on for you with this feature, just with the SQL:</p>
<pre class="code"><span style="color:blue;">public void </span>MultipleWithClauseJustDoesEverythingYouWouldHope()
{
    <span style="color:blue;">const string </span>expectedSql =
        <span style="color:#a31515;">"select [dbo].[employee].[id],[dbo].[employee].[name]," </span>+
        <span style="color:#a31515;">"[dbo].[employee].[managerid],[dbo].[employee].[departmentid]," </span>+
        <span style="color:#a31515;">"[manager].[id] as [__withn__manager__id]," </span>+
        <span style="color:#a31515;">"[manager].[name] as [__withn__manager__name]," </span>+
        <span style="color:#a31515;">"[manager].[managerid] as [__withn__manager__managerid]," </span>+
        <span style="color:#a31515;">"[manager].[departmentid] as [__withn__manager__departmentid]," </span>+
        <span style="color:#a31515;">"[dbo].[department].[id] as [__with1__department__id]," </span>+
        <span style="color:#a31515;">"[dbo].[department].[name] as [__with1__department__name]" </span>+
        <span style="color:#a31515;">" from [dbo].[employee] left join [dbo].[employee] [manager] " </span>+
        <span style="color:#a31515;">"on ([manager].[id] = [dbo].[employee].[managerid])" </span>+
        <span style="color:#a31515;">" left join [dbo].[department] " </span>+
        <span style="color:#a31515;">"on ([dbo].[department].[id] = [dbo].[employee].[departmentid])"</span>;

    <span style="color:blue;">dynamic </span>manager;
    <span style="color:blue;">var </span>q = _db.Employees.All()
        .OuterJoin(_db.Employees.As(<span style="color:#a31515;">"Manager"</span>), <span style="color:blue;">out </span>manager)
        .On(Id: _db.Employees.ManagerId)
        .With(manager)
        .WithDepartment();

    GeneratedSqlIs(expectedSql);
}
</pre>
<p>(Never mind the logic involved in turning that result set into the correct in-memory object graphs.)</p>
<p>Now, this works on multi-record queries, but not on single-record ones such as FindById or the key-driven Get method, and that’s more problematic since those methods don’t return a query you can modify, just a record. In the past I did actually toy with having the SimpleRecord type do lazy self-evaluation, but the fact that the NUnit Assert.IsNull test wouldn’t accept that the object was null even when it swore black-was-blue that it was put me off. (It works for Nullable&lt;T&gt;; no fair.)</p>
<p>Instead of that, and this is only in the 1.0 beta release, you can specify your With clause before the Get or FindBy:</p>
<pre class="code"><span style="color:blue;">var </span>db = <span style="color:#2b91af;">DatabaseHelper</span>.Open();
<span style="color:#2b91af;">Customer </span>actual = db.Customers.WithOrders().Get(1);
</pre>
<p>So now you get all that goodness for single records, where it’s arguably more useful anyway.</p>
<h3>Upsert</h3>
<p>Inserting and updating is all very well, but sometimes you’ve got some data and you just don’t know whether it’s in the database already or not. If it is, you want to update the row with some new values; if it’s not, you want to insert it. Boring.</p>
<p>To save you the time and trouble, Simple.Data now provides the <strong>Upsert</strong> method. Give it a record, and it will do all the checking to see if it exists or not. And in beta2, there’ll be back-end database-specific optimizations; for example, if you’re using the SQL Server provider with SQL 2008 or later, it will use the MERGE operation.</p>
<p>Upsert returns the record as it is in the database following the operation, with any database-specified values intact.</p>
<pre class="code"><span style="color:blue;">var </span>db = <span style="color:#2b91af;">DatabaseHelper</span>.Open();
<span style="color:blue;">var </span>user = <span style="color:blue;">new </span><span style="color:#2b91af;">User </span>{Id = 2, Name = <span style="color:#a31515;">"Charlie"</span>, Password = <span style="color:#a31515;">"foobar"</span>, Age = 42};
<span style="color:blue;">var </span>actual = db.Users.Upsert(user);
</pre>
<p>&nbsp;</p>
<p>That’s one example, but there are plenty of other ways to use Upsert. Take a look at <a href="https://github.com/markrendle/Simple.Data/blob/master/Simple.Data.SqlTest/UpsertTests.cs">the tests</a> to see the others.</p>
<h2></h2>
<h2>NuGet and SemVer</h2>
<p>I’ve pushed this release to <a href="http://nuget.org/packages/simple.data.core">NuGet</a> using the <a href="http://semver.org">Semantic Version</a> number for pre-release (1.0.0-beta1), which NuGet added support for in 1.6. Using this form means that NuGet knows that it’s pre-release software, and you’ll have to explicitly tell it that that’s what you want. So to get the 1.0 beta releases, remember to use the –Pre flag for the Install-Package command. The great thing about this is that when we get to 1.0 RTW, I’ll start on 1.1.0-alpha1 and both package types will be available from the repository.</p>
<p>If you’re waiting for the Mono build, I hope to have it out as a tgz by the end of this weekend.</p>
<h2>What’s still to do?</h2>
<p>So with those two features, I’m drawing a temporary line in the sand and focusing on getting everything to release quality. That means implementing some optimizations around object creation and database tricks, but more importantly, working on test coverage, refactoring some messy code, and making <a href="http://simplefx.org/simpledata/docs">the documentation</a> comprehensive. Help on that last one would be much appreciated!</p>
<p>Come to that, if anybody wants to make a really nice website… <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/266/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/266/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/266/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/266/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/266/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/266/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/266/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/266/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/266/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/266/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/266/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/266/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/266/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/266/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=266&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2012/02/16/simple-data-1-0-0-beta1/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>Mark Rendle, Freelance Consultant</title>
		<link>http://blog.markrendle.net/2012/01/13/mark-rendle-freelance-consultant/</link>
		<comments>http://blog.markrendle.net/2012/01/13/mark-rendle-freelance-consultant/#comments</comments>
		<pubDate>Fri, 13 Jan 2012 14:12:10 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[consulting]]></category>
		<category><![CDATA[professional]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=237</guid>
		<description><![CDATA[As some of you may know, for some time I have been considering starting my own venture, and I’m pleased to announce that I’m taking the first step on this journey. Starting in March 2012 I will be reducing my commitment to my current employer, Dot Net Solutions, and spending the remainder of my time [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=237&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>As some of you may know, for some time I have been considering starting my own venture, and I’m pleased to announce that I’m taking the first step on this journey. Starting in March 2012 I will be reducing my commitment to my current employer, <a href="http://www.dotnetsolutions.co.uk/" target="_blank">Dot Net Solutions</a>, and spending the remainder of my time working as an independent software development consultant, focusing on both Cloud Computing and Software Quality. Work on a web site is underway, which will outline the full set of services I will be offering.</p>
<p>This does not, however, mark in any way an end to my relationship with Dot Net Solutions. I will remain in my current position as Principal Consultant and will continue to work closely on major projects and supporting Microsoft as an active member of the VTSP (Virtual Technology Specialist Program) performing consulting and conducting ADSs (Architecture Design Sessions).</p>
<p>From my perspective, there are things one cannot achieve as a singleton, and this continuing relationship will enable me to pursue potential work that would otherwise be out of reach.</p>
<p>Dot Net Solutions has been a great company to work for, and over the last two years they have been very supportive of my community and OSS work. I have learned a great deal, and I like to think that I have made a valuable contribution too. As a company, DNS are in an excellent position to grow this year and beyond, and I am very excited to remain part of that process.</p>
<p>If you would like to discuss what I can do for your project, team, or company, please use <a href="http://blog.markrendle.net/contact-me/">the Contact Me page</a> to get in touch.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/237/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/237/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/237/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/237/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/237/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/237/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/237/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/237/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/237/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/237/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/237/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/237/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/237/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/237/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=237&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2012/01/13/mark-rendle-freelance-consultant/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>Eager-loading RFC</title>
		<link>http://blog.markrendle.net/2011/12/01/eager-loading-rfc/</link>
		<comments>http://blog.markrendle.net/2011/12/01/eager-loading-rfc/#comments</comments>
		<pubDate>Thu, 01 Dec 2011 14:53:06 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=227</guid>
		<description><![CDATA[There are two more features I want to get into Simple.Data before releasing 1.0beta1: upserts, and eager loading. Upserts are pretty straight-forward, but there are a few different approaches to eager loading and I want to get some input from the community before I pick one. In case you don’t know, eager loading is a [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=227&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>There are two more features I want to get into Simple.Data before releasing 1.0beta1: <a href="http://en.wikipedia.org/wiki/Upsert">upserts</a>, and eager loading. Upserts are pretty straight-forward, but there are a few different approaches to eager loading and I want to get some input from the community before I pick one.</p>
<p>In case you don’t know, eager loading is a pattern for getting data from the database in an optimal fashion, with the minimum number of requests or least-possible server load. It’s the opposite of <a href="http://en.wikipedia.org/wiki/Lazy_loading">lazy loading</a>, which Simple.Data already does.</p>
<p>The implementation syntax will look like this:</p>
<pre class="code"><span style="color:blue;">    IEnumerable&lt;Customer&gt; </span>customers = _db.Customers.FindAllByRegion(<span style="color:#a31515;">"South"</span>)
                .With(_db.Customers.Orders)                .Cast&lt;Customer&gt;();</pre>
<p>This will create the customer objects and populate an <strong>ICollection&lt;Order&gt; Orders</strong> property in each one, assuming there is one.</p>
<p>There are two directions in which a class may have relationships with other classes: it may have “parent” (or “lookup”) classes, where there is at most a single instance of that parent class within the instance of the class in question; and it may have “child” classes, where there is a collection of instances of the child class. Eager loading of parent classes is trivial; you just add the necessary join(s) to the master table(s) and marshal the data into the right places in code.</p>
<p>Eager loading of child classes is similarly easy when there is only a single child collection to be loaded; you join to the detail table and then process the results so that a single instance of the main table row is created, and instances of the detail table rows are grouped into collections.</p>
<p>For example, loading user objects with a list of phone numbers:</p>
<p>SELECT User.Id, User.Name, Phone.Number<br />FROM User<br />LEFT JOIN Phone ON User.Id = Phone.UserId</p>
<p>Returned rows:</p>
<table border="1" cellspacing="0" cellpadding="2" width="400">
<tbody>
<tr>
<td valign="top" width="133">User.Id</td>
<td valign="top" width="133">User.Name</td>
<td valign="top" width="133">Phone.Number</td>
</tr>
<tr>
<td valign="top" width="133">1</td>
<td valign="top" width="133">Alice</td>
<td valign="top" width="133">0123456789</td>
</tr>
<tr>
<td valign="top" width="133">1</td>
<td valign="top" width="133">Alice</td>
<td valign="top" width="133">0738473284</td>
</tr>
<tr>
<td valign="top" width="133">2</td>
<td valign="top" width="133">Bob</td>
<td valign="top" width="133">0129934845</td>
</tr>
<tr>
<td valign="top" width="133">2</td>
<td valign="top" width="133">Bob</td>
<td valign="top" width="133">0729478594</td>
</tr>
</tbody>
</table>
<p>From this we create a User object for Alice with her two phone numbers, and an object for Bob with his. Even if there are a lot of rows in the detail table, this is still the preferred way of handling eager loading for this scenario as it involves the fewest round-trips to the database. Often, you can handle a parent-child-child relationship using this algorithm, too, although beyond that point you’re getting a bit scary.</p>
<p>The complexity arises when you want to load two unrelated child collections, say, load Customers with their Invoices and Orders:</p>
<p>SELECT Customer.*, Invoice.*, Order.*<br />FROM Customer<br />LEFT JOIN Invoice ON Customer.Id = Invoice.CustomerId<br />LEFT JOIN Order ON Customer.Id = Order.CustomerId</p>
<p>This creates what is technically called an “outer <a href="http://db.grussell.org/section010.html#_Toc67114480">Cartesian product</a>”, where a row is returned for every possible combination of the rows from the two outer-joined tables. So if you’re grabbing the details for a single valuable customer who has placed a thousand orders and generated a thousand invoices, you get a million rows back from the database. I have a hunch this might not be optimal.</p>
<p>So this is my <a href="http://en.wikipedia.org/wiki/Request_for_Comments">Request for Comments</a>: what would you like to see done here?</p>
<p>The options are:</p>
<ol>
<li>Only allow one detail-table With clause to be specified per query. Throw an exception if there is more than one.</li>
<li>Allow multiple detail-table With clauses, and use additional SELECT operations for all except the first.</li>
<li>Add a parameter to the With method <em>allowing</em> the developer to specify the technique on a per-detail-table basis:</li>
<pre class="code"><span style="color:blue;">    var </span>customers = _db.Customers.FindAllByRegion(<span style="color:#a31515;">"South"</span>)
                .With(_db.Customers.Orders, <span style="color:#2b91af;">WithUsing</span>.Join)
                .With(_db.Customers.Orders.Items, <span style="color:#2b91af;">WithUsing</span>.Join)
                .With(_db.Customers.Invoices, <span style="color:#2b91af;">WithUsing</span>.ExtraQuery);
</pre>
<p>If only one detail table is specified, or one detail with a detail below it (e.g. _db.Customers.Orders.Items), the default behaviour when no <strong>WithUsing</strong> parameter is supplied will be to use JOIN. Multiple detail tables without a <strong>WithUsing</strong> will cause the ADO adapter to throw an exception (other adapters, such as <a href="https://github.com/craiggwilson/Simple.Data.MongoDB">the one for MongoDB</a>, can use the With clause as they see fit).</ol>
<p>I think I’ve <a href="http://c2.com/cgi/wiki?RubberDucking">rubber ducked</a> here a bit, as Option 3 is looking like a no-brainer, but I’ve typed it all now, so if you do have any comments or suggestions, please do leave them below. I’m planning on starting code for this on Sunday morning, so there’s plenty of time to change my mind.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/227/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/227/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/227/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/227/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/227/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/227/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/227/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/227/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/227/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/227/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/227/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/227/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/227/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/227/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=227&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2011/12/01/eager-loading-rfc/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>Yes, Simple.Data protects against SQL Injection</title>
		<link>http://blog.markrendle.net/2011/12/01/yes-simple-data-protects-against-sql-injection/</link>
		<comments>http://blog.markrendle.net/2011/12/01/yes-simple-data-protects-against-sql-injection/#comments</comments>
		<pubDate>Thu, 01 Dec 2011 12:24:35 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=225</guid>
		<description><![CDATA[Several people who weren’t following the show at the inception of Simple.Data have asked whether it does anything to prevent SQL Injection attacks. Those of you who remember the start of the project will understand why I’m kind of amused by the question. I originally built Simple.Data as a proof-of-concept when there was a big [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=225&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Several people who weren’t following the show at the inception of Simple.Data have asked whether it does anything to prevent <a href="http://en.wikipedia.org/wiki/SQL_injection">SQL Injection</a> attacks. Those of you who remember the start of the project will understand why I’m kind of amused by the question.</p>
<p>I originally built Simple.Data as a proof-of-concept when there was a big web-scuffle over what was then called Microsoft.Data (now <a href="http://msdn.microsoft.com/en-us/library/webmatrix.data%28v=vs.99%29.aspx">WebMatrix.Data</a>). <a href="http://weblogs.asp.net/davidfowler/default.aspx">David Fowler</a>, a developer I have since come to <a href="http://www.codeplex.com/site/users/view/dfowler">respect</a> <a href="https://github.com/SignalR/SignalR">greatly</a>, posted an example on his blog which used concatenated SQL, and everybody lined up to tear him a new one. I’m a big fan of code over cockfights, so I had a go at implementing a simple data access library which made SQL Injection impossible by eliminating SQL strings. Thus Simple.Data. You told it what you wanted, and provided the necessary values, and then it wrapped them safely up in parameters and executed them. I stuck it on <a href="http://github.com/markrendle/Simple.Data">GitHub</a>, and <a href="http://blog.markrendle.net/2010/08/05/introducing-simple-data/">posted about it on my blog</a>.</p>
<p>(In fact, the first version did allow you to execute SQL strings, much like Dapper and Massive, because the functionality was extremely limited otherwise. As I’ve iterated on it, I’ve been able to expose nearly all the required functionality using the dynamic approach, so the only way you can execute SQL directly now is by getting an IDbConnection object from the AdoAdapter and using ADO.NET against it.)</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/225/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/225/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/225/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/225/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/225/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/225/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/225/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/225/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/225/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/225/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/225/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/225/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/225/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/225/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=225&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2011/12/01/yes-simple-data-protects-against-sql-injection/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>Macro-optimisations</title>
		<link>http://blog.markrendle.net/2011/12/01/macro-optimisations/</link>
		<comments>http://blog.markrendle.net/2011/12/01/macro-optimisations/#comments</comments>
		<pubDate>Thu, 01 Dec 2011 00:36:23 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[Simple.Data]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=210</guid>
		<description><![CDATA[I&#8217;ve used Simple.Data in a few production projects now (and it&#8217;s doing a great job so far). It&#8217;s not often you actually get to use the software that you write, but when you do, it&#8217;s a great opportunity to see it through users&#8217; eyes, and I&#8217;ve made a few changes and improvements over the past [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=210&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve used Simple.Data in a few production projects now (and it&#8217;s doing a great job so far). It&#8217;s not often you actually get to use the software that you write, but when you do, it&#8217;s a great opportunity to see it through users&#8217; eyes, and I&#8217;ve made a few changes and improvements over the past year as a result.</p>
<p>The most recent project that we&#8217;ve used it on at Dot Net Solutions is the Met Office open data thing that was announced on Tuesday. And that forced me to bring forward an optimisation that&#8217;s been way down my to-do list, partly because I didn&#8217;t really just how much of an optimisation it would be.</p>
<p>The Met Office project involves inserting something like 8 million records a day into a SQL Azure database, which isn&#8217;t a huge amount, but enough to need you to be smart about how you do it. The version of Simple.Data that was on NuGet when we started supported bulk inserts, but it wasn&#8217;t friendly to the error handling we needed and it assumed it needed to return the inserted records, doing that whole &#8216;select just-inserted-record&#8217; thing, which is often completely unnecessary.</p>
<p><em>(So it turns out that when you&#8217;re handling TryInvokeMember in a DynamicObject, you can actually find out whether the return value is used by the caller, and not bother if it isn&#8217;t. But that&#8217;s another blog post.)</em></p>
<p>Anyway, I tweaked a couple of things and shaved off a fraction of the time it was taking, but it was a small fraction, and things were still far too slow. So we did what we should have done in the first place, and used <a href="http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx" target="_blank">SqlBulkCopy</a>.</p>
<p>If you haven&#8217;t used this (SqlClient-specific) method, you should read up on it and keep it in your mental list of &#8220;things that are good that I might need some day&#8221;. It lets you prepare a big batch of rows in a DataTable (turns out they&#8217;re still good for something) and then insert them in a single operation, and man, it&#8217;s quick.</p>
<p>But it&#8217;s SQL Server specific, so I couldn&#8217;t support it in the generic ADO adapter code.</p>
<p>I&#8217;ve exposed a few interfaces in the Simple.Data.Ado assembly which providers can optionally implement if they need to do something a little differently or can do something better. The first instance was ICustomInserter, which is implemented in the Oracle provider to handle fetch-backs in a world without IDENTITY columns. Since then I&#8217;ve added more as I went along, and IBulkInserter was one of them because, as I said earlier, I had half a mind to implement this. And now I have.</p>
<p>Anyway, I&#8217;ll stop blathering now and just post the comparison code I wrote (measures time to insert 10,000 records, five times) and the before and after results.</p>
<p><strong>Code:</strong></p>
<p><pre class="brush: csharp;">
namespace BulkInsertComparison
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using Simple.Data;

    class Program
    {
        static void Main(string[] args)
        {
            var db = Database.OpenConnection(&quot;data source=.;initial catalog=BulkInsertTest;integrated security=true&quot;);

            for (int i = 0; i &lt; 5; i++)
            {
                Console.WriteLine(TimeInsert(db));
            }
        }

        private static TimeSpan TimeInsert(dynamic db)
        {
            var stopwatch = Stopwatch.StartNew();
            db.Target.Insert(GenerateItems(10000));
            stopwatch.Stop();
            return stopwatch.Elapsed;
        }

        static IEnumerable&lt;Item&gt; GenerateItems(int number)
        {
            for (int i = 0; i &lt; number; i++)
            {
                var guid = Guid.NewGuid();
                yield return new Item(0, guid, guid.ToString(&quot;N&quot;));
            }
        }
    }

    class Item
    {
        private readonly int _id;
        private readonly Guid _guid;
        private readonly string _text;

        public Item(int id, Guid guid, string text)
        {
            _id = id;
            _guid = guid;
            _text = text;
        }

        public string Text { get { return _text; } }
        public Guid Guid { get { return _guid; } }
        public int Id { get { return _id; } }
    }
}
</pre></p>
<p><strong>Before:</strong></p>
<pre>00:00:16.9799819
00:00:17.1971797
00:00:18.0744958
00:00:19.1514537
00:00:17.3798541</pre>
<p><strong>After:</strong></p>
<pre>00:00:00.4616911 (First run includes MEFing IBulkInserter)
00:00:00.2757802
00:00:00.2852119
00:00:00.2504587
00:00:00.2453277</pre>
<p>Totally worth it.</p>
<p>0.12.2 on NuGet now. <em>Mini-roadmap: eager-loading (0.14) and upserts (0.15).</em></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/210/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/210/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/210/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=210&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2011/12/01/macro-optimisations/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>Simple.Data for Mono</title>
		<link>http://blog.markrendle.net/2011/11/27/simple-data-for-mono/</link>
		<comments>http://blog.markrendle.net/2011/11/27/simple-data-for-mono/#comments</comments>
		<pubDate>Sun, 27 Nov 2011 14:44:10 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[Simple.Data]]></category>
		<category><![CDATA[mono]]></category>
		<category><![CDATA[simpledata]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=208</guid>
		<description><![CDATA[TL;DR I&#8217;ve got Simple.Data running on Mono 2.10.6. Most tests pass. YMMV. Download it here. Ritalin version Simple.Data on Mono is something that people have been asking about, and I&#8217;ve been meaning to sort out, pretty much since the project went from a proof-of-concept to an actual OSS product. One way or another I&#8217;ve never [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=208&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<h3>TL;DR</h3>
<p>I&#8217;ve got <a href="https://github.com/markrendle/Simple.Data" target="_blank">Simple.Data</a> running on <a href="http://www.mono-project.com/Release_Notes_Mono_2.10.6" target="_blank">Mono 2.10.6</a>. Most tests pass. YMMV. <a href="https://github.com/downloads/markrendle/Simple.Data/mono-release-0.11.4.tgz" target="_blank">Download it here</a>.</p>
<h3>Ritalin version</h3>
<p>Simple.Data on Mono is something that people have been asking about, and I&#8217;ve been meaning to sort out, pretty much since the project went from a proof-of-concept to an actual OSS product. One way or another I&#8217;ve never gotten round to it, but a couple of things have made it seem more relevant. Firstly, there are providers for lots of OSS databases now (<a href="https://github.com/Vidarls/Simple.Data.Mysql" target="_blank">MySQL</a>, <a href="https://github.com/NotMyself/Simple.Data.Sqlite" target="_blank">SQLite</a>, <a href="https://github.com/ChrisMH/Simple.Data.PostgreSql" target="_blank">PostgreSQL</a>); secondly, a certain <a href="https://twitter.com/#!/fekberg" target="_blank">@fekberg</a> has been very persistent in his status update requests, so I&#8217;ve taken the time this weekend to make it work.</p>
<h4>The challenges</h4>
<p>For the most part, I&#8217;ve been pleasantly surprised by how easy it&#8217;s been. I&#8217;ve found what I think is a bug in the Mono implementation of either dynamic or LINQ or the combination of the two, which I&#8217;m going to file with <a href="http://xamarin.com/" target="_blank">Xamarin</a> once I&#8217;ve created a simple repro project. I&#8217;ve come up with a workaround involving old-school class-based IEnumerable/IEnumerator implementations, and the performance doesn&#8217;t seem to be affected, so that&#8217;s fine.</p>
<p>The hardest thing about the whole process is that <a href="http://monodevelop.com/" target="_blank">MonoDevelop</a> just isn&#8217;t Visual Studio 2010 + ReSharper. It&#8217;s not a bad IDE by any standards – I&#8217;d still take it over Eclipse any day – but I work day in, day out with VS and jumping into any other IDE just feels like somebody moved all the cheese. Add to that the fact that I&#8217;m running it under OSX, so even the standard Windows keyboard shortcuts don&#8217;t work, and it&#8217;s a bit like running in treacle. As I understand it, the Mono Tools for Visual Studio don&#8217;t support 2.10; Miguel de Icaza tells me that they&#8217;re working on some awesome new VS tooling, so I&#8217;m really looking forward to that.</p>
<p>The other big challenge was testing the ADO adapter against a real database. I only own the SQL Server and SQL Compact providers, so I really wanted to test with SQL Server to keep things simple and let me step-debug if necessary. I was expecting not to have fun with this, but it turned out fine. I run my Windows development environment on my MacBook using <a href="http://www.parallels.com/products/desktop/" target="_blank">Parallels 7</a>, so I set up the Host-Guest networking (easy) and opened inbound port 1433 in Windows Firewall (also easy) and that was it. There were a couple of failing tests, one calling a stored procedure with a DataTable and one involving a scalar function, but the rest just passed. I&#8217;m guessing that the majority of people who want to use Simple.Data on Mono will be using one of the OSS DB providers, so hopefully this won&#8217;t be a problem.</p>
<h4>Releases</h4>
<p>I don&#8217;t know what the Mono NuGet situation is, so I&#8217;ll be releasing Mono builds as tgz downloads from the GitHub project page. For the time being, there are differences between the Mono build of Simple.Data.SqlServer and the Microsoft .NET build, so if you want to use that provider, don&#8217;t use the NuGet version.</p>
<p>Right now, there&#8217;s <a href="https://github.com/markrendle/Simple.Data/downloads" target="_blank">a 0.11.4 build in the Downloads section</a> which I hope works. However, I haven&#8217;t really exercised it to any great degree, so if you encounter any problems please <a href="https://github.com/markrendle/Simple.Data/issues?sort=created&amp;direction=desc&amp;state=open" target="_blank">raise an issue</a> if you think it&#8217;s a bug, or ask on <a href="http://groups.google.com/group/simpledata?pli=1" target="_blank">the mailing list</a> if you aren&#8217;t sure.</p>
<p>If you are one of the developers of an adapter or provider, you might want to test against Mono. If, for any reason, that&#8217;s not an option, then let me know and I&#8217;ll try to find time to test it for you.</p>
<p>Going forward, I will support (in the OSS sense of the word) both Microsoft .NET and Mono for all releases.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/208/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/208/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/208/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/208/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/208/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/208/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/208/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/208/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/208/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/208/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/208/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/208/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/208/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/208/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=208&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2011/11/27/simple-data-for-mono/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>Simple.Data 0.11</title>
		<link>http://blog.markrendle.net/2011/11/24/simple-data-0-11/</link>
		<comments>http://blog.markrendle.net/2011/11/24/simple-data-0-11/#comments</comments>
		<pubDate>Thu, 24 Nov 2011 12:13:39 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[Simple.Data]]></category>
		<category><![CDATA[simpledata]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=199</guid>
		<description><![CDATA[Some API changes and enhancements After the slow-down in development caused by all that InMemoryAdapter stuff, there were a few important things I needed to address quickly. One of these will have broken third-party adapters (but not providers) so let’s talk about that one first. Get var db = DatabaseHelper.Open(); var user = db.Users.Get(1); Assert.AreEqual(1, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=199&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><strong>Some API changes and enhancements</strong></p>
<p>After the slow-down in development caused by <a href="http://blog.markrendle.net/2011/11/24/simple-data-0-10/">all that InMemoryAdapter stuff</a>, there were a few important things I needed to address quickly. One of these will have broken third-party adapters (but <strong>not</strong> providers) so let’s talk about that one first.</p>
<h3>Get</h3>
<pre class="code"><span style="color:blue;">var </span>db = <span style="color:#2b91af;">DatabaseHelper</span>.Open();
<span style="color:blue;">var </span>user = db.Users.Get(1);
<span style="color:#2b91af;">Assert</span>.AreEqual(1, user.Id);</pre>
<p>I’m not really sure why Get wasn’t already there, to be honest. Part of the problem is that it requires a new abstract method internally, and until adapter authors implement that method, their users are stuck on &lt;0.11, which I try to avoid where possible.</p>
<p>For the ADO adapter, Get will use the table’s primary key to construct the query (once; it’s then cached internally, no worries about performance). For the MongoDB adapter, I’d expect it to use the built-in id value that Mongo assigns to all records. Somebody is working on an OData adapter, for which, e.g., Customers.Get(1001) will resolve to the /Customers(1001) URL.</p>
<p>Get is supported in the InMemoryAdapter, but you’ll have to configure the key(s) for each table:</p>
<pre class="code"><span style="color:blue;">var </span>adapter = <span style="color:blue;">new </span><span style="color:#2b91af;">InMemoryAdapter</span>();
adapter.SetKeyColumn(<span style="color:#a31515;">"Test"</span>, <span style="color:#a31515;">"Id"</span>);
<span style="color:#2b91af;">Database</span>.UseMockAdapter(adapter);
<span style="color:blue;">var </span>db = <span style="color:#2b91af;">Database</span>.Open();
db.Test.Insert(Id: 1, Name: <span style="color:#a31515;">"Alice"</span>);
<span style="color:blue;">var </span>record = db.Test.Get(1);
<span style="color:#2b91af;">Assert</span>.IsNotNull(record);
<span style="color:#2b91af;">Assert</span>.AreEqual(1, record.Id);
<span style="color:#2b91af;">Assert</span>.AreEqual(<span style="color:#a31515;">"Alice"</span>, record.Name);</pre>
<h3>Trace configurability</h3>
<p>The ADO adapter has been writing all generated SQL to the Trace output at the point of execution for a while now. While this is often very useful, I’ve had a couple of people ask if I could make it turn-off-and-on-able, so I have. You can do this in two ways:</p>
<p><strong>In code:</strong></p>
<pre class="code"><span style="color:#2b91af;">Database</span>.TraceLevel = <span style="color:#2b91af;">TraceLevel</span>.Off;</pre>
<p><strong>In config:</strong></p>
<pre class="code"><span style="color:blue;">&lt;?</span><span style="color:#a31515;">xml </span><span style="color:red;">version</span><span style="color:blue;">=</span>"<span style="color:blue;">1.0</span>" <span style="color:red;">encoding</span><span style="color:blue;">=</span>"<span style="color:blue;">utf-8</span>" <span style="color:blue;">?&gt; &lt;</span><span style="color:#a31515;">configuration</span><span style="color:blue;">&gt; &lt;</span><span style="color:#a31515;">configSections</span><span style="color:blue;">&gt; &lt;</span><span style="color:#a31515;">sectionGroup </span><span style="color:red;">name</span><span style="color:blue;">=</span>"<span style="color:blue;">simpleData</span>"<span style="color:blue;">&gt; &lt;</span><span style="color:#a31515;">section </span><span style="color:red;">name</span><span style="color:blue;">=</span>"<span style="color:blue;">simpleDataConfiguration</span>"                <span style="color:red;">type</span><span style="color:blue;">=</span>"<span style="color:blue;">Simple.Data.SimpleDataConfigurationSection, Simple.Data</span>"<span style="color:blue;">/&gt; &lt;/</span><span style="color:#a31515;">sectionGroup</span><span style="color:blue;">&gt; &lt;/</span><span style="color:#a31515;">configSections</span><span style="color:blue;">&gt; &lt;</span><span style="color:#a31515;">simpleData</span><span style="color:blue;">&gt; &lt;</span><span style="color:#a31515;">simpleDataConfiguration </span><span style="color:red;">traceLevel</span><span style="color:blue;">=</span>"<span style="color:blue;">Error</span>"<span style="color:blue;">/&gt; &lt;/</span><span style="color:#a31515;">simpleData</span><span style="color:blue;">&gt; &lt;/</span><span style="color:#a31515;">configuration</span><span style="color:blue;">&gt;</span></pre>
<p>(Gotta love XML.)</p>
<p>ADO SQL output will happen with the trace level set to Info, Warning or Error.</p>
<h3>More ADO connection control</h3>
<p>I occasionally see how Simple.Data performs compared to other ORM/micro-ORM tools, using the <a href="https://github.com/SamSaffron/dapper-dot-net/blob/master/Tests/PerformanceTests.cs">PerformanceTests</a> project from Dapper. I was running this through the other day, and I realised that Simple.Data was losing a lot of time opening and closing connections, while the other test cases were mostly using an open connection for the duration of the test. I’ve had a few comments that they’d like more control over the connection, or that Simple.Data is too aggressive in closing connections, so I decided to improve my standing in the Dapper smack-down and hopefully help some real people out too.</p>
<p><strong>Start using an open connection like this:</strong></p>
<pre class="code"><span style="color:#2b91af;">SqlConnection </span>connection = <span style="color:#2b91af;">Program</span>.GetOpenConnection();
((<span style="color:#2b91af;">AdoAdapter</span>) db.GetAdapter()).UseSharedConnection(connection);</pre>
<p><strong>And stop using it again like this:</strong></p>
<pre class="code">((<span style="color:#2b91af;">AdoAdapter</span>) simpleDb.GetAdapter()).StopUsingSharedConnection();</pre>
<p>And that’s it. In my performance test project (which is in the solution on Github), this knocked 20-30% off the runtime, with 500 FindById operations taking ~80ms, versus ~50ms using plain ADO.</p>
<p>I’ve also tried to tone down the aggression a little when it comes to closing connections, doing it as soon as possible, instead of (occasionally) before.</p>
<h3>Immediate road-map</h3>
<p>I want to get the Azure Table Service adapter done, and help with the OData adapter, and I’ve got a cool website to build using Simple.Data and Nancy, so Core will go into maintenance while I do those things for a while. I’ll try to fix any problems in a timely fashion, as usual. If you’ve got anything still outstanding as of 0.11.1 (now on Nuget) please gently remind <a href="https://twitter.com/#!/markrendle">me on Twitter</a>.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/199/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/199/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/199/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/199/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/199/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/199/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/199/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/199/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/199/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/199/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/199/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/199/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/199/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/199/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=199&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2011/11/24/simple-data-0-11/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>Simple.Data 0.10</title>
		<link>http://blog.markrendle.net/2011/11/24/simple-data-0-10/</link>
		<comments>http://blog.markrendle.net/2011/11/24/simple-data-0-10/#comments</comments>
		<pubDate>Thu, 24 Nov 2011 11:21:39 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">https://markrendle.wordpress.com/?p=197</guid>
		<description><![CDATA[Deserves its own post, even though I’m about to write the 0.11 one. This release took much longer than I would have liked, mainly because I bit off more than I could chew. I had a requirement to provide poly-fills that implement query operations against in-memory datasets, on behalf of adapters for data-stores that don’t [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=197&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p><strong>Deserves its own post, even though I’m about to write the 0.11 one.</strong></p>
<p>This release took much longer than I would have liked, mainly because I bit off more than I could chew. I had a requirement to provide poly-fills that implement query operations against in-memory datasets, on behalf of adapters for data-stores that don’t support certain operations. Think aggregates, grouping and so on. At some point, it occurred to me that this would make it really easy to create an in-memory adapter which would just have all query functionality implemented by these poly-fills.</p>
<p><em>Aside: From very early on, Simple.Data has had the XmlMockAdapter which could be used for providing a quick and dirty database for test environments. At the time I wrote that, I wasn’t totally confident in the Simple.Data model, so a way to instantiate that data without using the API seemed important. Since then, of course, the API has become much more stable and I’ve gained confidence, so it seems perfectly OK to use it to set up the test data as well as consume it. <strong>Consider XmlMockAdapter deprecated.</strong></em></p>
<h4>Simple.Data.InMemoryAdapter</h4>
<p>The InMemoryAdapter lives directly in the Simple.Data namespace in the Simple.Data.dll assembly from the Simple.Data.Core package. It is a first-class component, because testing is a first-class concern.</p>
<p>You can use the adapter like this:</p>
<pre class="code"><span style="color:#2b91af;">Database</span>.UseMockAdapter(<span style="color:blue;">new </span><span style="color:#2b91af;">InMemoryAdapter</span>());
<span style="color:blue;">var </span>db = <span style="color:#2b91af;">Database</span>.Open();
db.Test.Insert(Id: 1, Name: <span style="color:#a31515;">"Alice"</span>);
<span style="color:blue;">var </span>record = db.Test.FindById(1);
<span style="color:#2b91af;">Assert</span>.IsNotNull(record);
<span style="color:#2b91af;">Assert</span>.AreEqual(1, record.Id);
<span style="color:#2b91af;">Assert</span>.AreEqual(<span style="color:#a31515;">"Alice"</span>, record.Name);</pre>
<p>That UseMockAdapter method is now directly on the Database class. After calling that, all subsequent calls to any of the Database.Open methods will return a database using that adapter.</p>
<p>Any tables you reference in the database will be “created” if they don’t already exist. Internally, the tables are just lists of dictionaries. Any data you insert will retain its CLR type, so the adapter can handle byte arrays and so on quite happily.</p>
<p>Joins are supported:</p>
<pre class="code"><span style="color:blue;">var </span>adapter = <span style="color:blue;">new </span><span style="color:#2b91af;">InMemoryAdapter</span>();
adapter.ConfigureJoin(<span style="color:#a31515;">"Customer"</span>, <span style="color:#a31515;">"ID"</span>, <span style="color:#a31515;">"Orders"</span>, <span style="color:#a31515;">"Order"</span>, <span style="color:#a31515;">"CustomerID"</span>, <span style="color:#a31515;">"Customer"</span>);
<span style="color:#2b91af;">Database</span>.UseMockAdapter(adapter);
<span style="color:blue;">var </span>db = <span style="color:#2b91af;">Database</span>.Open();
db.Customer.Insert(ID: 1, Name: <span style="color:#a31515;">"NASA"</span>);
db.Customer.Insert(ID: 2, Name: <span style="color:#a31515;">"ACME"</span>);
db.Order.Insert(ID: 1, CustomerID: 1, Date: <span style="color:blue;">new </span><span style="color:#2b91af;">DateTime</span>(1997, 1, 12));
db.Order.Insert(ID: 2, CustomerID: 2, Date: <span style="color:blue;">new </span><span style="color:#2b91af;">DateTime</span>(2001, 1, 1));

<span style="color:blue;">var </span>customers = db.Customer&nbsp;&nbsp;&nbsp; .FindAll(db.Customer.Orders.Date &lt; <span style="color:blue;">new </span><span style="color:#2b91af;">DateTime</span>(1999, 12, 31)).ToList();
<span style="color:#2b91af;">Assert</span>.IsNotNull(customers);
<span style="color:#2b91af;">Assert</span>.AreEqual(1, customers.Count);
</pre>
<p>And most query operations work OK.</p>
<p><strong>YMMV</strong>: This is probably not perfect, but it was stalling other development so I took the decision to release it. So far in my own projects it has not caused any problems; I’ve had one reported which is fixed in 0.11 (more on that in the next post).</p>
<h4>Bug fixes and such</h4>
<p>There were a bunch of fixes for various issues in 0.10, most of which were contributed by <a href="https://github.com/richardhopton">Richard Hopton</a>, who has also released an ADO provider for Sybase SQL Anywhere.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/197/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/197/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/197/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/197/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/197/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/197/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/197/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/197/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/197/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/197/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/197/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/197/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/197/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/197/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=197&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2011/11/24/simple-data-0-10/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
		<item>
		<title>I&#8217;m going 100% digital in 2012</title>
		<link>http://blog.markrendle.net/2011/11/21/im-going-100percen-digital-in-2012/</link>
		<comments>http://blog.markrendle.net/2011/11/21/im-going-100percen-digital-in-2012/#comments</comments>
		<pubDate>Mon, 21 Nov 2011 14:14:26 +0000</pubDate>
		<dc:creator>markrendle</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.markrendle.net/?p=192</guid>
		<description><![CDATA[I know it&#8217;s early for New Year resolutions, but I&#8217;m going to share this one now partly so I don&#8217;t forget in six weeks. I buy a lot of media. I have an entire 6&#8242;x3&#8242; bookcase full of technical books, most of which are out of date by at least one version. There&#8217;s a cubic [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=192&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I know it&#8217;s early for New Year resolutions, but I&#8217;m going to share this one now partly so I don&#8217;t forget in six weeks.</p>
<p>I buy a <em>lot</em> of media. I have an entire 6&#8242;x3&#8242; bookcase full of technical books, most of which are out of date by at least one version. There&#8217;s a cubic hectare of Blu-ray and DVD boxes lying around the place, and I&#8217;m pretty sure there are boxes of CDs (remember those?) in the loft somewhere. Probably half the available storage space in my house is taken up with things which would actually fit on a few terabytes of hard disk.</p>
<p>It&#8217;s not like everything in the house isn&#8217;t already digital. We&#8217;ve got a 160GB iPod Classic, iPhones, iPads, Kindles, three laptops, an Xbox 360, a PS3 (with a 320GB HD), a 50Mbps internet connection, and on Saturday we bought an Apple TV.</p>
<p>It&#8217;s ridiculous. It has to stop. It ends, starting in January. From then on, where a digital purchase option is available, I shall avail myself of it. I will invest in a home server with a few TB of storage on mirrored drives; I&#8217;m thinking of the Lacie 5big Network 2, which will take up to 10TB. Then I can &#8220;back up&#8221; my movie collection to that, and install iTunes on it for music streaming. Paper books will go to charities and libraries; if I want to read any of them again, I&#8217;ll buy them in ebook format. Magazines through Newsstand and papers through the Times iPad app.</p>
<p>Now, I just need Sony and Microsoft to distribute all PS3 and Xbox games digitally, and I need never darken the door of another shop. Not that I do anyway. All this crap comes from Amazon.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/markrendle.wordpress.com/192/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/markrendle.wordpress.com/192/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/markrendle.wordpress.com/192/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/markrendle.wordpress.com/192/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/markrendle.wordpress.com/192/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/markrendle.wordpress.com/192/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/markrendle.wordpress.com/192/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/markrendle.wordpress.com/192/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/markrendle.wordpress.com/192/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/markrendle.wordpress.com/192/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/markrendle.wordpress.com/192/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/markrendle.wordpress.com/192/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/markrendle.wordpress.com/192/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/markrendle.wordpress.com/192/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=blog.markrendle.net&amp;blog=16759552&amp;post=192&amp;subd=markrendle&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://blog.markrendle.net/2011/11/21/im-going-100percen-digital-in-2012/feed/</wfw:commentRss>
		<slash:comments>40</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/cc060db2b5331d8cbbfe080cec4add6f?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">markrendle</media:title>
		</media:content>
	</item>
	</channel>
</rss>
