<?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/"
	>

<channel>
	<title>Implement IToddWood</title>
	<atom:link href="http://www.woodcp.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.woodcp.com</link>
	<description>Technology Blog for Todd A. Wood, Solution Architect and Owner of Wood Consulting Practice, LLC</description>
	<lastBuildDate>Fri, 01 Mar 2013 14:43:18 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Git Unite &#8211; Fix Case Sensitive File Paths on Windows</title>
		<link>http://www.woodcp.com/2013/01/git-unite-fix-case-sensitive-file-paths-on-windows/</link>
		<comments>http://www.woodcp.com/2013/01/git-unite-fix-case-sensitive-file-paths-on-windows/#comments</comments>
		<pubDate>Mon, 14 Jan 2013 04:34:38 +0000</pubDate>
		<dc:creator>Todd Wood</dc:creator>
				<category><![CDATA[Git]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[windows]]></category>

		<guid isPermaLink="false">http://www.woodcp.com/?p=120</guid>
		<description><![CDATA[Git Unite is a utility that fixes case sensitive file paths present in a git repository index on Windows. Since Windows is not case sensitive, the git index case sensitivity issue does not manifest itself until browsing the code repository &#8230; <a href="http://www.woodcp.com/2013/01/git-unite-fix-case-sensitive-file-paths-on-windows/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p><a title="git-unite on GitHub" href="https://github.com/tawman/git-unite" target="_blank">Git Unite</a> is a utility that fixes case sensitive file paths present in a git repository index on Windows. Since Windows is not case sensitive, the git index case sensitivity issue does not manifest itself until browsing the code repository on GitHub or cloning the repository to a case sensitive file system on Linux.</p>
<p>Introducing case sensitive file paths into the git index on a case insensitive operating system like Windows is easier than you think. A simple ‘<em>git mv .\Where\Waldo where\is\Waldo</em>&#8216; is all you need to create two separate paths in the git index, but the Windows working directory will only report one. There might be <em>git config</em> settings that help avoid this problem, but controlling the settings and behavior of 20+ contributors on a project team is nearly impossible.</p>
<p>The problem is exacerbated when hundreds of files are moved during a repository layout reorganization. If the user moving the files is not careful, these case sensitive path names will pollute the git index but appear fine in the working directory. Cleaning up these case sensitive file path issues on Windows is tedious, and this is where Git Unite helps out.</p>
<p>Git Unite will search the git repository index for file paths that do not match the same case that Windows is using. For each git index path case mismatch found, Git Unite will update the git index entry with the case reported by the Windows file system.</p>
<h2>Usage</h2>
<pre>Usage: Git.Unite [OPTIONS]+ repository
Unite the git repository index file paths with current Windows case usage.
If no repository path is specified, the current directory is used.

Options:
      --dry-run              dry run without making changes
  -h, --help                 show this message and exit
</pre>
<h2>History</h2>
<p>I work on a project that has one particular git repository tracking over 7,000 files. The repository contains a mixture of ASP.NET MVC3 code, SQL Server SSIS ETL packages, and PowerShell scripts. It all started one day when an ETL developer could not locate the package she developed on the GitHub web site.</p>
<p>I took a look at the git repository on her machine and the ETL package was clearly there under an <em>Etl\Some\Dir\Path</em> folder. The repository reported being up to date with origin/master, but it took several minutes before I noticed an <em>etl</em> and <em>Etl</em> folder on the GitHub web site.</p>
<p>It turns out that the ETL team was in the process reorganizing the ETL packages into a new directory structure layout. I booted up a VM running Ubuntu and cloned the repository down to a case sensitive file system. I found 694 ETL files that were tracked in the git index with a directory path case different than the one reported by the Windows file system.</p>
<p>I fixed the problem by using a combination of <em>find</em>, <em>sort</em>, and <em>awk</em> to build a bash script to run the 694 git mv commands. This was a painful process that I did not want to repeat so I decided to build a tool anyone on the team could use on Windows to fix the problem.</p>
<p>In fact, two months later the same issue appeared again in a different repository. This time I was able to install the Git Unite utility on the user’s machine and fix the issue in a couple minutes. We tracked down the source of the problem to a developer that hand-typed the target directory of a git mv command in all lowercase.</p>
<h2>Example Scenario</h2>
<p>Here is a representative example using Posh-Git on Windows 7 as to how someone can introduce case sensitive file paths on a case insensitive file system.</p>
<h3>Step 1 – Create a new git repository and push it to GitHub</h3>
<pre>C:\demo&gt; mkdir Where
C:\demo&gt; touch .\Where\Waldo
C:\demo&gt; touch .\Where\IsHere
C:\demo&gt; git init .
Initialized empty Git repository in C:/demo/.git/
C:\demo [master +1 ~0 -0 !]&gt; git add .
C:\demo [master +2 ~0 -0]&gt; git commit -m initial
[master (root-commit) 42ea0fc] initial
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 Where/IsHere
 create mode 100644 Where/Waldo

C:\demo [master]&gt; git remote add origin git@github.com:tawman/waldo.git
C:\demo [master]&gt; git push -u origin master
Counting objects: 4, done.
Delta compression using up to 6 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 265 bytes, done.
Total 4 (delta 0), reused 0 (delta 0)
To git@github.com:tawman/waldo.git
 * [new branch]      master -&gt; master
Branch master set up to track remote branch master from origin.
</pre>
<p>When we look on GitHub the repository appears as expected:<a href="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2013/01/Step1.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Initial repository as seen on GitHub" border="0" alt="Initial repository as seen on GitHub" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2013/01/Step1_thumb.png" width="644" height="256"></a></p>
<h3>Step 2 – Start asking some questions</h3>
<pre>C:\demo [master]&gt; mkdir .\Where\Is
C:\demo [master]&gt; touch .\Where\Is\He
C:\demo [master +1 ~0 -0 !]&gt; git add -A
C:\demo [master +1 ~0 -0]&gt; git commit -m "Good Question"
[master 3d9006e] Good Question
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 Where/Is/He
</pre>
<p>Keep a close eye on <em>where</em> Waldo is going&#8230;</p>
<pre>C:\demo [master]&gt; git mv .\Where\Waldo where\is\Waldo
C:\demo [master +0 ~1 -0]&gt; git commit -m "Find Me"
[master 35f843b] Find Me
 1 files changed, 0 insertions(+), 0 deletions(-)
 rename {Where =&gt; where/is}/Waldo (100%)

C:\demo [master]&gt; find Where
Where
Where/Is
Where/Is/He
Where/Is/Waldo
Where/IsHere
C:\demo [master]&gt; ls


    Directory: C:\demo


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         1/12/2013  10:54 PM            Where
</pre>
<p>Seems quite obvious <em>Where</em> Waldo is, but let’s check what GitHub thinks:</p>
<pre>C:\demo [master]&gt; git push
Counting objects: 11, done.
Delta compression using up to 6 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (9/9), 683 bytes, done.
Total 9 (delta 1), reused 0 (delta 0)
To git@github.com:tawman/waldo.git
   42ea0fc..35f843b  master -&gt; master
</pre>
<p>It would appear that git and GitHub have narrowed down the location of Waldo to one of two possible locations:<a href="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2013/01/Step2.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="GitHub is not exactly sure where he is at" border="0" alt="GitHub is not exactly sure where he is at" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2013/01/Step2_thumb.png" width="644" height="132"></a></p>
<h3>Step 3 – Let the confusion begin</h3>
<pre>C:\demo [master]&gt; ls .\Where\Is\Waldo


    Directory: C:\demo\Where\Is


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         1/12/2013  10:50 PM          0 Waldo
</pre>
<p>According to Windows, Waldo should be hanging out right here:<a href="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2013/01/Step3a.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Is he here?" border="0" alt="Is he here?" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2013/01/Step3a_thumb.png" width="644" height="133"></a>Unfortunately, according to git he is hanging out over there:</p>
<p><a href="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2013/01/Step3b.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Or is he here?" border="0" alt="Or is he here?" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2013/01/Step3b_thumb.png" width="644" height="129"></a></p>
<h3>Step 4 – Get everyone back on the same page with Git Unite</h3>
<pre>C:\demo [master]&gt; Git.Unite.exe C:\demo
C:\demo [master +0 ~1 -0]&gt; git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       renamed:    where/is/Waldo -&gt; Where/Is/Waldo
#
C:\demo [master +0 ~1 -0]&gt; git commit -m fixed
[master 4495f40] fixed
 1 files changed, 0 insertions(+), 0 deletions(-)
 rename {where/is =&gt; Where/Is}/Waldo (100%)
C:\demo [master]&gt; git push
Counting objects: 7, done.
Delta compression using up to 6 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 354 bytes, done.
Total 4 (delta 0), reused 0 (delta 0)
To git@github.com:tawman/waldo.git
   35f843b..4495f40  master -&gt; master
</pre>
<p>Git Unite clears up the confusion by reconciling the git index file path with the same case Windows is using. When I go back and look at the repository on GitHub, there is only one place <em>Where</em> Waldo could be:<a href="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2013/01/Step4a.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Everyone is back Where expected" border="0" alt="Everyone is back Where expected" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2013/01/Step4a_thumb.png" width="644" height="105"></a> As far as Windows was concerned, Waldo was here the whole time:<a href="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2013/01/Step4b.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="I knew he was here the whole time" border="0" alt="I knew he was here the whole time" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2013/01/Step4b_thumb.png" width="644" height="152"></a></p>
<p><a title="Fork me on GitHub" href="https://github.com/tawman/git-unite" target="_blank">Fork me on GitHub</a></p>
<p><a href="https://github.com/tawman/git-unite" target="_blank"><img style="position: absolute; border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; right: 0px; top: 0px" alt="Fork me on GitHub" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.woodcp.com/2013/01/git-unite-fix-case-sensitive-file-paths-on-windows/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>PowerShell Object Pipeline</title>
		<link>http://www.woodcp.com/2012/04/powershell-object-pipeline/</link>
		<comments>http://www.woodcp.com/2012/04/powershell-object-pipeline/#comments</comments>
		<pubDate>Sun, 15 Apr 2012 19:22:51 +0000</pubDate>
		<dc:creator>Todd Wood</dc:creator>
				<category><![CDATA[PowerShell]]></category>

		<guid isPermaLink="false">http://www.woodcp.com/?p=104</guid>
		<description><![CDATA[On .NET projects today, a common theme with setup and builds scripts is psake and Windows PowerShell. A development team member on my current project is a PowerShell Ninja, which prompted me to learn more about PowerShell this weekend. I &#8230; <a href="http://www.woodcp.com/2012/04/powershell-object-pipeline/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>On .NET projects today, a common theme with setup and builds scripts is <a href="https://github.com/psake/psake" target="_blank"><em>psake</em></a> and <a href="http://technet.microsoft.com/en-us/dd793612" target="_blank">Windows PowerShell</a>. A development team member on my current project is a PowerShell Ninja, which prompted me to learn more about PowerShell this weekend. I watched an excellent five-part webcast series by Ed Wilson (<a href="https://twitter.com/#!/ScriptingGuys" target="_blank">@ScriptingGuys</a>) on <a href="http://technet.microsoft.com/en-us/scriptcenter/dd742419" target="_blank">Scripting with Windows PowerShell</a> that got me up to speed in a couple hours.</p>
<p>These webcasts changed my viewpoint of PowerShell from being a VBScript replacement (that I never used) to a powerful scripting framework and shell. I have modified and extended existing <em>psake</em> build scripts, but I did not realize some of the key concepts lurking just below the surface.</p>
<p>I did not consider it possible that PowerShell pipelines objects between commands instead of strings due to the many years I spent developing shell scripts on UNIX/Linux. Once Ed explained this key concept, I discarded my preconceived understanding of PowerShell and watched the entire series to learn more.</p>
<p>I can only imagine how useful object pipelining in UNIX shell scripts would be after witnessing the equivalent in PowerShell. For example, getting basic process information from the bash prompt on the Mac can be done with the <em>ps</em> command. The output of the <em>ps</em> command can be manipulated as standard ASCII text:</p>
<div><script src="https://gist.github.com/2394435.js?file=BashShell.txt"></script></div>
<p>Conversely, the same process information in PowerShell passes along the entire process object to the next command to inspect:</p>
<div><script src="https://gist.github.com/2394445.js?file=PowerShell.txt"></script></div>
<p>Object passing between commands in PowerShell is just a minor fact hardly worth blogging about, but it is a fundamental reason you should ignore decades of preconceived ideas about shell scripting and give PowerShell an honest look.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.woodcp.com/2012/04/powershell-object-pipeline/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>PetaPoco Custom SQL Paging</title>
		<link>http://www.woodcp.com/2012/03/petapoco-custom-sql-paging/</link>
		<comments>http://www.woodcp.com/2012/03/petapoco-custom-sql-paging/#comments</comments>
		<pubDate>Sun, 25 Mar 2012 03:08:42 +0000</pubDate>
		<dc:creator>Todd Wood</dc:creator>
				<category><![CDATA[PetaPoco]]></category>

		<guid isPermaLink="false">http://www.woodcp.com/?p=102</guid>
		<description><![CDATA[I blogged previously about Server-Side Paging with PetaPoco and DataTables, which works well for about 80% of the SQL statements that require server-side paging. In fact, I already submitted a pull request in December 2011 to modify the rxOrderBy Regex &#8230; <a href="http://www.woodcp.com/2012/03/petapoco-custom-sql-paging/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I blogged previously about <a href="http://www.woodcp.com/2012/02/server-side-paging-with-petapoco-and-datatables/" target="_blank">Server-Side Paging with PetaPoco and DataTables</a>, which works well for about 80% of the SQL statements that require server-side paging. In fact, I already submitted a <a href="https://github.com/toptensoftware/PetaPoco/pull/94" target="_blank">pull request</a> in December 2011 to modify the <em>rxOrderBy</em> Regex used by <a href="http://www.toptensoftware.com/petapoco/" target="_blank">PetaPoco</a> during <em>Page&lt;T&gt;</em> query rewrite to support sub-select ordering containing <em>ROW_NUMBER() PARTITION BY</em>.</p>
<p>The latest query from the 20% unsupported category prompted my <a href="https://github.com/toptensoftware/PetaPoco/pull/104" target="_blank">pull request</a> to bypass the PetaPoco query rewrite logic entirely and allow the caller to provide the <em>count</em> and <em>paging</em> queries. After all, PetaPoco is a single-file micro-ORM that expects the user to understand SQL already. The secret sauce covers the low friction data access layer between the database and your POCOs, and not the SQL itself.</p>
<p>Currently, PetaPoco supports server-side paging with the following <em>Page&lt;T&gt;</em> method overloads that generate <em>count</em> and <em>page</em> results queries from a single SQL statement:</p>
<ul>
<li><font face="Consolas">public Page&lt;T&gt; Page&lt;T&gt;(long page, long itemsPerPage, Sql sql)</font>
<li><font face="Consolas">public Page&lt;T&gt; Page&lt;T&gt;(long page, long itemsPerPage, string sql, params object[] args)</font></li>
</ul>
<p>My <a href="https://github.com/toptensoftware/PetaPoco/pull/104" target="_blank">pull request</a> simply adds another <em>Page&lt;T&gt;</em> method overload that accepts the two SQL statements to use for the count and page results without calling the <em>BuildPageQueries&lt;T&gt;</em> method: <font face="Consolas">public Page&lt;T&gt; Page&lt;T&gt;(long page, long itemsPerPage, Sql sqlCount, Sql sqlPage)</font></p>
<p>The following gist provides a sample set of queries using the new Page&lt;T&gt; overload:</p>
<div><script src="https://gist.github.com/2126002.js?file=SamplePetaPocoPageCustomSql.cs"></script></div>
<p>There has not been much activity in the <a href="https://github.com/toptensoftware/PetaPoco" target="_blank">PetaPoco GitHub repository</a> in over 8 months, so you might want to pull this change into your own fork if faced with similar server-side paging requirements. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.woodcp.com/2012/03/petapoco-custom-sql-paging/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Server-Side Paging with PetaPoco and DataTables</title>
		<link>http://www.woodcp.com/2012/02/server-side-paging-with-petapoco-and-datatables/</link>
		<comments>http://www.woodcp.com/2012/02/server-side-paging-with-petapoco-and-datatables/#comments</comments>
		<pubDate>Sun, 19 Feb 2012 02:52:18 +0000</pubDate>
		<dc:creator>Todd Wood</dc:creator>
				<category><![CDATA[DataTables]]></category>
		<category><![CDATA[PetaPoco]]></category>

		<guid isPermaLink="false">http://www.woodcp.com/?p=99</guid>
		<description><![CDATA[TL;DR – Server-side paging of table data is not only faster and more responsive, but very easy to implement with PetaPoco and DataTables. I will demonstrate how millisecond response times are still possible even when dealing with a million rows &#8230; <a href="http://www.woodcp.com/2012/02/server-side-paging-with-petapoco-and-datatables/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>TL;DR – Server-side paging of table data is not only faster and more responsive, but very easy to implement with <a href="http://www.toptensoftware.com/petapoco/" target="_blank">PetaPoco</a> and <a href="http://datatables.net/" target="_blank">DataTables</a>. I will demonstrate how millisecond response times are still possible even when dealing with a million rows of data.</p>
<p>This blog post can be forked on <a href="https://github.com/tawman/PetaPocoPage" target="_blank">GitHub: tawman / PetaPocoPage</a>.</p>
<h2>Sample Web Site and Data</h2>
<p>For the sample web site, I used the <a href="http://spawner.sourceforge.net/" target="_blank">Spawner Data Generator</a> tool to generate 1,000,000 rows of test data for use in this example. As you can see from the timings, each table grid page request is limited to approximately 1.25 KB of data and a response time around 75 milliseconds. </p>
<p><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="SiteTimings" border="0" alt="SiteTimings" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2012/02/SiteTimings.jpg" width="630" height="586"></p>
<p>On my current project, we initially used <a href="http://tablesorter.com/docs/" target="_blank">jQuery tablesorter</a> with a table loading between 1,000 and 1,500 detail records for a report. There was a noticeable delay of a couple seconds while the data loaded. Obviously, we needed to implement server-side paging and I knew <a href="http://www.toptensoftware.com/petapoco/" target="_blank">PetaPoco</a> could help on the backend. However, tablesorter had some other issues with searching paged tables that lead me to discover <a href="http://datatables.net/" target="_blank">DataTables</a></p>
<h2>DataTables</h2>
<p>DataTables is a great extensible jQuery plug-in and satisfied our searching, paging, and server-side processing requirements. The only negative issue I had is cosmetic since DataTables uses <a href="http://en.wikipedia.org/wiki/Hungarian_notation" target="_blank">Hungarian notation</a>. The other features and extensibility options shine through making DataTables an excellent client side UI choice.</p>
<h3>Client Side Setup</h3>
<p>Wiring up a view table with DataTables is very simple, and adding the server-side callbacks and Twitter Bootstrap formatting is also very straight forward. In my example view, there is very little markup required and actually no model is provided:</p>
<div><script src="https://gist.github.com/1861582.js"></script></div>
<p>The sample project also includes some additional JavaScript to setup a 500 ms filtering delay before sending the search term back to the server, pagination styling, and CSS styling. Fortunately, the DataTables library is thoroughly documented on its web site along with these extension configurations.</p>
<h3>Server Side Setup</h3>
<p>DataTables will POST a JSON request back to the server Controller that I process with a custom <em>IModelBinder</em> to keep the Controller code clean and remove the Hungarian notation:</p>
<div><script src="https://gist.github.com/1861621.js"></script></div>
<p>The combination of the <em>IModelBinder</em> and a helper method to format the DataTable response keeps the Controller action code simple:</p>
<div><script src="https://gist.github.com/1861623.js"></script></div>
<p>The DataTable response formatter simply combines the <em>DataTablesPageRequest</em> object with the PetaPoco <em>Page&lt;Customer&gt;</em> object into a JSON response expected by DataTables:</p>
<div><script src="https://gist.github.com/1861658.js"></script></div>
<p>Fortunately, the DataTable request and response object formats are very compatible with how PetaPoco support paging.</p>
<h2>PetaPoco</h2>
<p>PetaPoco makes it very simple and efficient to issue paged queries to SQL Server and it handles the query rewrite to use <em>ROW_NUMBER</em> for you. The resulting PetaPoco <em>Page&lt;T&gt;</em> object makes it easy to interface with the DataTables response object:</p>
<pre><code>
public class Page&lt;T&gt; where T:new()
{
    public long CurrentPage { get; set; }
    public long ItemsPerPage { get; set; }
    public long TotalPages { get; set; }
    public long TotalItems { get; set; }
    public List&lt;T&gt; Items { get; set; }
}</code></pre>
<p>To support the DataTables searching and ordering in my sample project, I used some helper methods to apply the search criteria against all columns and order by the columns selected. The resulting repository method to handle the PetaPoco Page&lt;T&gt; query request is quite straightforward:</p>
<div><script src="https://gist.github.com/1861686.js"></script></div>
<p>In the end, it does not matter if you are dealing with 100, 1,000, or 1,000,000 rows of data. You can still achieve fast page response times and low latency calls to your backend database to serve data up one page at a time. The following timings are from pressing the Next page link 7 times:</p>
<p><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="Timings" border="0" alt="Timings" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2012/02/Timings.png" width="634" height="351"></p>
<h2>Conclusion</h2>
<p>The million row sample data is not a practical use case and merely used to illustrate a point. In fact, I reduced the sample data down to 4,000 rows for publishing on GitHub as a 250 MB database is not very clone friendly. Have a look at the project source on <a href="https://github.com/tawman/PetaPocoPage" target="_blank">GitHub: tawman / PetaPocoPage</a> and I hope it provides a useful reference for someone faced with a similar challenge.</p>
<p>DataTables and PetaPoco were made to page together.</p>
<p><a href="https://github.com/tawman/PetaPocoPage" target="_blank"><img style="position: absolute; border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; right: 0px; top: 0px" alt="Fork me on GitHub" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.woodcp.com/2012/02/server-side-paging-with-petapoco-and-datatables/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>PetaPoco DoddleReport Dynamic PIVOT Query</title>
		<link>http://www.woodcp.com/2012/02/petapoco-doddlereport-dynamic-pivot-query/</link>
		<comments>http://www.woodcp.com/2012/02/petapoco-doddlereport-dynamic-pivot-query/#comments</comments>
		<pubDate>Sun, 12 Feb 2012 04:59:04 +0000</pubDate>
		<dc:creator>Todd Wood</dc:creator>
				<category><![CDATA[DoddleReport]]></category>
		<category><![CDATA[PetaPoco]]></category>
		<category><![CDATA[doddlereport]]></category>

		<guid isPermaLink="false">http://www.woodcp.com/?p=94</guid>
		<description><![CDATA[TL;DR – Sample ASP.NET MVC3 application demonstrating how to load PIVOT query results as a dynamic object with PetaPoco and exporting the data to Excel using DoddleReport. This blog post can be forked on GitHub: tawman / PetaPocoPivot. Dynamic Data &#8230; <a href="http://www.woodcp.com/2012/02/petapoco-doddlereport-dynamic-pivot-query/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>TL;DR – Sample ASP.NET MVC3 application demonstrating how to load PIVOT query results as a dynamic object with <a href="http://www.toptensoftware.com/petapoco/" target="_blank">PetaPoco</a> and exporting the data to Excel using <a href="http://doddlereport.codeplex.com/" target="_blank">DoddleReport</a>.</p>
<p>This blog post can be forked on <a href="https://github.com/tawman/PetaPocoPivot" target="_blank">GitHub: tawman / PetaPocoPivot</a>.</p>
<h2>Dynamic Data Structures with PIVOT</h2>
<p>SQL Server 2008 R2 provides the capability to <a href="http://msdn.microsoft.com/en-us/library/ms177410.aspx" target="_blank">PIVOT and UNPIVOT</a> table data depending on your need to flatten rows into columns or columns into rows. In our case, we needed to transform multiple rows of employee expiration dates into a single employee row with columns for each requirement expiration date.</p>
<h3>SQL PIVOT Query Example</h3>
<p>The following source data is used to illustrate a SQL PIVOT query in action:<br />
<table border="1">
<thead>
<tr>
<th>Employee</th>
<th>Requirement</th>
<th>Expiration Date</th>
</tr>
</thead>
<tbody>
<tr>
<td>John Doe</td>
<td>Alpha</td>
<td>01/12/2011</td>
</tr>
<tr>
<td>John Doe</td>
<td>Bravo</td>
<td>11/07/2012</td>
</tr>
<tr>
<td>John Doe</td>
<td>Charlie</td>
<td><em>NULL</em></td>
</tr>
<tr>
<td>John Doe</td>
<td>Delta</td>
<td>10/11/2009</td>
</tr>
<tr>
<td>Sally Smith</td>
<td>Bravo</td>
<td>05/10/2012</td>
</tr>
<tr>
<td>Sally Smith</td>
<td>Charlie</td>
<td>07/04/2012</td>
</tr>
<tr>
<td>Sally Smith</td>
<td>Echo</td>
<td>08/31/2012</td>
</tr>
</tbody>
</table>
<p>A simple SQL PIVOT query to transform the data:</p>
<pre>SELECT *
FROM(SELECT * FROM UserRequirement) AS UserInfo
PIVOT (MIN(ExpirationDate) 
       FOR Requirement IN ([Alpha], [Bravo], [Charlie], [Delta], [Echo])
) AS UserPivot
</pre>
<p>The following table illustrates the results of the SQL PIVOT query: </p>
<table border="1">
<thead>
<tr>
<th>Employee</th>
<th>Alpha</th>
<th>Bravo</th>
<th>Charlie</th>
<th>Delta</th>
<th>Echo</th>
</tr>
</thead>
<tbody>
<tr>
<td>John Doe</td>
<td>01/12/2011</td>
<td>11/07/2012</td>
<td>&nbsp;</td>
<td>10/11/2009</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>Sally Smith</td>
<td>&nbsp;</td>
<td>05/10/2012</td>
<td>07/04/2012</td>
<td>&nbsp;</td>
<td>08/31/2012</td>
</tr>
</tbody>
</table>
<h3>Data Driven Object Structure</h3>
<div>
<p>Obviously, defining a POCO object to load the PIVOT data ahead of time is not possible if the aggregated column values are not known until runtime. Our initial implementation bypassed PetaPoco entirely and used a <em>DataTable</em> to export the data to Excel using DoddleReport. Working around PetaPoco did not seem right so I looked for an alternate approach involving PetaPoco.</p>
<h2>PetaPoco and Dynamic Types</h2>
<p>Fortunately, C# provides a <a href="http://msdn.microsoft.com/en-us/library/dd264741.aspx" target="_blank">dynamic type</a> but I did not know if PetaPoco and DoddleReport could support this option. Every time I think we pushed PetaPoco to its limit, I learn that it has more tricks up its sleeve. I decided to not even consult the documentation and wired it up to see if we could return an <em>IEnumerable&lt;dynamic&gt;</em> instead of a <em>DataTable</em>.</p>
<p>The answer came as no surprise when coding the PIVOT query into the Repository that PetaPoco could care less if you actually had a POCO:</p>
</div>
<div><script src="https://gist.github.com/1806105.js"></script></div>
<h2>DoddleReport and Dynamic Types</h2>
<div>
<p>Now that PetaPoco was returning a dynamic data set, I needed to figure out what DoddleReport could do with it. I had not worked with DoddleReport up to this point, but quickly located the code in our Controller that performed the export to Excel functionality. I checked the <em>ToReportSource()</em> method overloads and saw it had one for an <em>IEnumerable</em>.</p>
<p>Typical <em>ReportResult</em> Action with DoddleReport does not require much code, but it sure does a lot behind the scenes:</p>
</div>
<div><script src="https://gist.github.com/1806138.js"></script></div>
<p>My first attempt to run the export with no change to the DoddleReport code was met with a blank export. I <a href="https://twitter.com/#!/iToddWood/status/167737343623696387" target="_blank">tweeted</a> out my status of trying this and <a href="http://www.matthidinger.com/" target="_blank">Matt Hidinger</a> quickly pointed me to the <a href="http://doddlereport.codeplex.com/SourceControl/changeset/view/840affd7397e#src%2fDoddleReport%2fDynamic%2fDynamicReportSource.cs" target="_blank">DynamicReportSource.cs on CodePlex</a>. I added the <em>DynamicReportSource</em> code as a Helper in my project (Note: There is a <a href="http://nuget.org/packages/DoddleReport.Dynamic" target="_blank">Nuget package</a> for it) and tried to use it. The first issue I ran into was that the code used an <em>ExpandoObject</em>, but I changed it to use <em>dynamic</em> instead. The second issue I ran into was the handling of NULL values, but I worked around this by using a <em>new object()</em> when the <em>t.Value</em> is null.</p>
<p>Modified DoddleReport <em>DynamicReportSource.cs</em> file used:</p>
<div><script src="https://gist.github.com/1784079.js"></script></div>
<h2>Dynamic PetaPoco and DoddleReport</h2>
<p>With the final changes to DoddleReport in place, our project now supports exporting PIVOT reports to Microsoft Excel. I put together a <a href="https://github.com/tawman/PetaPocoPivot" target="_blank">sample ASP.NET MVC3 application</a> that demonstrates the flow of the dynamic data from SQL Server via PetaPoco and DoddleReport to Excel.</p>
<h3>Standard MVC ActionResult View</h3>
<div>
<p>The default Index action displays the dynamic data in a normal table view by iterating over the dynamic results:<img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="PivotWebExample" border="0" alt="PivotWebExample" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2012/02/PivotWebExample.png" width="630" height="395"></p>
<h3>Exporting Data to Excel</h3>
<p>The <em>DoddleReport Excel</em> link in the header will call the /Home/PivotReport<em>.xlsx</em> ReportAction to trigger the export to Excel. The .xlsx extension it what tells DoddleReport we want an Excel result:</p>
<p><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="PivotExcelExample" border="0" alt="PivotExcelExample" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2012/02/PivotExcelExample.png" width="630" height="435"></p>
<h3>Generating a Default HTML View</h3>
<p>If you leave off the extension like the DoddleReport HTML header link does, then DoddleReport will generate the HTML view similar to the Index view I coded:<img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="PivotDoddleHtmlExample" border="0" alt="PivotDoddleHtmlExample" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2012/02/PivotDoddleHtmlExample.png" width="630" height="395"></p>
<p>DoddleReport supports additional formats like PDF, but I did not add the necessary Nuget packages to support it. With the proper library references in place, all it takes to generate a PDF is to add the .PDF extension to the ReportResult Action URL and DoddleReport will happily generate it for you.</p>
</div>
<h2>Conclusion</h2>
<div>
<p>Yet again I learned to never underestimate PetaPoco. I now have the same respect for DoddleReport as it makes a dynamic teammate with PetaPoco to deliver Excel exports based on our PIVOT query results.</p>
<p>I hope you found this blog post helpful and be sure to check out the full source code on <a href="https://github.com/tawman/PetaPocoPivot" target="_blank">GitHub: tawman / PetaPocoPivot</a> to see this dynamic pair in action.</p>
</div>
<p><a href="https://github.com/tawman/PetaPocoPivot" target="_blank"><img style="position: absolute; border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; right: 0px; top: 0px" alt="Fork me on GitHub" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.woodcp.com/2012/02/petapoco-doddlereport-dynamic-pivot-query/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Hierarchical Data with PetaPoco Multi-Poco Mapping</title>
		<link>http://www.woodcp.com/2012/02/hierarchical-data-with-petapoco-multi-poco-mapping/</link>
		<comments>http://www.woodcp.com/2012/02/hierarchical-data-with-petapoco-multi-poco-mapping/#comments</comments>
		<pubDate>Thu, 02 Feb 2012 03:50:56 +0000</pubDate>
		<dc:creator>Todd Wood</dc:creator>
				<category><![CDATA[PetaPoco]]></category>

		<guid isPermaLink="false">http://www.woodcp.com/?p=90</guid>
		<description><![CDATA[TL;DR – Sample ASP.NET MVC3 application demonstrating how to load hierarchical table data with a single SQL SELECT statement using PetaPoco’s&#160;Multi-Poco mapping feature. This blog post can be forked on GitHub: tawman / PetaPocoHierarchy. PetaPoco – A Tiny ORM-ish Thing &#8230; <a href="http://www.woodcp.com/2012/02/hierarchical-data-with-petapoco-multi-poco-mapping/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>TL;DR – Sample ASP.NET MVC3 application demonstrating how to load hierarchical table data with a single SQL <em>SELECT</em> statement using <a href="http://www.toptensoftware.com/petapoco/" target="_blank">PetaPoco’s</a>&nbsp;<a href="http://www.toptensoftware.com/Articles/115/PetaPoco-Mapping-One-to-Many-and-Many-to-One-Relationships" target="_blank">Multi-Poco mapping feature</a>.</p>
<p>This blog post can be forked on <a href="https://github.com/tawman/PetaPocoHierarchy" target="_blank">GitHub: tawman / PetaPocoHierarchy</a>.</p>
<h2>PetaPoco – A Tiny ORM-ish Thing</h2>
<p>We are using <a href="http://www.toptensoftware.com/petapoco/" target="_blank">PetaPoco</a> on a current project implementation since our data management needs do not <a href="http://ayende.com/blog/136195/when-should-you-use-nhibernate" target="_blank">rise to the level of NHibernate</a>. I learn something new each time I think we reached the limits of what PetaPoco can achieve for us. The most recent scenario involved loading hierarchical data without introducing a <a href="http://nhprof.com/Learn/Alerts/SelectNPlusOne" target="_blank">SELECT N+1 problem</a>. I will demonstrate how to use the PetaPoco Multi-Poco Mapping Feature to load hierarchical table data with a single SELECT statement.</p>
<h3>Multi-Poco Mapping Feature</h3>
<p><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="PetaPocoInfoGraphicDisplay" border="0" alt="PetaPocoInfoGraphicDisplay" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2012/02/PetaPocoInfoGraphicDisplay.png" width="630" height="298"></p>
<p>The <a href="http://www.toptensoftware.com/Articles/115/PetaPoco-Mapping-One-to-Many-and-Many-to-One-Relationships" target="_blank">PetaPoco – Mapping One-to-Many and Many-to-One Relationships</a> blog article described using the Multi-Poco Mapping Feature for loading one-to-many relationships, but I found the same technique works well with hierarchical data.</p>
<h4>Organization Hierarchical Data Example</h4>
<p>I built a simple ASP.NET MVC3 website involving an organization hierarchy modeled as a single table with a self-referencing column for the parent organization. The site contains a single page and table to display the hierarchical organization tree.</p>
<p>The DDL used to generate the table in SQL Server 2008 R2 Express is shown in the following gist:</p>
<div><script src="https://gist.github.com/1700953.js"></script></div>
<div>The following table illustrates the sample data loaded in the Organization table and used for this demo, but I replaced the Guid values with integers to make the parent-child relationships easier to identify:</div>
<div>&nbsp;</div>
<table border="1" cellspacing="0" cellpadding="2" width="606">
<thead>
<tr>
<th width="50">Id</th>
<th width="50">ParentId</th>
<th width="50">OrganizationCode</th>
<th width="450">Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
</tr>
<tr>
<td>2</td>
<td>1</td>
<td>MW</td>
<td>Midwest</td>
</tr>
<tr>
<td>3</td>
<td>1</td>
<td>NE</td>
<td>Northeast</td>
</tr>
<tr>
<td>4</td>
<td>1</td>
<td>NW</td>
<td>Northwest</td>
</tr>
<tr>
<td>5</td>
<td>1</td>
<td>SE</td>
<td>Southeast</td>
</tr>
<tr>
<td>6</td>
<td>1</td>
<td>SW</td>
<td>Southwest</td>
</tr>
<tr>
<td>7</td>
<td>2</td>
<td>MI</td>
<td>Michigan</td>
</tr>
<tr>
<td>8</td>
<td>2</td>
<td>IN</td>
<td>Indiana</td>
</tr>
<tr>
<td>9</td>
<td>2</td>
<td>IL</td>
<td>Illinois</td>
</tr>
<tr>
<td>10</td>
<td>2</td>
<td>OH</td>
<td>Ohio</td>
</tr>
<tr>
<td>11</td>
<td>7</td>
<td>WC</td>
<td>Wayne</td>
</tr>
<tr>
<td>12</td>
<td>7</td>
<td>WA</td>
<td>Washtenaw</td>
</tr>
<tr>
<td>13</td>
<td>11</td>
<td>DE</td>
<td>Detroit</td>
</tr>
<tr>
<td>14</td>
<td>11</td>
<td>CA</td>
<td>Canton</td>
</tr>
<tr>
<td>15</td>
<td>11</td>
<td>PM</td>
<td>Plymouth</td>
</tr>
<tr>
<td>16</td>
<td>12</td>
<td>AA</td>
<td>Ann Arbor</td>
</tr>
<tr>
<td>17</td>
<td>12</td>
<td>YP</td>
<td>Ypsilanti</td>
</tr>
<tr>
<td>18</td>
<td>16</td>
<td>UM</td>
<td>University of Michigan</td>
</tr>
<tr>
<td>19</td>
<td>17</td>
<td>EMU</td>
<td>Eastern Michigan University</td>
</tr>
</tbody>
</table>
<p>The website uses the following Organization POCO object to store the hierarchical data from the Organization table:</p>
<div><script src="https://gist.github.com/1701086.js"></script></div>
<div>Loading the data from SQL Server is accomplished with a single CTE query, but processed by PetaPoco with a custom helper method to transform the query results. The Organization Repository <em>GetAll()</em> method invokes the PetaPoco Multi-Poco Mapping feature as follows:</div>
<div>&nbsp;</div>
<div><script src="https://gist.github.com/1721103.js"></script></div>
<div>The CTE query prepares the Organization data for processing by the custom Multi-Poco Mapping Helper <em>OrganizationParentRelator().BuildHierarchy</em> with the following query result set (<em>only last 4 of Guid shown</em>):</div>
<div>&nbsp;</div>
<table style="font-size: 90%" border="1" cellspacing="0" cellpadding="0">
<thead>
<tr>
<th>Id</th>
<th>Parent</th>
<th>Code</th>
<th>Name</th>
<th>Id</th>
<th>Parent</th>
<th>Code</th>
<th>Name</th>
<th>Level</th>
<th>LinkId</th>
</tr>
</thead>
<tbody>
<tr>
<td>5D6B</td>
<td>26A5</td>
<td>SW</td>
<td>Southwest</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>1</td>
<td>5D6B</td>
</tr>
<tr>
<td>5D6B</td>
<td>26A5</td>
<td>SW</td>
<td>Southwest</td>
<td>5D6B</td>
<td>26A5</td>
<td>SW</td>
<td>Southwest</td>
<td>0</td>
<td>5D6B</td>
</tr>
<tr>
<td>FACC</td>
<td>BF51</td>
<td>WC</td>
<td>Wayne</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>3</td>
<td>FACC</td>
</tr>
<tr>
<td>FACC</td>
<td>BF51</td>
<td>WC</td>
<td>Wayne</td>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>2</td>
<td>FACC</td>
</tr>
<tr>
<td>FACC</td>
<td>BF51</td>
<td>WC</td>
<td>Wayne</td>
<td>BF51</td>
<td>88BB</td>
<td>MI</td>
<td>Michigan</td>
<td>1</td>
<td>FACC</td>
</tr>
<tr>
<td>FACC</td>
<td>BF51</td>
<td>WC</td>
<td>Wayne</td>
<td>FACC</td>
<td>BF51</td>
<td>WC</td>
<td>Wayne</td>
<td>0</td>
<td>FACC</td>
</tr>
<tr>
<td>BF51</td>
<td>88BB</td>
<td>MI</td>
<td>Michigan</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>2</td>
<td>BF51</td>
</tr>
<tr>
<td>BF51</td>
<td>88BB</td>
<td>MI</td>
<td>Michigan</td>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>1</td>
<td>BF51</td>
</tr>
<tr>
<td>BF51</td>
<td>88BB</td>
<td>MI</td>
<td>Michigan</td>
<td>BF51</td>
<td>88BB</td>
<td>MI</td>
<td>Michigan</td>
<td>0</td>
<td>BF51</td>
</tr>
<tr>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>0</td>
<td>26A5</td>
</tr>
<tr>
<td>3661</td>
<td>FACC</td>
<td>PM</td>
<td>Plymouth</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>4</td>
<td>3661</td>
</tr>
<tr>
<td>3661</td>
<td>FACC</td>
<td>PM</td>
<td>Plymouth</td>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>3</td>
<td>3661</td>
</tr>
<tr>
<td>3661</td>
<td>FACC</td>
<td>PM</td>
<td>Plymouth</td>
<td>BF51</td>
<td>88BB</td>
<td>MI</td>
<td>Michigan</td>
<td>2</td>
<td>3661</td>
</tr>
<tr>
<td>3661</td>
<td>FACC</td>
<td>PM</td>
<td>Plymouth</td>
<td>FACC</td>
<td>BF51</td>
<td>WC</td>
<td>Wayne</td>
<td>1</td>
<td>3661</td>
</tr>
<tr>
<td>3661</td>
<td>FACC</td>
<td>PM</td>
<td>Plymouth</td>
<td>3661</td>
<td>FACC</td>
<td>PM</td>
<td>Plymouth</td>
<td>0</td>
<td>3661</td>
</tr>
<tr>
<td>D24E</td>
<td>88BB</td>
<td>IL</td>
<td>Illinois</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>2</td>
<td>D24E</td>
</tr>
<tr>
<td>D24E</td>
<td>88BB</td>
<td>IL</td>
<td>Illinois</td>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>1</td>
<td>D24E</td>
</tr>
<tr>
<td>D24E</td>
<td>88BB</td>
<td>IL</td>
<td>Illinois</td>
<td>D24E</td>
<td>88BB</td>
<td>IL</td>
<td>Illinois</td>
<td>0</td>
<td>D24E</td>
</tr>
<tr>
<td>DCAC</td>
<td>BF51</td>
<td>WA</td>
<td>Washtenaw</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>3</td>
<td>DCAC</td>
</tr>
<tr>
<td>DCAC</td>
<td>BF51</td>
<td>WA</td>
<td>Washtenaw</td>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>2</td>
<td>DCAC</td>
</tr>
<tr>
<td>DCAC</td>
<td>BF51</td>
<td>WA</td>
<td>Washtenaw</td>
<td>BF51</td>
<td>88BB</td>
<td>MI</td>
<td>Michigan</td>
<td>1</td>
<td>DCAC</td>
</tr>
<tr>
<td>DCAC</td>
<td>BF51</td>
<td>WA</td>
<td>Washtenaw</td>
<td>DCAC</td>
<td>BF51</td>
<td>WA</td>
<td>Washtenaw</td>
<td>0</td>
<td>DCAC</td>
</tr>
<tr>
<td>FD9B</td>
<td>DCAC</td>
<td>YP</td>
<td>Ypsilanti</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>4</td>
<td>FD9B</td>
</tr>
<tr>
<td>FD9B</td>
<td>DCAC</td>
<td>YP</td>
<td>Ypsilanti</td>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>3</td>
<td>FD9B</td>
</tr>
<tr>
<td>FD9B</td>
<td>DCAC</td>
<td>YP</td>
<td>Ypsilanti</td>
<td>BF51</td>
<td>88BB</td>
<td>MI</td>
<td>Michigan</td>
<td>2</td>
<td>FD9B</td>
</tr>
<tr>
<td>FD9B</td>
<td>DCAC</td>
<td>YP</td>
<td>Ypsilanti</td>
<td>DCAC</td>
<td>BF51</td>
<td>WA</td>
<td>Washtenaw</td>
<td>1</td>
<td>FD9B</td>
</tr>
<tr>
<td>FD9B</td>
<td>DCAC</td>
<td>YP</td>
<td>Ypsilanti</td>
<td>FD9B</td>
<td>DCAC</td>
<td>YP</td>
<td>Ypsilanti</td>
<td>0</td>
<td>FD9B</td>
</tr>
<tr>
<td>18F8</td>
<td>FACC</td>
<td>DE</td>
<td>Detroit</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>4</td>
<td>18F8</td>
</tr>
<tr>
<td>18F8</td>
<td>FACC</td>
<td>DE</td>
<td>Detroit</td>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>3</td>
<td>18F8</td>
</tr>
<tr>
<td>18F8</td>
<td>FACC</td>
<td>DE</td>
<td>Detroit</td>
<td>BF51</td>
<td>88BB</td>
<td>MI</td>
<td>Michigan</td>
<td>2</td>
<td>18F8</td>
</tr>
<tr>
<td>18F8</td>
<td>FACC</td>
<td>DE</td>
<td>Detroit</td>
<td>FACC</td>
<td>BF51</td>
<td>WC</td>
<td>Wayne</td>
<td>1</td>
<td>18F8</td>
</tr>
<tr>
<td>18F8</td>
<td>FACC</td>
<td>DE</td>
<td>Detroit</td>
<td>18F8</td>
<td>FACC</td>
<td>DE</td>
<td>Detroit</td>
<td>0</td>
<td>18F8</td>
</tr>
<tr>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>1</td>
<td>88BB</td>
</tr>
<tr>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>0</td>
<td>88BB</td>
</tr>
<tr>
<td>947A</td>
<td>BB56</td>
<td>UM</td>
<td>University of Michigan</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>5</td>
<td>947A</td>
</tr>
<tr>
<td>947A</td>
<td>BB56</td>
<td>UM</td>
<td>University of Michigan</td>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>4</td>
<td>947A</td>
</tr>
<tr>
<td>947A</td>
<td>BB56</td>
<td>UM</td>
<td>University of Michigan</td>
<td>BF51</td>
<td>88BB</td>
<td>MI</td>
<td>Michigan</td>
<td>3</td>
<td>947A</td>
</tr>
<tr>
<td>947A</td>
<td>BB56</td>
<td>UM</td>
<td>University of Michigan</td>
<td>DCAC</td>
<td>BF51</td>
<td>WA</td>
<td>Washtenaw</td>
<td>2</td>
<td>947A</td>
</tr>
<tr>
<td>947A</td>
<td>BB56</td>
<td>UM</td>
<td>University of Michigan</td>
<td>BB56</td>
<td>DCAC</td>
<td>AA</td>
<td>Ann Arbor</td>
<td>1</td>
<td>947A</td>
</tr>
<tr>
<td>947A</td>
<td>BB56</td>
<td>UM</td>
<td>University of Michigan</td>
<td>947A</td>
<td>BB56</td>
<td>UM</td>
<td>University of Michigan</td>
<td>0</td>
<td>947A</td>
</tr>
<tr>
<td>AB85</td>
<td>26A5</td>
<td>NW</td>
<td>Northwest</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>1</td>
<td>AB85</td>
</tr>
<tr>
<td>AB85</td>
<td>26A5</td>
<td>NW</td>
<td>Northwest</td>
<td>AB85</td>
<td>26A5</td>
<td>NW</td>
<td>Northwest</td>
<td>0</td>
<td>AB85</td>
</tr>
<tr>
<td>24D5</td>
<td>FACC</td>
<td>CA</td>
<td>Canton</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>4</td>
<td>24D5</td>
</tr>
<tr>
<td>24D5</td>
<td>FACC</td>
<td>CA</td>
<td>Canton</td>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>3</td>
<td>24D5</td>
</tr>
<tr>
<td>24D5</td>
<td>FACC</td>
<td>CA</td>
<td>Canton</td>
<td>BF51</td>
<td>88BB</td>
<td>MI</td>
<td>Michigan</td>
<td>2</td>
<td>24D5</td>
</tr>
<tr>
<td>24D5</td>
<td>FACC</td>
<td>CA</td>
<td>Canton</td>
<td>FACC</td>
<td>BF51</td>
<td>WC</td>
<td>Wayne</td>
<td>1</td>
<td>24D5</td>
</tr>
<tr>
<td>24D5</td>
<td>FACC</td>
<td>CA</td>
<td>Canton</td>
<td>24D5</td>
<td>FACC</td>
<td>CA</td>
<td>Canton</td>
<td>0</td>
<td>24D5</td>
</tr>
<tr>
<td>B338</td>
<td>88BB</td>
<td>IN</td>
<td>Indiana</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>2</td>
<td>B338</td>
</tr>
<tr>
<td>B338</td>
<td>88BB</td>
<td>IN</td>
<td>Indiana</td>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>1</td>
<td>B338</td>
</tr>
<tr>
<td>B338</td>
<td>88BB</td>
<td>IN</td>
<td>Indiana</td>
<td>B338</td>
<td>88BB</td>
<td>IN</td>
<td>Indiana</td>
<td>0</td>
<td>B338</td>
</tr>
<tr>
<td>F352</td>
<td>FD9B</td>
<td>EMU</td>
<td>Eastern Michigan University</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>5</td>
<td>F352</td>
</tr>
<tr>
<td>F352</td>
<td>FD9B</td>
<td>EMU</td>
<td>Eastern Michigan University</td>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>4</td>
<td>F352</td>
</tr>
<tr>
<td>F352</td>
<td>FD9B</td>
<td>EMU</td>
<td>Eastern Michigan University</td>
<td>BF51</td>
<td>88BB</td>
<td>MI</td>
<td>Michigan</td>
<td>3</td>
<td>F352</td>
</tr>
<tr>
<td>F352</td>
<td>FD9B</td>
<td>EMU</td>
<td>Eastern Michigan University</td>
<td>DCAC</td>
<td>BF51</td>
<td>WA</td>
<td>Washtenaw</td>
<td>2</td>
<td>F352</td>
</tr>
<tr>
<td>F352</td>
<td>FD9B</td>
<td>EMU</td>
<td>Eastern Michigan University</td>
<td>FD9B</td>
<td>DCAC</td>
<td>YP</td>
<td>Ypsilanti</td>
<td>1</td>
<td>F352</td>
</tr>
<tr>
<td>F352</td>
<td>FD9B</td>
<td>EMU</td>
<td>Eastern Michigan University</td>
<td>F352</td>
<td>FD9B</td>
<td>EMU</td>
<td>Eastern Michigan University</td>
<td>0</td>
<td>F352</td>
</tr>
<tr>
<td>4EE6</td>
<td>26A5</td>
<td>SE</td>
<td>Southeast</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>1</td>
<td>4EE6</td>
</tr>
<tr>
<td>4EE6</td>
<td>26A5</td>
<td>SE</td>
<td>Southeast</td>
<td>4EE6</td>
<td>26A5</td>
<td>SE</td>
<td>Southeast</td>
<td>0</td>
<td>4EE6</td>
</tr>
<tr>
<td>FCFC</td>
<td>88BB</td>
<td>OH</td>
<td>Ohio</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>2</td>
<td>FCFC</td>
</tr>
<tr>
<td>FCFC</td>
<td>88BB</td>
<td>OH</td>
<td>Ohio</td>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>1</td>
<td>FCFC</td>
</tr>
<tr>
<td>FCFC</td>
<td>88BB</td>
<td>OH</td>
<td>Ohio</td>
<td>FCFC</td>
<td>88BB</td>
<td>OH</td>
<td>Ohio</td>
<td>0</td>
<td>FCFC</td>
</tr>
<tr>
<td>22E8</td>
<td>26A5</td>
<td>NE</td>
<td>Northeast</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>1</td>
<td>22E8</td>
</tr>
<tr>
<td>22E8</td>
<td>26A5</td>
<td>NE</td>
<td>Northeast</td>
<td>22E8</td>
<td>26A5</td>
<td>NE</td>
<td>Northeast</td>
<td>0</td>
<td>22E8</td>
</tr>
<tr>
<td>BB56</td>
<td>DCAC</td>
<td>AA</td>
<td>Ann Arbor</td>
<td>26A5</td>
<td>NULL</td>
<td>US</td>
<td>United States</td>
<td>4</td>
<td>BB56</td>
</tr>
<tr>
<td>BB56</td>
<td>DCAC</td>
<td>AA</td>
<td>Ann Arbor</td>
<td>88BB</td>
<td>26A5</td>
<td>MW</td>
<td>Midwest</td>
<td>3</td>
<td>BB56</td>
</tr>
<tr>
<td>BB56</td>
<td>DCAC</td>
<td>AA</td>
<td>Ann Arbor</td>
<td>BF51</td>
<td>88BB</td>
<td>MI</td>
<td>Michigan</td>
<td>2</td>
<td>BB56</td>
</tr>
<tr>
<td>BB56</td>
<td>DCAC</td>
<td>AA</td>
<td>Ann Arbor</td>
<td>DCAC</td>
<td>BF51</td>
<td>WA</td>
<td>Washtenaw</td>
<td>1</td>
<td>BB56</td>
</tr>
<tr>
<td>BB56</td>
<td>DCAC</td>
<td>AA</td>
<td>Ann Arbor</td>
<td>BB56</td>
<td>DCAC</td>
<td>AA</td>
<td>Ann Arbor</td>
<td>0</td>
<td>BB56</td>
</tr>
</tbody>
</table>
<div>&nbsp;</div>
<div>The custom helper is supplied as a parameter to the PetaPoco Multi Fetch call:</div>
<div>
<blockquote><span style="color: #0000ff"><font face="Consolas">public</font></span><span style="color: #000000"><font face="Consolas"> <span style="color: #2b91af">List</span></font><span style="color: #000000"><font face="Consolas"> &lt;TRet&gt; Fetch&lt;T1, T2, TRet&gt;(<span style="color: #2b91af">Func</span></font><span style="color: #000000"><font face="Consolas"> &lt;T1, T2, TRet&gt; cb, <span style="color: #0000ff">string</span></font><span style="color: #000000"><font face="Consolas"> sql, <span style="color: #0000ff">params</span></font><span style="color: #000000"><font face="Consolas"> <span style="color: #0000ff">object</span></font><span style="color: #000000"><font face="Consolas"> [] args) <span style="color: #000000">{</span> <span style="color: #0000ff">return</span></font><span style="color: #000000"><font face="Consolas"> Query&lt;T1, T2, TRet&gt;(cb, sql, args).ToList(); <span style="color: #000000">}</span></font></p></blockquote>
</div>
<div>The repository query is structured such that each resulting row of data contains an Organization (T1) and Parent Organization (T2). The query will return multiple rows for the same Organization equal to its depth in the hierarchy. The rows are sorted by Organization Hierarchy Level in descending order.</div>
<div>&nbsp;</div>
<div>The <em>OrganizationParentRelator.BuildHierarchy(organization, parent)</em> helper method will push the parent organization upward as each Organization row is processed and then return the hierarchical representation of the Organization (TRet) when no more parents are present:</div>
<div><script src="https://gist.github.com/1721109.js"></script></div>
<h4>Resulting Organization Structure Displayed Online</h4>
<div><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="WebPageView" border="0" alt="WebPageView" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2012/02/WebPageView.png" width="630" height="492"></div>
<div>&nbsp;</div>
<h3>Conclusion</h3>
<div>I hope you found this blog post helpful and be sure to check out the full source code on <a href="https://github.com/tawman/PetaPocoHierarchy" target="_blank">GitHub: tawman / PetaPocoHierarchy</a>. The PetaPoco project page over on <a href="http://www.toptensoftware.com/petapoco/" target="_blank">Topten Software</a> has more examples under the blog posts sections for using the Multi-Poco Mapping feature in other ways.</div>
<p> <a href="https://github.com/tawman/PetaPocoHierarchy" target="_blank"><img style="position: absolute; border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; right: 0px; top: 0px" alt="Fork me on GitHub" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.woodcp.com/2012/02/hierarchical-data-with-petapoco-multi-poco-mapping/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Light the Afterburners with WP Engine</title>
		<link>http://www.woodcp.com/2012/01/light-the-afterburners-with-wp-engine/</link>
		<comments>http://www.woodcp.com/2012/01/light-the-afterburners-with-wp-engine/#comments</comments>
		<pubDate>Fri, 27 Jan 2012 07:33:39 +0000</pubDate>
		<dc:creator>Todd Wood</dc:creator>
				<category><![CDATA[Azure]]></category>
		<category><![CDATA[Parallels]]></category>
		<category><![CDATA[WP Engine]]></category>

		<guid isPermaLink="false">http://www.woodcp.com/?p=82</guid>
		<description><![CDATA[TL; DR – You will enjoy rolling your own WordPress instance on Azure until you see the cost of scaling and maintaining the site. I decided to spend more time blogging and less time and money managing the infrastructure by &#8230; <a href="http://www.woodcp.com/2012/01/light-the-afterburners-with-wp-engine/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p><a href="http://wpengine.com"><img style="background-image: none; margin: 0px 0px 0px 20px; padding-left: 0px; padding-right: 0px; display: inline; float: right; padding-top: 0px; border-width: 0px;" title="wpe-banner-125x125" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2012/01/wpe-banner-125x125.jpg" alt="wpe-banner-125x125" width="129" height="129" align="right" border="0" /></a></p>
<p>TL; DR – You will enjoy rolling your own <a href="http://wordpress.org/download/" target="_blank">WordPress</a> instance on <a href="https://www.windowsazure.com/en-us/" target="_blank">Azure</a> until you see the cost of scaling and maintaining the site. I decided to spend more time blogging and less time and money managing the infrastructure by leaving the speed, scale, security, and support of a fully managed <em>WordPress</em> installation to Austin’s very own <a href="http://wpengine.com/" target="_blank">WP Engine</a>.</p>
<h2>Turbulence</h2>
<p>It did not take long before I hit my first patch of turbulence in the <a href="https://www.windowsazure.com/en-us/" target="_blank">Windows Azure Cloud</a>. My second blog post about using <a href="http://www.woodcp.com/2012/01/heterogeneous-development-environment-with-parallels-desktop-7-for-mac/" target="_blank">Parallels Desktop® 7 for Mac</a> for a development machine was retweeted by <a href="https://twitter.com/#!/parallelsmac" target="_blank">@ParallelsMac</a> to its 18K+ followers. I checked my blog entry for any comments, but was greeted by the message: <strong>Error establishing a database connection</strong>.</p>
<h2>The Cathedral and the Bazaar in the Sky</h2>
<p><img style="background-image: none; padding-left: 0px; padding-right: 20px; display: inline; float: left; padding-top: 0px; border-width: 0px;" title="Windows Azure" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2012/01/Azure.png" alt="Windows Azure" width="207" height="175" align="left" border="0" /></p>
<p>I had <em>WordPress 3.3.1</em> configured to run on two Extra Small Azure server instances (Shared CPU Cores and 768 MB Memory) with a <em>SQL Azure</em> backend. I figured this configuration would suffice for a single blog site with no following.</p>
<p>The first action I took during the outage was to start up an additional two instances via the web management interface. This immediately resolved the issue, but I assumed the traffic that caused it was long gone and never to return. Since I was only 3 days into my 90 day free trial of Azure, there was no cost for spinning up additional instances. However, projecting the cost forward under normal conditions after the trial period gave me cause for concern.</p>
<h3>Cloud with a Silver Lining</h3>
<p>Windows Azure is quite up front about its pricing levels and provides an excellent <a href="https://www.windowsazure.com/en-us/pricing/calculator/" target="_blank">Pricing Calculator</a> to check out the cost of various configurations. It took me several days, but I finally spotted the <em>Billing</em> link on my management portal page. I checked today to see the net effect of running five Extra Small Azure instances the past couple days. The 6 days worth of statistics made it clear I would not be needing the full 90 day <em>free</em> trial period:</p>
<ul>
<li>Database (DB / Month) – Web Edition: 19.355% of 1 db/month</li>
<li>Compute Hours – Windows Azure Compute: 17.2% of 750 Unit</li>
<li>Storage Transactions (in 10,000s) – Windows Azure Storage: 3.112% of 5 10,000s</li>
<li>Data Transfer Out: 0.17 GB of 80GB</li>
<li>Data Transfer In: 0.39 GB</li>
</ul>
<p>The free trial period includes 750 hours of compute time per month, but that is only enough for a single Extra Small instance. The recommended configuration by Azure is two instances and that was not even enough for my small burst of traffic.</p>
<h3>Seeding Your Own Cloud</h3>
<p>I thoroughly enjoyed rolling my own instance of <em>WordPress</em> in the Azure cloud, but the price of scaling it is too much for the average blogger. Change management of the <em>WordPress</em> site is not as straight forward either when running your own cloud. I found this out quickly when using the <em>WordPress</em> administration interface.</p>
<p>I knew from the start that running multiple instances would isolate certain aspects of the framework but not by how much. The <a href="https://github.com/Interop-Bridges/Windows-Azure-PHP-Scaffolders" target="_blank">Windows-Azure-PHP-Scaffolders</a> included a Windows Azure Storage plug-in to make images and static content available across all instances. In addition, the <em>WordPress</em> database will keep your content and plug-in settings available for all instances. The problem is with the other items that you frequently change when first setting up a new <em>WordPress</em> site:</p>
<ul>
<li>Plugins – You cannot install or uninstall plugins using the online admin interface unless you understand the fine art of round robin load balance dancing (F5 or Command-R) to install them on all nodes</li>
<li>Themes – You cannot install or modify themes using the online admin interface without the same issue</li>
<li>You could install the certificates to Remote Desktop into the instances, but Azure will use the base image uploaded when starting up any new instances. All component and template changes will be lost on the new instance.</li>
</ul>
<p>The remedy is to configure the <em>WordPress</em> plugins and theme modifications on your local computer, repackage the changes into a new Azure deployment, and use the Azure management console to stage the upgrade into the Cloud. Azure makes the process quite simple for someone like myself, but it is more complicated than simply using the WP-Admin interface to make the changes online.</p>
<h2>The Specialists</h2>
<p>Reliability and performance is rarely free or inexpensive, so I went back to where I started 6 days ago looking for hosted <em>WordPress</em> providers. I had no interest in the standard web hosting shared / VPS offerings thereby limiting my search to true SaaS providers like <a href="https://en.wordpress.com/signup/">WordPress.com</a> and <a href="http://wpengine.com">WP Engine</a>. After seeing the cost of Azure, I did not even bother with exploring Amazon AWS.</p>
<h3>WordPress.com</h3>
<p>My new review of <em>WordPress.com</em> left me with the same concerns as before. It needs to control your DNS zone file, only short form domain name URL, and from what I read you cannot use any plugin that generates / uses javascript. There was some confusing verbiage on ads and I am not looking to run ads on my blog no matter how much I mention the products I use and find value.</p>
<h3>WP Engine</h3>
<p><a href="http://wpengine.com/"><img style="background-image: none; margin: 0px 0px 0px 20px; padding-left: 0px; padding-right: 0px; display: inline; float: right; padding-top: 0px; border-width: 0px;" title="engine" src="http://woodcp.wpengine.netdna-cdn.com/wp-content/uploads/2012/01/engine.png" alt="engine" width="244" height="244" align="right" border="0" /></a>WP Engine on the other hand, provides exactly what I was attempting to accomplish on my own, but without the change management opportunity and scaling costs. I also like the idea of supporting a <a href="http://wpengine.com/about/">locally operated Austin business</a>.</p>
<p>If I am not mistaken, I only know of WP Engine by word of mouth of them either sponsoring or helping out at some Austin technical user group meeting or something. This just goes to prove that more tech companies should be sponsoring local tech user groups with beer and food.</p>
<p>The best part, it literally only took me 43 minutes from the time I received the <em>Welcome to WP Engine!</em> email until the moment I logged into <a href="http://www.namecheap.com/">Namecheap.com</a> to update my DNS settings to point my CNAME record directly to WP Engine.</p>
<h2>Closing Thought</h2>
<p>In the end, Azure is fun but WP Engine will get it done. I enjoyed the experience of  understanding the finer points of packaging and deploying to Azure, but I am not willing to spend the dollars necessary to operate successfully on it. Stay tuned, I have only been on WP Engine for 5 hours now.</p>
<h2>References</h2>
<ul>
<li>Eric S. Raymond (1999). <a class="external text" href="http://www.catb.org/~esr/writings/cathedral-bazaar/cathedral-bazaar/" rel="nofollow"><em>The Cathedral &amp; the Bazaar</em></a>. O&#8217;Reilly. <a title="International Standard Book Number" href="/wiki/International_Standard_Book_Number">ISBN</a> <a title="Special:BookSources/1-56592-724-9" href="/wiki/Special:BookSources/1-56592-724-9">1-56592-724-9</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.woodcp.com/2012/01/light-the-afterburners-with-wp-engine/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Heterogeneous Development Environment with Parallels Desktop® 7 for Mac</title>
		<link>http://www.woodcp.com/2012/01/heterogeneous-development-environment-with-parallels-desktop-7-for-mac/</link>
		<comments>http://www.woodcp.com/2012/01/heterogeneous-development-environment-with-parallels-desktop-7-for-mac/#comments</comments>
		<pubDate>Tue, 24 Jan 2012 07:36:32 +0000</pubDate>
		<dc:creator>Todd Wood</dc:creator>
				<category><![CDATA[Parallels]]></category>

		<guid isPermaLink="false">http://www.woodcp.com/?p=73</guid>
		<description><![CDATA[TL;DR – Purchase a 17” MacBook Pro, add two external monitors, install Parallels Desktop® 7 for Mac, and start developing software solutions for any environment (Mac OS X, iOS, Android, Microsoft .NET, Windows 8, and Ruby on Rails et al) &#8230; <a href="http://www.woodcp.com/2012/01/heterogeneous-development-environment-with-parallels-desktop-7-for-mac/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>TL;DR – Purchase a 17” MacBook Pro, add two external monitors, install Parallels Desktop® 7 for Mac, and start developing software solutions for any environment (Mac OS X, iOS, Android, Microsoft .NET, Windows 8, and Ruby on Rails et al) without compromising a thing. You can take advantage of Parallels Coherence mode to do all this seamlessly allowing you to use the right tool for the right job.</p>
<p><a href="http://woodcp.wpengine.com/wp-content/uploads/2012/01/DesktopConfig.jpg"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="DesktopConfig" src="http://woodcp.wpengine.com/wp-content/uploads/2012/01/DesktopConfig_thumb.jpg" alt="DesktopConfig" width="628" height="238" border="0" /></a></p>
<p><strong>Resolution</strong>: Dell 24&#8243; 1920 x 1080 + 17&#8243; MBP LCD 1920 x 1200 + Dell 24&#8243; 1920 x 1080 = 5760 x 1080/1200 x 3 Virtual Desktops</p>
<p>I spend nearly all my time developing Microsoft .NET solutions lately, and my MacBook Pro is the best Windows development platform I have used to date. Parallels ability to let me use the Mac apps I like alongside the .NET development tools I require makes it a win-win all around. The seamless integration of the Mac file system with the Windows VM is nice and requires only a couple Visual Studio 2010 Professional settings changes to get it operating smoothly with installed add-on, extensions, and debugging. VS2010 setup is a topic for another day and post.</p>
<h2>Prototypical Heterogeneous Developer</h2>
<p>I have primarily been developing Microsoft .NET solutions with an Oracle, Sybase, and SQL Server database backend since 2004, but I have an additional 14 years of experience developing anything but Microsoft prior to that. In fact, my first computer was an Apple IIe and I still have the Mac IIsi I used from 1990 to 1996. I switched over to Wintel in 1996 for two reasons: Linux and DOOM.</p>
<p>In the Spring of 2011, I started to get more interested in Ruby on Rails after having not looked at it since shortly after it was first released. Austin has a strong RoR community and that itch inside every developer flared up after I attended one of the Austin on Rails meetings. It was this desire to explore RoR further that led me to purchase my MacBook Pro in June of 2011. I also had some business development ideas I wanted to develop further and purchasing new hardware is one way to motivate yourself.</p>
<p><a href="http://woodcp.wpengine.com/wp-content/uploads/2012/01/P7VMList.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="P7VMList" src="http://woodcp.wpengine.com/wp-content/uploads/2012/01/P7VMList_thumb.png" alt="P7VMList" width="498" height="282" border="0" /></a></p>
<h2>Vendor Lock-in and Parallels to the Rescue</h2>
<p>As an Independent Consultant, the first Faustian bargain you willing enter into is Quickbooks. The opportunity cost savings alone with the Payroll and Business Tax software pays for itself. Unfortunately, the payroll subscription I use only runs on the Microsoft Windows version. Intuit does not offer the Payroll component with the Mac version of Quickbooks and it charges too much for the online version. I cannot wait until there is a viable alternative to the Intuit market stronghold. Microsoft even forced me down the Quicken path for personal use when it discontinued the Money product line.</p>
<h3>VMware or Parallels</h3>
<p>I researched the differences between VMware Fusion and Parallels and decided to go with Parallels 6 (upgraded to Parallels 7 later) because of Coherence mode. I did not want to use bootcamp partitions plus I had used VMware off and on since pre-version 1.0 came out on Linux. I figured I would test the hype and try something new for me with Parallels. I will honestly state that I have not been disappointed and Parallels has exceeded my expectations.</p>
<h2>Seamless Integration with Coherence and Alfred</h2>
<p>Coherence mode is everything it claims to be, but I did notice Parallels 6 had less redraw issues than Parallels 7 in some edge cases. There is also a strange condition when returning from sleep in between different monitor configurations. Parallels will claim it cannot switch to Coherence mode and it is not until you move the window onto the main MBP display that Coherence mode will start to function. I certainly hope there is a point release of fixes coming out soon.</p>
<p><a href="http://woodcp.wpengine.com/wp-content/uploads/2012/01/Coherence.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="Coherence" src="http://woodcp.wpengine.com/wp-content/uploads/2012/01/Coherence_thumb.png" alt="Coherence" width="638" height="400" border="0" /></a></p>
<h3>Alfred is the Man</h3>
<p>Alfred is a Mac application launcher that you can activate with a key sequence. It opens a dialog as you start typing the characters of the application you wish to start. Parallels integration exposes your Windows applications seamlessly for launching from Alfred (or any application). For example, start typing the word Chrome and Alfred will let you choose between the Mac or Windows version of the application.</p>
<p><a href="http://woodcp.wpengine.com/wp-content/uploads/2012/01/Alfred.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="Alfred" src="http://woodcp.wpengine.com/wp-content/uploads/2012/01/Alfred_thumb.png" alt="Alfred" width="557" height="412" border="0" /></a></p>
<h3>Mac Virtual Desktops</h3>
<p>Virtual desktops have been around for a long time with X11, CDE, Gnome, KDE, and Windows third party tools but for some reason the Magic Mouse and Mac Virtual Desktops feels natural to me. I run three virtual desktops with two external monitors at my home office and one external monitor at my client site. The 17” MacBook Pro LCD with 1920&#215;1200 resolution is as good as a standalone monitor so operating with only one external monitor is still highly productive.</p>
<p><a href="http://woodcp.wpengine.com/wp-content/uploads/2012/01/VirtualDesktops.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="VirtualDesktops" src="http://woodcp.wpengine.com/wp-content/uploads/2012/01/VirtualDesktops_thumb.png" alt="VirtualDesktops" width="673" height="380" border="0" /></a></p>
<p>I typically partition my activities across the three virtual desktops with the following flow when using two external monitors:</p>
<ul>
<li>Desktop 1: Left – Evernote / Center – Email &amp; iTerm / Right – Twitter &amp; Safari</li>
<li>Desktop 2: Left – Tortoise HG, Command2 (command line builds), Windows Web Browsers / Center – IM and Debug Browser Sessions / Right – Visual Studio 2010</li>
<li>Desktop 3: Left – Database Model / Center – Miscellaneous / Right – SQL Server 2008 R2 Management Studio</li>
</ul>
<h2>My Environment Configuration</h2>
<p>Since purchasing my MacBook Pro in June, my old Windows desktop machine has been in sleep mode 99% of the time. I only wake it to retrieve a document I forgot to migrate over to the MBP.</p>
<p>I only purchased a new AirPort Extreme WiFi because the Vonage router I had was even worse than the Linksys one, but I am glad I did. The Xtand Pro XL stand is a little pricey, but it lines up the external monitors with the top of the MBP very well. I acquired all these components over the past six months and each item was worth the investment.</p>
<h3>Baseline Hardware Kit</h3>
<ul>
<li>17&#8243; MacBook Pro quad-core Intel Core i7 2.3GHz, 4GB RAM, 750GB Hard Drive, Intel HD Graphics 3000 and AMD Radeon HD 6750M, SuperDrive, Thunderbolt port, Aluminum unibody, Hi-Res Antiglare (Mftr Part No : Z0M3-2.3-4G750-HRA)</li>
<li>Crucial.com 8GB Kit (4GBx2), 204-pin SODIMM  Upgrade for a Apple MacBook Pro 2.3GHz Intel Core i7 (17-inch DDR3) Early-2011 System (Part Number: CT2KIT51264BC1339)</li>
<li>Wired Keyboard with Numeric Keypad (Mftr Part No : MB110LL/A) [Note: Net gain of +1 USB ports]</li>
<li>Magic Mouse (Mftr Part No : MB829LL/A)</li>
</ul>
<h3>Displays and Stand</h3>
<ul>
<li>Apple Mini-DP to DVI Adapter Part Number: MB570Z/A</li>
<li>2 x Dell ST2420L 24-inch Full HD Widescreen Monitor with LED</li>
<li>StarTech.com 1ft DVI-D Dual Link Digital Video Monitor Cable</li>
<li>Rosewill 3 ft. DVI-D Male to DVI-D Male Digital Dual Link Cable, Model RCAB-11053</li>
<li>HIS Multi-View II Video Adapter (Mac &amp; Window 7 compatible version) HMV2-MAC-PC USB to DVI Interface (Download <a href="http://www.displaylink.com/support/mac_downloads.php)">DisplayLink Drivers for Mac</a>)</li>
<li>Just Mobile Xtand Pro XL for Macbook</li>
</ul>
<h3>Networking</h3>
<ul>
<li>AirPort Extreme Base Station &#8211; Simultaneous Dual-Band &#8211; 2011 model (Mftr Part No : MD031LL/A)</li>
</ul>
<h3>Backup and Recovery</h3>
<ul>
<li>Time Machine software that comes with Mac OS X</li>
<li>G-Technology G-DRIVE Q 2TB External Hard Drive w/ eSATA, USB 2.0, Firewire 400, Firewire 800 Interfaces (Model 0G00203)</li>
<li>StarTech 3-Feet Shielded External eSATA Cable M/M (ESATA3)</li>
<li>Tempo Edge Sata 6GBPS E34 Single Port Controller</li>
</ul>
<h3>Licensed Software</h3>
<ul>
<li>OS X Lion</li>
<li>Parallels Desktop® 7 for Mac</li>
<li>Windows 7 Professional</li>
<li>Visual Studio 2010 Professional + ReSharper 6.1</li>
<li>Microsoft Office Windows Version</li>
<li>Balsamiq Mockups</li>
<li>RubyMine / TextMate</li>
<li>Expresso Regex</li>
</ul>
<h2>Closing Thoughts</h2>
<p>My only gripe with the 17” MacBook Pro is the weight. It is noticeable but then again I am only transporting it between my home office and the client site. The advantage of the 17” over the 15” MBP is an additional USB port. This seemingly minor detail has been a major headache for a number of my colleagues using the 15&#8243; MBP. Ironically, my full-size Apple keyboard nets me an additional USB port.</p>
<p>If you have read this far and develop Windows applications… What are you waiting for? Purchase a Mac and enjoy it developing for Windows more.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.woodcp.com/2012/01/heterogeneous-development-environment-with-parallels-desktop-7-for-mac/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>To the Cloud</title>
		<link>http://www.woodcp.com/2012/01/to-the-cloud/</link>
		<comments>http://www.woodcp.com/2012/01/to-the-cloud/#comments</comments>
		<pubDate>Sat, 21 Jan 2012 17:31:07 +0000</pubDate>
		<dc:creator>Todd Wood</dc:creator>
				<category><![CDATA[Azure]]></category>

		<guid isPermaLink="false">http://woodcp.cloudapp.net/?p=24</guid>
		<description><![CDATA[To state that my net presence needed an upgrade would be the under statement of the decade. A quick glance at my legacy web site dashboard shows a perfect example of a static web site: Joomla! Version: Joomla! 1.0.11 Stable &#8230; <a href="http://www.woodcp.com/2012/01/to-the-cloud/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>To state that my net presence needed an upgrade would be the under statement of the decade. A quick glance at my legacy web site dashboard shows a perfect example of a static web site:</p>
<blockquote><p><strong>Joomla! Version:</strong><br />
Joomla! 1.0.11 Stable [ Sunbow ] 28 August 2006 20:00 UTC</p>
<h5>Your version of Joomla! [ 1.0.11 Stable ] is 1973 days old</h5>
</blockquote>
<p>The key to longevity of a static web site is ripping out all the framework components that you do not need, which in the case of <em>Joomla</em> was nearly all of them. A simple <em>htpasswd</em> file to lock down the Administration URL and you are quite safe. I would check on the site every couple years to make sure it was still static.</p>
<p>Fast forward to present day and I find myself work along side a number of active bloggers. The first push came from an off hand remark by <a title="http://jeffreypalermo.com/" href="http://jeffreypalermo.com/" target="_blank">Jeffrey Palermo</a> that I should use my website to blog, but the final straw came from <a title="http://lostechies.com/jimmybogard/" href="http://lostechies.com/jimmybogard/" target="_blank">Jimmy Bogard</a> who hosted a brown bag lunch discussion on blogging yesterday.</p>
<p>So how should I do this? After reviewing the free and paid options over on the WordPress.com website, I decided to host my own WordPress site on Azure. I watched the <a title="http://channel9.msdn.com/Events/windowsazure/learn/Keynote-Getting-Started-with-Windows-Azure" href="http://channel9.msdn.com/Events/windowsazure/learn/Keynote-Getting-Started-with-Windows-Azure" target="_blank">Keynote: Getting Started with Windows Azure</a> talk by <a title="http://weblogs.asp.net/scottgu/" href="http://weblogs.asp.net/scottgu/" target="_blank">Scott Guthrie</a> and wanted a reason to give Azure a try.</p>
<p>The are a couple great references on the net to get WordPress stood up on Azure, so I will not go into the details here. The follow links containing instructions and a tool for setting up your public storage container should get you going.</p>
<ul>
<li><a title="http://www.designisphilosophy.com/tutorials/wordpress-on-azure-single-site-deployment/" href="http://www.designisphilosophy.com/tutorials/wordpress-on-azure-single-site-deployment/" target="_blank">WordPress on Windows Azure: Single-Site Deployment</a></li>
<li><a title="http://azurephp.interoperabilitybridges.com/articles/how-to-deploy-wordpress-using-the-windows-azure-sdk-for-php-wordpress-scaffold" href="http://azurephp.interoperabilitybridges.com/articles/how-to-deploy-wordpress-using-the-windows-azure-sdk-for-php-wordpress-scaffold" target="_blank">How to deploy WordPress using the Windows Azure SDK for PHP WordPress scaffold</a></li>
<li><a title="http://clumsyleaf.com/products/cloudxplorer" href="http://clumsyleaf.com/products/cloudxplorer" target="_blank">CloudXplorer &#8211; explore your cloud storage with ease</a></li>
</ul>
<p>See you in the clouds and take advantage of the 3-Month Free Trial offer from Azure.</p>
<p><a href="http://woodcp.wpengine.com/wp-content/uploads/2012/01/WCP-Azure.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="WCP-Azure" src="http://woodcp.wpengine.com/wp-content/uploads/2012/01/WCP-Azure_thumb.png" alt="WCP-Azure" width="662" height="256" border="0" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.woodcp.com/2012/01/to-the-cloud/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
