﻿<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel><title>Ayende @ Rahien</title><link>http://ayende.com</link><description>Ayende @ Rahien</description><copyright>Copyright (C) Ayende Rahien  2004 - 2021 (c) 2026</copyright><ttl>60</ttl><item><title>Rhino ETL Union Operation</title><description>&lt;p&gt;Yes, it is somewhat of a blast from the past, but I just got asked how to create a good Union All operation for Rhino ETL.&lt;/p&gt; &lt;p&gt;The obvious implementation is:&lt;/p&gt; &lt;blockquote&gt; &lt;div id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; UnionAllOperation : AbstractOperation&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; List&amp;lt;IOperation&amp;gt; _operations = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;IOperation&amp;gt;(); &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; IEnumerable&amp;lt;Row&amp;gt; Execute(IEnumerable&amp;lt;Row&amp;gt; rows)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var operation &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; _operations)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var row &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; operation.Execute(&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;))&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;yield&lt;/span&gt; &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; row;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; UnionAllOperation Add(IOperation operation)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;     {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;         _operations.Add(operation);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;The problem is that this does everything synchronously. The following code is a better impl, but note that this is notepad code, with all the implications of that.&lt;/p&gt;
&lt;blockquote&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; UnionAllOperation : AbstractOperation&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; List&amp;lt;IOperation&amp;gt; _operations = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;IOperation&amp;gt;(); &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; IEnumerable&amp;lt;Row&amp;gt; Execute(IEnumerable&amp;lt;Row&amp;gt; rows)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;         var blockingCollection = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; BlockingCollection&amp;lt;Row&amp;gt;();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;         var tasks = _operations.Select(currentOp =&amp;gt; Task.Factory.StartNew(() =&amp;gt;{&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt;(var operation &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; currentOp.Execute(&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;))&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;                 {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;                     blockingCollection.Add(operation);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;                 }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;                 blockingCollection.Add(&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;); &lt;span style="color: #008000"&gt;// free the consumer thread&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;             });&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;         Row r;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;while&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;true&lt;/span&gt;){&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(tasks.All(x=&amp;gt;x.IsFaulted || x.IsCanceled || x.IsCompleted)) &lt;span style="color: #008000"&gt;// all done&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum19"&gt;  19:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;break&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum20"&gt;  20:&lt;/span&gt;             r = blockingCollection.Take();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum21"&gt;  21:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(r == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum22"&gt;  22:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;continue&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum23"&gt;  23:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;yield&lt;/span&gt; &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; r;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum24"&gt;  24:&lt;/span&gt;         }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum25"&gt;  25:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;while&lt;/span&gt;(blockingCollection.TryTake(&lt;span style="color: #0000ff"&gt;out&lt;/span&gt; r)) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum26"&gt;  26:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(r == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum27"&gt;  27:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;continue&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum28"&gt;  28:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;yield&lt;/span&gt; &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; r;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum29"&gt;  29:&lt;/span&gt;         }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum30"&gt;  30:&lt;/span&gt;         Task.WaitAll(tasks.ToArray()); &lt;span style="color: #008000"&gt;// raise any exception that were raised during execption&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum31"&gt;  31:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum32"&gt;  32:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum33"&gt;  33:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; UnionAllOperation Add(IOperation operation)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum34"&gt;  34:&lt;/span&gt;     {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum35"&gt;  35:&lt;/span&gt;         _operations.Add(operation);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum36"&gt;  36:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum37"&gt;  37:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum38"&gt;  38:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;p&gt;Usual caveats apply, notepad code, never actually run it, much less tested / debugged it.&lt;/p&gt;
&lt;p&gt;Feel free to rip into it, though.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://code.google.com/p/sqloogle/"&gt;Dale Newman&lt;/a&gt; did some improvements, the most important one is to make sure that we aren’t going to evaluate the tasks several times (opps! I told ya it was notepad code &lt;img style="border-bottom-style: none; border-left-style: none; border-top-style: none; border-right-style: none" class="wlEmoticon wlEmoticon-smile" alt="Smile" src="http://ayende.com/blog/Images/Windows-Live-Writer/Rhino-ETL-Union-Operation_14155/wlEmoticon-smile_2.png"&gt;), and now it looks like this:&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// Combines rows from all operations.&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt; &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; UnionAllOperation : AbstractOperation {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; List&amp;lt;IOperation&amp;gt; _operations = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; List&amp;lt;IOperation&amp;gt;();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// Executes the added operations in parallel.&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;param name="rows"&amp;gt;&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; IEnumerable&amp;lt;Row&amp;gt; Execute(IEnumerable&amp;lt;Row&amp;gt; rows) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;         var blockingCollection = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; BlockingCollection&amp;lt;Row&amp;gt;();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt;         Debug(&lt;span style="color: #006080"&gt;"Creating tasks for {0} operations."&lt;/span&gt;, _operations.Count);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum19"&gt;  19:&lt;/span&gt;         var tasks = _operations.Select(currentOp =&amp;gt; Task.Factory.StartNew(() =&amp;gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum20"&gt;  20:&lt;/span&gt;             Trace(&lt;span style="color: #006080"&gt;"Executing {0} operation."&lt;/span&gt;, currentOp.Name);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum21"&gt;  21:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var row &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; currentOp.Execute(&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum22"&gt;  22:&lt;/span&gt;                 blockingCollection.Add(row);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum23"&gt;  23:&lt;/span&gt;             }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum24"&gt;  24:&lt;/span&gt;             blockingCollection.Add(&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;); &lt;span style="color: #008000"&gt;// free the consumer thread&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum25"&gt;  25:&lt;/span&gt;         })).ToArray();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum26"&gt;  26:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum27"&gt;  27:&lt;/span&gt;         Row r;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum28"&gt;  28:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;while&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;true&lt;/span&gt;) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum29"&gt;  29:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (tasks.All(x =&amp;gt; x.IsFaulted || x.IsCanceled || x.IsCompleted)) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum30"&gt;  30:&lt;/span&gt;                 Debug(&lt;span style="color: #006080"&gt;"All tasks have been canceled, have faulted, or have completed."&lt;/span&gt;);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum31"&gt;  31:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;break&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum32"&gt;  32:&lt;/span&gt;             }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum33"&gt;  33:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum34"&gt;  34:&lt;/span&gt;             r = blockingCollection.Take();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum35"&gt;  35:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (r == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum36"&gt;  36:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;continue&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum37"&gt;  37:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum38"&gt;  38:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;yield&lt;/span&gt; &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; r;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum39"&gt;  39:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum40"&gt;  40:&lt;/span&gt;         }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum41"&gt;  41:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum42"&gt;  42:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;while&lt;/span&gt; (blockingCollection.TryTake(&lt;span style="color: #0000ff"&gt;out&lt;/span&gt; r)) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum43"&gt;  43:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (r == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum44"&gt;  44:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;continue&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum45"&gt;  45:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;yield&lt;/span&gt; &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; r;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum46"&gt;  46:&lt;/span&gt;         }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum47"&gt;  47:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum48"&gt;  48:&lt;/span&gt;         Task.WaitAll(tasks); &lt;span style="color: #008000"&gt;// raise any exception that were raised during execption&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum49"&gt;  49:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum50"&gt;  50:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum51"&gt;  51:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum52"&gt;  52:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum53"&gt;  53:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// Initializes this instance&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum54"&gt;  54:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum55"&gt;  55:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;param name="pipelineExecuter"&amp;gt;The current pipeline executer.&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum56"&gt;  56:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; PrepareForExecution(IPipelineExecuter pipelineExecuter) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum57"&gt;  57:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var operation &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; _operations) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum58"&gt;  58:&lt;/span&gt;             operation.PrepareForExecution(pipelineExecuter);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum59"&gt;  59:&lt;/span&gt;         }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum60"&gt;  60:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum61"&gt;  61:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum62"&gt;  62:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum63"&gt;  63:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// Add operation parameters&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum64"&gt;  64:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum65"&gt;  65:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;param name="ops"&amp;gt;operations delimited by commas&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum66"&gt;  66:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum67"&gt;  67:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; UnionAllOperation Add(&lt;span style="color: #0000ff"&gt;params&lt;/span&gt; IOperation[] ops) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum68"&gt;  68:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (var operation &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; ops) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum69"&gt;  69:&lt;/span&gt;             _operations.Add(operation);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum70"&gt;  70:&lt;/span&gt;         }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum71"&gt;  71:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum72"&gt;  72:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum73"&gt;  73:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum74"&gt;  74:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum75"&gt;  75:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// Add operations&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum76"&gt;  76:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum77"&gt;  77:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;param name="ops"&amp;gt;an enumerable of operations&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum78"&gt;  78:&lt;/span&gt;     &lt;span style="color: #008000"&gt;/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum79"&gt;  79:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; UnionAllOperation Add(IEnumerable&amp;lt;IOperation&amp;gt; ops) {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum80"&gt;  80:&lt;/span&gt;         _operations.AddRange(ops);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum81"&gt;  81:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum82"&gt;  82:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum83"&gt;  83:&lt;/span&gt;&amp;nbsp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum84"&gt;  84:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;</description><link>http://ayende.com/160962/rhino-etl-union-operation?Key=2c12426a-1b33-4cb1-8e0e-a30f09a0896e</link><guid>http://ayende.com/160962/rhino-etl-union-operation?Key=2c12426a-1b33-4cb1-8e0e-a30f09a0896e</guid><pubDate>Fri, 15 Feb 2013 10:00:00 GMT</pubDate></item><item><title>Legacy ETL solutions</title><description>&lt;p&gt;I am currently working with a customer on some issues that they have with moving to RavenDB, and we run into a set of problems with their (&lt;em&gt;Legacy&lt;/em&gt; with a capital L) relational database.&lt;/p&gt; &lt;p&gt;They run into several problems with how to create a good ETL on that, especially with regards to how to detect changes and the tendency of the legacy system to re-use old primary keys.&lt;/p&gt; &lt;p&gt;The solution for both is actually fairly easy. Instead of relying on the primary keys of the legacy system, which can be re-used and creates a ton of trouble down the stream, create your own ids, distinct from the legacy system ids.&lt;/p&gt; &lt;p&gt;That can be done easily enough by issuing:&lt;/p&gt; &lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;ALTER&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; Customers &lt;span class="kwrd"&gt;ADD&lt;/span&gt; UniqueKeyForEtl uniqueidentifier &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;span class="kwrd"&gt;DEFAULT&lt;/span&gt;(newid())&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;This is a non breaking change operation, that is, you can do that on any database without fearing that this would somehow break any application that is using it. The good thing about this is that this now ensures that every row in the table is going to have a unique, never repeating, never re-used key. This is a good approach because it is also something that has such a low cost. &lt;/p&gt;
&lt;p&gt;The next problem was how to actually detect changes, the Legacy System does have LastModified column on some tables, and actually bothers to update this in some cases, but not in all of them. Again, the answer is to add a column to the table. The easiest option would probably to just ensure that the LastModified is updated in a trigger, something like:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;TRIGGER&lt;/span&gt; UpdateCustomersLastModifiedDate &lt;span class="kwrd"&gt;ON&lt;/span&gt; Customers
&lt;span class="kwrd"&gt;FOR&lt;/span&gt; &lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; 
&lt;span class="kwrd"&gt;AS&lt;/span&gt;
&lt;span class="kwrd"&gt;UPDATE&lt;/span&gt; [TableName] &lt;span class="kwrd"&gt;SET&lt;/span&gt; Customers.LastModified=getdate()
&lt;span class="kwrd"&gt;FROM&lt;/span&gt; Customers &lt;span class="kwrd"&gt;INNER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; Inserted &lt;span class="kwrd"&gt;ON&lt;/span&gt; Customers.[UniqueID]= Inserted.[UniqueID]&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;Maybe with a check to skip the update if the Legacy System already updated it. &lt;/p&gt;
&lt;p&gt;The problem is that the Legacy System has so many triggers already, that the client is very reluctant to add another one. So another option is to use the &lt;a href="http://msdn.microsoft.com/en-us/library/ms182776.aspx"&gt;rowversion&lt;/a&gt; feature in SQL Server. This allows us to define the following:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;ALTER&lt;/span&gt; &lt;span class="kwrd"&gt;TABLE&lt;/span&gt; Customers &lt;span class="kwrd"&gt;ADD&lt;/span&gt; ModifiedVersionForEtl rowversion &lt;span class="kwrd"&gt;NOT&lt;/span&gt; &lt;span class="kwrd"&gt;NULL&lt;/span&gt; &lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/blockquote&gt;
&lt;p&gt;The rowversion will be incremented by the DB on every write. So you can check on all rows that has been updated since the last version that you have seen. This isn’t a trigger, since this happens as part of the actual update process, and is likely to be significantly cheaper. &lt;/p&gt;
&lt;p&gt;By adding these two columns, an operation that it is safe to make since it can’t break any code that uses the database, we have given ourselves an easy way to detect changes, and an easy way to get unique keys that are actually unique, and non repeating.&lt;/p&gt;</description><link>http://ayende.com/132097/legacy-etl-solutions?Key=4bccd7f5-29c8-4bb3-83c6-50e967156d9f</link><guid>http://ayende.com/132097/legacy-etl-solutions?Key=4bccd7f5-29c8-4bb3-83c6-50e967156d9f</guid><pubDate>Fri, 11 Nov 2011 10:00:00 GMT</pubDate></item><item><title>Public Service Announcement: Git master repositories for the Rhino Tools projects</title><description>&lt;p&gt;There have been some changes, and it seems that it is hard to track them. Here are where you can find the master repositories for the rhino tools projects:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Rhino Commons - &lt;a href="https://github.com/lorenzomelato/rhino-commons"&gt;https://github.com/lorenzomelato/rhino-commons&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Rhino Service Bus- &lt;a title="https://github.com/hibernating-rhinos/rhino-esb" href="https://github.com/hibernating-rhinos/rhino-esb"&gt;https://github.com/hibernating-rhinos/rhino-esb&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Rhino Licensing - &lt;a title="https://github.com/hibernating-rhinos/rhino-licensing" href="https://github.com/hibernating-rhinos/rhino-licensing"&gt;https://github.com/hibernating-rhinos/rhino-licensing&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Rhino ETL - &lt;a title="https://github.com/hibernating-rhinos/rhino-etl" href="https://github.com/hibernating-rhinos/rhino-etl"&gt;https://github.com/hibernating-rhinos/rhino-etl&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Rhino Security - &lt;a title="https://github.com/hibernating-rhinos/rhino-security" href="https://github.com/hibernating-rhinos/rhino-security"&gt;https://github.com/hibernating-rhinos/rhino-security&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Rhino Persistent Hash Table - &lt;a title="https://github.com/hibernating-rhinos/rhino-pht" href="https://github.com/hibernating-rhinos/rhino-pht"&gt;https://github.com/hibernating-rhinos/rhino-pht&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Rhino Distributed Hash Table - &lt;a title="https://github.com/hibernating-rhinos/rhino-dht" href="https://github.com/hibernating-rhinos/rhino-dht"&gt;https://github.com/hibernating-rhinos/rhino-dht&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Rhino DSL - &lt;a title="https://github.com/hibernating-rhinos/rhino-dsl" href="https://github.com/hibernating-rhinos/rhino-dsl"&gt;https://github.com/hibernating-rhinos/rhino-dsl&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Rhino Mocks - &lt;a title="https://github.com/hibernating-rhinos/rhino-mocks" href="https://github.com/hibernating-rhinos/rhino-mocks"&gt;https://github.com/hibernating-rhinos/rhino-mocks&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;Rhino Queues - &lt;a title="https://github.com/hibernating-rhinos/rhino-queues" href="https://github.com/hibernating-rhinos/rhino-queues"&gt;https://github.com/hibernating-rhinos/rhino-queues&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;</description><link>http://ayende.com/4735/public-service-announcement-git-master-repositories-for-the-rhino-tools-projects?Key=3e567a32-9e98-4920-835d-c3ce48a64596</link><guid>http://ayende.com/4735/public-service-announcement-git-master-repositories-for-the-rhino-tools-projects?Key=3e567a32-9e98-4920-835d-c3ce48a64596</guid><pubDate>Tue, 28 Dec 2010 08:07:59 GMT</pubDate></item><item><title>Rhino ETL Video</title><description>&lt;p&gt;&lt;a href="http://www.webpaul.net/"&gt;Paul Barriere&lt;/a&gt; has a video up of a &lt;a href="http://www.blip.tv/file/3303967"&gt;presentation about Rhino ETL&lt;/a&gt;:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;ETL stands for Extract, Transform, Load. For example, you receive files or other data from vendors or other third parties which you need to manipulate in some way and then insert into your own database. Rhino ETL is an open source C# package that I have used for dozens of production processes quite successfully. By using C# for your ETL tasks you can create testable, reusable components more easily than with tools like SSIS and DTS.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;It is good to see more information available on Rhino ETL.&lt;/p&gt;</description><link>http://ayende.com/4438/rhino-etl-video?Key=ebce3ca4-86db-43f9-a02d-75e03b0fd731</link><guid>http://ayende.com/4438/rhino-etl-video?Key=ebce3ca4-86db-43f9-a02d-75e03b0fd731</guid><pubDate>Thu, 18 Mar 2010 10:00:00 GMT</pubDate></item><item><title>On PSake</title><description>&lt;p&gt;&lt;a href="http://codebetter.com/blogs/james.kovacs/archive/2008/06/27/introducing-psake.aspx"&gt;James Kovacks&lt;/a&gt; introduced &lt;a href="http://code.google.com/p/psake/"&gt;psake&lt;/a&gt; ( a power shell based build system )over a year ago, and at the time, I gave it a glance and decided that it was interesting, but not worth further investigation.&lt;/p&gt;  &lt;p&gt;This weekend, as I was restructuring my Rhino Tools project, I realized that I need to touch the build system as well. The Rhino Tools build system has been through several projects, and was originally ported from Hibernate. It is NAnt based, complex, and can do just about everything that you want expect be easily understandable.&lt;/p&gt;  &lt;p&gt;It became clear to me very quickly that it ain’t going to be easy to change the way it works, nor would it be easy to modify that to reflect the new structure. There are other issues with complex build systems, they tend to create zones of “there be dragons”, where only the initiated go, and even they go with trepidation. I decided to take advantage of the changes that I am already making to get a simpler build system.&lt;/p&gt;  &lt;p&gt;I had a couple of options open to me: Rake and Bake.&lt;/p&gt;  &lt;p&gt;Bake seemed natural, until I remember that no one touched it in a year or two. Beside, I can only stretch NIH so far :-). And while I know that people rave about rake, I did &lt;em&gt;not&lt;/em&gt; want to introduce a Ruby dependency on my build system. I know that it was an annoyance when I had to build Fluent NHibernate.&lt;/p&gt;  &lt;p&gt;One thing that I knew that I am not willing to go back to was editing XML, so I started looking at other build systems, ending up running into PSake.&lt;/p&gt;  &lt;p&gt;There are a few interesting things that reading about it brought to mind. First, NAnt doesn’t cut it anymore. It can’t build WPF applications nor handle multi targeting well. Second, I am already managing the compilation part of the build using MSBuild, thanks to Visual Studio.&lt;/p&gt;  &lt;p&gt;That leave the build system with executing msbuild, setting up directories, executing tests, running post build tools, etc.&lt;/p&gt;  &lt;p&gt;PSake handles those well, since the execution environment is the command line. The syntax is nice, just enough to specify tasks and dependencies, but everything else is just pure command line. The following is Rhino Mocks build script, using PSake:&lt;/p&gt;  &lt;blockquote&gt;   &lt;div&gt;     &lt;pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"&gt;properties { 
  $base_dir  = resolve-path .
  $lib_dir = &lt;span style="color: #006080"&gt;"$base_dir\SharedLibs"&lt;/span&gt;
  $build_dir = &lt;span style="color: #006080"&gt;"$base_dir\build"&lt;/span&gt; 
  $buildartifacts_dir = &lt;span style="color: #006080"&gt;"$build_dir\" 
  $sln_file = "&lt;/span&gt;$base_dir\Rhino.Mocks-vs2008.sln&lt;span style="color: #006080"&gt;" 
  $version = "&lt;/span&gt;3.6.0.0&lt;span style="color: #006080"&gt;"
  $tools_dir = "&lt;/span&gt;$base_dir\Tools&lt;span style="color: #006080"&gt;"
  $release_dir = "&lt;/span&gt;$base_dir\Release&lt;span style="color: #006080"&gt;"
} 

task default -depends Release

task Clean { 
  remove-item -force -recurse $buildartifacts_dir -ErrorAction SilentlyContinue 
  remove-item -force -recurse $release_dir -ErrorAction SilentlyContinue 
} 

task Init -depends Clean { 
    . .\psake_ext.ps1
    Generate-Assembly-Info `
        -file "&lt;/span&gt;$base_dir\Rhino.Mocks\Properties\AssemblyInfo.cs&lt;span style="color: #006080"&gt;" `
        -title "&lt;/span&gt;Rhino Mocks $version&lt;span style="color: #006080"&gt;" `
        -description "&lt;/span&gt;Mocking Framework &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; .NET&lt;span style="color: #006080"&gt;" `
        -company "&lt;/span&gt;Hibernating Rhinos&lt;span style="color: #006080"&gt;" `
        -product "&lt;/span&gt;Rhino Mocks $version&lt;span style="color: #006080"&gt;" `
        -version $version `
        -copyright "&lt;/span&gt;Hibernating Rhinos &amp;amp; Ayende Rahien 2004 - 2009&lt;span style="color: #006080"&gt;"
        
    Generate-Assembly-Info `
        -file "&lt;/span&gt;$base_dir\Rhino.Mocks.Tests\Properties\AssemblyInfo.cs&lt;span style="color: #006080"&gt;" `
        -title "&lt;/span&gt;Rhino Mocks Tests $version&lt;span style="color: #006080"&gt;" `
        -description "&lt;/span&gt;Mocking Framework &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; .NET&lt;span style="color: #006080"&gt;" `
        -company "&lt;/span&gt;Hibernating Rhinos&lt;span style="color: #006080"&gt;" `
        -product "&lt;/span&gt;Rhino Mocks Tests $version&lt;span style="color: #006080"&gt;" `
        -version $version `
        -clsCompliant "&lt;/span&gt;&lt;span style="color: #0000ff"&gt;false&lt;/span&gt;&lt;span style="color: #006080"&gt;" `
        -copyright "&lt;/span&gt;Hibernating Rhinos &amp;amp; Ayende Rahien 2004 - 2009&lt;span style="color: #006080"&gt;"
        
    Generate-Assembly-Info `
        -file "&lt;/span&gt;$base_dir\Rhino.Mocks.Tests.Model\Properties\AssemblyInfo.cs&lt;span style="color: #006080"&gt;" `
        -title "&lt;/span&gt;Rhino Mocks Tests Model $version&lt;span style="color: #006080"&gt;" `
        -description "&lt;/span&gt;Mocking Framework &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; .NET&lt;span style="color: #006080"&gt;" `
        -company "&lt;/span&gt;Hibernating Rhinos&lt;span style="color: #006080"&gt;" `
        -product "&lt;/span&gt;Rhino Mocks Tests Model $version&lt;span style="color: #006080"&gt;" `
        -version $version `
        -clsCompliant "&lt;/span&gt;&lt;span style="color: #0000ff"&gt;false&lt;/span&gt;&lt;span style="color: #006080"&gt;" `
        -copyright "&lt;/span&gt;Hibernating Rhinos &amp;amp; Ayende Rahien 2004 - 2009&lt;span style="color: #006080"&gt;"
        
    new-item $release_dir -itemType directory 
    new-item $buildartifacts_dir -itemType directory 
    cp $tools_dir\MbUnit\*.* $build_dir
} 

task Compile -depends Init { 
  exec msbuild "&lt;/span&gt;/p:OutDir=&lt;span style="color: #006080"&gt;""&lt;/span&gt;$buildartifacts_dir &lt;span style="color: #006080"&gt;""&lt;/span&gt; $sln_file&lt;span style="color: #006080"&gt;"
} 

task Test -depends Compile {
  $old = pwd
  cd $build_dir
  exec "&lt;/span&gt;.\MbUnit.Cons.exe&lt;span style="color: #006080"&gt;" "&lt;/span&gt;$build_dir\Rhino.Mocks.Tests.dll&lt;span style="color: #006080"&gt;"
  cd $old        
}

task Merge {
    $old = pwd
    cd $build_dir
    
    Remove-Item Rhino.Mocks.Partial.dll -ErrorAction SilentlyContinue 
    Rename-Item $build_dir\Rhino.Mocks.dll Rhino.Mocks.Partial.dll
    
    &amp;amp; $tools_dir\ILMerge.exe Rhino.Mocks.Partial.dll `
        Castle.DynamicProxy2.dll `
        Castle.Core.dll `
        /out:Rhino.Mocks.dll `
        /t:library `
        "&lt;/span&gt;/keyfile:$base_dir\ayende-open-source.snk&lt;span style="color: #006080"&gt;" `
        "&lt;/span&gt;/internalize:$base_dir\ilmerge.exclude&lt;span style="color: #006080"&gt;"
    if ($lastExitCode -ne 0) {
        throw "&lt;/span&gt;Error: Failed to merge assemblies!&lt;span style="color: #006080"&gt;"
    }
    cd $old
}

task Release -depends Test, Merge {
    &amp;amp; $tools_dir\zip.exe -9 -A -j `
        $release_dir\Rhino.Mocks.zip `
        $build_dir\Rhino.Mocks.dll `
        $build_dir\Rhino.Mocks.xml `
        license.txt `
        acknowledgements.txt
    if ($lastExitCode -ne 0) {
        throw "&lt;/span&gt;Error: Failed to execute ZIP command"
    }
}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is about 50 lines, all told, with a lot of spaces and is quite readable.&lt;/p&gt;

&lt;p&gt;This handles the same tasks as the old set of scripts did, and it does this without undue complexity. I like it.&lt;/p&gt;</description><link>http://ayende.com/4156/on-psake?Key=a139247c-a9eb-49eb-b918-41a87ed8d72c</link><guid>http://ayende.com/4156/on-psake?Key=a139247c-a9eb-49eb-b918-41a87ed8d72c</guid><pubDate>Sun, 30 Aug 2009 12:02:48 GMT</pubDate></item><item><title>The complexity of unity</title><description>&lt;p&gt;This post is about the Rhino Tools project. It has been running for a long time now, over 5 years, and amassed quite a few projects in it.&lt;/p&gt;  &lt;p&gt;I really like the codebase in the projects in Rhino Tools, but secondary aspects has been creeping in that made &lt;em&gt;managing&lt;/em&gt; the project harder. In particular, putting all the projects in a single repository made it easy, far &lt;em&gt;too&lt;/em&gt; easy. Projects had an easy time taking dependencies that they shouldn’t, and the entire build process was… complex, to say the least.&lt;/p&gt;  &lt;p&gt;I have been somewhat unhappily tolerant of this so far because while it was annoying, it didn’t actively create problems for me so far. The problems started creeping when I wanted to move Rhino Tools to use NHibernate 2.1. That is when I realized that this is going to be a very painful process, since I have to take on the entire Rhino Tools set of projects in one go, instead of dealing with each of them independently. the fact that so many of the dependencies where in Rhino Commons, to which I have a profound dislike, helped increase my frustration.&lt;/p&gt;  &lt;p&gt;There are other things that I find annoying now, Rhino Security is a general purpose library for NHibernate, but it makes a &lt;em&gt;lot&lt;/em&gt; of assumptions about how it is going to use, which is wrong. Rhino ETL had a dependency on Rhino Commons because of three classes.&lt;/p&gt;  &lt;p&gt;To resolve that, I decided to make a few other changes, taking dependencies is supposed to be a hard process, it is supposed to make you &lt;em&gt;think&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;I have been working on splitting the Rhino Tools projects to all its sub projects, so each of them is independent of all the others. That increase the effort of managing all of them as a unit, but decrease the effort of managing them independently. &lt;/p&gt;  &lt;p&gt;The current goals are to:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Make it simpler to treat each project independently&lt;/li&gt;    &lt;li&gt;Make it easier to deal with the management of each project (dependencies, build scripts)&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;There is a side line in which I am also learning to use Git, and there is a high likelihood that the separate Rhino Tools projects will move to github. Suversion’s patching &amp;amp; tracking capabilities annoyed me for the very last time about a week ago.&lt;/p&gt;</description><link>http://ayende.com/4155/the-complexity-of-unity?Key=c67b137f-39fe-42a1-990f-815541e1fa4d</link><guid>http://ayende.com/4155/the-complexity-of-unity?Key=c67b137f-39fe-42a1-990f-815541e1fa4d</guid><pubDate>Sun, 30 Aug 2009 08:14:42 GMT</pubDate></item><item><title>Rhino ETL 2.0</title><description>&lt;p&gt;Rhino ETL was born out of a need. I need to do a lot of ETL type operations. Those include anything from moving data from legacy databases to my database, importing files, importing data over web services, etc. For a while, I have used SSIS for those needs. It has proven... inadequate. Mostly in terms of ease of development, deployment, error handling, etc.&lt;/p&gt; &lt;p&gt;This is my third attempt at building an ETL tool. The third time is &lt;em&gt;much&lt;/em&gt; shorter and clearer than both previous attempts. &lt;/p&gt; &lt;p&gt;The goals for the project were:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Developer friendly:&lt;/li&gt; &lt;ul&gt; &lt;li&gt;Errors&lt;/li&gt; &lt;li&gt;Development&lt;/li&gt; &lt;li&gt;Deployment&lt;/li&gt;&lt;/ul&gt; &lt;li&gt;Performant - I need to move large amounts of data around, and I need to do it fast.&lt;/li&gt; &lt;li&gt;Easy - The hard part should be handling the required transforms, dealing with the logic for in/out, etc.&lt;/li&gt; &lt;li&gt;Unlimited - You should not be limited to what the tool gives you, and you should be able to integrate easily with other tools&lt;/li&gt; &lt;li&gt;Language agnostic - You should be able to develop solutions for this using C#/VB/Boo&lt;/li&gt; &lt;li&gt;DSL - Provide a DSL to make it even easier to work with&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;The overall concept is based around these two classes, and the idea of a pipeline:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/RhinoETL2.0_928C/image_2.png"&gt;&lt;img height="145" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/RhinoETL2.0_928C/image_thumb.png" width="163" border="0" /&gt;&lt;/a&gt; &lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/RhinoETL2.0_928C/image_4.png"&gt;&lt;img height="192" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/RhinoETL2.0_928C/image_thumb_1.png" width="211" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;Here is a simple operation, which just generate all the even numbers to a million:&lt;/p&gt; &lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; EvenNumberToMillion : AbstractOperation
{
	&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; IEnumerable&amp;lt;Row&amp;gt; Execute(IEnumerable&amp;lt;Row&amp;gt; rows)
	{
		&lt;span style="color: #0000ff"&gt;for&lt;/span&gt;(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; i = 2; i&amp;lt; 1000000; i += 2)
		{
			Row row = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Row();
			row["&lt;span style="color: #8b0000"&gt;number&lt;/span&gt;"] = i;
			&lt;font color="#0000ff"&gt;yield&lt;/font&gt; &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; row;
		}
	}
}&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;This is an input operation, it ignores its rows parameter, and yields rows generated by some other way. As you can see, we use the yield rows for each iteration. &lt;/p&gt;
&lt;p&gt;We combine operations into a pipeline using the process. If we wanted to print the numbers, we would have build the following pipeline process:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; PrintNumbersProcess : EtlProcess
{
	&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Initialize()
	{
		Register(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; EvenNumberToMillion());
		Register(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; PrintNumbers());
	}
}&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;All the output of the first operation goes into the second operation, and so on and so forth. Using the DSL it will look like:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;operation EvenNumbersToMillion:
	&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; i &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; range(1000000,2):
		yield Row(Number: i)

operation PrintNumbers:
	&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; row &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; rows:
		print row.Number

process PrintNumbersProcess:
	EvenNumbersToMillion()
	PrintNumbers()&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;This is just to demonstrate the concept of the pipeline. Now we can get into the interesting operations. As you already surmised, AbstractOperation is the common base class, and you can inherit it to produce rows from any source. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Inputs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Rhino ETL offers special support for getting data from a database. It means that you can define it simple as:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ReadUsers : ConventionInputCommandOperation
{
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ReadUsers() : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;("&lt;span style="color: #8b0000"&gt;test&lt;/span&gt;")
    {
        Command = "&lt;span style="color: #8b0000"&gt;SELECT Id, Name,Email FROM Users&lt;/span&gt;";
    }
}
&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Or, using DSL:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;input "&lt;span style="color: #8b0000"&gt;test&lt;/span&gt;", Command = "&lt;span style="color: #8b0000"&gt;SELECT id, name, email  FROM Users&lt;/span&gt;"&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Note the "test" here, it is the name of the connection string in the app.config.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Outputs&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;On the output side, we have more interesting options. We can use any custom option that we want, of course, but for working with databases, we have the following options:&lt;/p&gt;
&lt;p&gt;Standard DB commands:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; FibonacciOutput : ConventionOutputCommandOperation
{
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; FibonacciOutput() : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;("&lt;span style="color: #8b0000"&gt;test&lt;/span&gt;")
    {
        Command = "&lt;span style="color: #8b0000"&gt;INSERT INTO Fibonacci (Id) VALUES(@Id)&lt;/span&gt;";
    }
}&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;You'll note that I am not specifying the parameters, those are taken implicitly from the current row.&lt;/p&gt;
&lt;p&gt;Using DSL:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;output "&lt;span style="color: #8b0000"&gt;test&lt;/span&gt;", Command = &lt;span style="color: #8b0000"&gt;"INSERT INTO Fibonacci (Id) VALUES(@Id)"&lt;/span&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;&lt;/blockquote&gt;
&lt;p&gt;SQL Batch operations:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; FibonacciOutput : ConventionSqlBatchOpeartion
{
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; FibonacciOutput() : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;("&lt;span style="color: #8b0000"&gt;test&lt;/span&gt;")
    {
        Command = "&lt;span style="color: #8b0000"&gt;INSERT INTO Fibonacci (Id) VALUES(@Id)&lt;/span&gt;";
    }
}&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Using DSL: Haven't written that yet :-(&lt;/p&gt;
&lt;p&gt;Sql Bulk Insert:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; FibonacciBulkInsert : SqlBulkInsertOperation
    {
        &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; FibonacciBulkInsert() : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;("&lt;span style="color: #8b0000"&gt;test&lt;/span&gt;", "&lt;span style="color: #8b0000"&gt;Fibonacci&lt;/span&gt;")
        {
        }

        &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; PrepareSchema()
        {
            Schema["&lt;span style="color: #8b0000"&gt;id&lt;/span&gt;"] = &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;);
        }
    }&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Using DSL: Haven't written that yet :-(&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Files&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For working with files, we have the support of the excellent &lt;a href="http://www.filehelpers.com/"&gt;FileHelpers library&lt;/a&gt;, which makes working with files really easy. &lt;/p&gt;
&lt;p&gt;Reading from a file is simply:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; UserRecord
{
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; email;
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; id;
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; name;
}

&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ReadUsersFromFile : AbstractOperation
{
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; IEnumerable&amp;lt;Row&amp;gt; Execute(IEnumerable&amp;lt;Row&amp;gt; rows)
    {
        &lt;span style="color: #0000ff"&gt;using&lt;/span&gt;(FileEngine file = FluentFile.For&amp;lt;UserRecord&amp;gt;().From("&lt;span style="color: #8b0000"&gt;users.txt&lt;/span&gt;"))
        {
            &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; obj &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; file)
            {
                yield &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; Row.FromObject(obj);
            }
        }
    }
}&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;There is 1:1 translation to Boo here, so I'll spare you that. &lt;/p&gt;
&lt;p&gt;Writing is very similar:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; WriteUsersToFile : AbstractOperation
{
    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; IEnumerable&amp;lt;Row&amp;gt; Execute(IEnumerable&amp;lt;Row&amp;gt; rows)
    {
        FluentFile engine = FluentFile.For&amp;lt;UserRecord&amp;gt;();
        engine.HeaderText = "&lt;span style="color: #8b0000"&gt;Id\tName\tEmail&lt;/span&gt;";
        &lt;span style="color: #0000ff"&gt;using&lt;/span&gt;(FileEngine file = engine.To("&lt;span style="color: #8b0000"&gt;users.txt&lt;/span&gt;"))
        {
            &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (Row row &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; rows)
            {
                UserRecord record = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; UserRecord();
                
                record.Id = (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;)row["&lt;span style="color: #8b0000"&gt;id&lt;/span&gt;"];
                record.Name = (&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;)row["&lt;span style="color: #8b0000"&gt;name&lt;/span&gt;"];
                record.Email = (&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;)row["&lt;span style="color: #8b0000"&gt;email&lt;/span&gt;"];

                file.Write(record);
            }
        }
        yield &lt;span style="color: #0000ff"&gt;break&lt;/span&gt;;
    }
}&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;Joins&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Joins are an interesting concept, and I play with them quite extensively recently. Joins in Rhino ETL are implemented as sub processes. Hash joins are very simple:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; JoinUsersAndIds : JoinOperation
{
	&lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; Row MergeRows(Row leftRow, Row rightRow)
	{
		Row row = leftRow.Clone();
		row["&lt;span style="color: #8b0000"&gt;user_id&lt;/span&gt;"] = rightRow["&lt;span style="color: #8b0000"&gt;new_id&lt;/span&gt;"];
		&lt;span style="color: #0000ff"&gt;return&lt;/span&gt; row;
	}

	&lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; SetupJoinConditions()
	{
		InnerJoin
			.Left("&lt;span style="color: #8b0000"&gt;id&lt;/span&gt;")
			.Right("&lt;span style="color: #8b0000"&gt;old_id&lt;/span&gt;");
	}
}&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;This is just the operation, you hook it up in the process using:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;Register(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; JoinUsersAndIds()
         	.Left(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; GenerateUsers(25000))
         	.Right(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; GenerateRandomIds(15000)));&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Each side is capable of accepting a full blown sub process on its own.&lt;/p&gt;
&lt;p&gt;Nested loops joins are appropriate for the more complex cases:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; FullJoinUsersToPeopleByEmail : NestedLoopsJoinOperation
{
    &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; MatchJoinCondition(Row leftRow, Row rightRow)
    {
        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; LeftJoin(leftRow["&lt;span style="color: #8b0000"&gt;email&lt;/span&gt;"], rightRow["&lt;span style="color: #8b0000"&gt;email&lt;/span&gt;"]);
    }

	&lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; Row MergeRows(Row leftRow, Row rightRow)
    {
        Row row = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Row();
        row.Copy(leftRow);
        row["&lt;span style="color: #8b0000"&gt;person_id&lt;/span&gt;"] = rightRow["&lt;span style="color: #8b0000"&gt;id&lt;/span&gt;"];
        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; row;
    }
}&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Using DSL it looks like this:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;join get_user_roles:
	left:
		input "&lt;span style="color: #8b0000"&gt;test&lt;/span&gt;", Command = "&lt;span style="color: #8b0000"&gt;SELECT id, name, email  FROM Users&lt;/span&gt;"
		
	right:
		nput "&lt;span style="color: #8b0000"&gt;test&lt;/span&gt;", Command = "&lt;span style="color: #8b0000"&gt;SELECT userid, roleid FROM UsersToRoles&lt;/span&gt;"
			
	on left.id ==  right.userid:
		row.Name = left.Name
		row.Role = right.RoleId&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;(A note about this syntax, this currently generate a nested loop join, I intend to make it generate an optimize version soon).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Branching&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That was quite a challenge to implement, I kept missing a key point, and that tripped me for a while. Here is how send a row to several sources:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;BranchingOperation split = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; BranchingOperation()
	.Add(Partial
		.Register(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; MultiplyByThreeOperation())
		.Register(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Fibonacci.Bulk.FibonacciBulkInsert()))
	.Add(Partial
		.Register(&lt;span style="color: #0000ff"&gt;new&lt;/span&gt; Fibonacci.Bulk.FibonacciBulkInsert()));
Register(split);&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;(Note, the implementation is not as optimized as it could be.)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Aggregates&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Well, you got to have those, don't you? Here is a simple Row Count aggregate:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; RowCount : AbstractAggregationOperation
{
    	&lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Accumulate(Row row, Row aggregate)
      {
            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (aggregate["&lt;span style="color: #8b0000"&gt;count&lt;/span&gt;"] == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)
                aggregate["&lt;span style="color: #8b0000"&gt;count&lt;/span&gt;"] = 0;

            &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; count = (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;)aggregate["&lt;span style="color: #8b0000"&gt;count&lt;/span&gt;"];
            aggregate["&lt;span style="color: #8b0000"&gt;count&lt;/span&gt;"] = count + 1;
      }
}&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;We are called once per row, and can accumulate all the values that we want. We can use grouping to create more interesting results:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; CostPerProductAggregation : AbstractAggregationOperation
{
    &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Accumulate(Row row, Row aggregate)
    {
        aggregate["&lt;span style="color: #8b0000"&gt;name&lt;/span&gt;"] = row["&lt;span style="color: #8b0000"&gt;name&lt;/span&gt;"];
        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(aggregate["&lt;span style="color: #8b0000"&gt;cost&lt;/span&gt;"]==&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)
            aggregate["&lt;span style="color: #8b0000"&gt;cost&lt;/span&gt;"] = 0;
        aggregate["&lt;span style="color: #8b0000"&gt;cost&lt;/span&gt;"] = ((&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;) aggregate["&lt;span style="color: #8b0000"&gt;cost&lt;/span&gt;"]) + ((&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;) row["&lt;span style="color: #8b0000"&gt;price&lt;/span&gt;"]);
    }

    &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[] GetColumnsToGroupBy()
    {
        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[] {"&lt;span style="color: #8b0000"&gt;name&lt;/span&gt;"};
    }
}&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;We can also override the FinishAggregation(Row) method to complete any calculations when all the rows are completed. Rhino ETL guarantees that we will get the same aggregate row for all the rows that match the same columns, so that is taken care of.&lt;/p&gt;
&lt;p&gt;Using DSL for that is simply:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;aggregate join_product_names:
	accumulate:
		aggregate.names = [] &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; aggregate.names &lt;span style="color: #0000ff"&gt;is&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;
		aggregate.names.Add(row.name)
	
	terminate:
		aggregate.result = &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;.Join("&lt;span style="color: #8b0000"&gt;, &lt;/span&gt;", aggregate.names.ToArray(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt;))&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;That is about it for now, I think. You can get the source for Rhino ETL here:&lt;/p&gt;
&lt;p&gt;&lt;a title="https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/rhino-etl" href="https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/rhino-etl"&gt;https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/rhino-etl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I plan to have a binary release one I am confident that all the notes in this post are no longer relevant.&lt;/p&gt;</description><link>http://ayende.com/3102/rhino-etl-2-0?Key=5d7147f9-b8ec-4eca-b8a1-5c5b39eb4ad3</link><guid>http://ayende.com/3102/rhino-etl-2-0?Key=5d7147f9-b8ec-4eca-b8a1-5c5b39eb4ad3</guid><pubDate>Tue, 15 Jan 2008 22:15:11 GMT</pubDate></item><item><title>Algorithms, joins and performance</title><description>&lt;p&gt;I thought about moving from hashtables to Dictionary&amp;lt;T,K&amp;gt;, I got interesting results.&lt;/p&gt; &lt;p&gt;For simple new Dictionary&amp;lt;string,object&amp;gt;(), I expected a significant improvement, but I got this:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Algorithmsjoinsandperformance_F49E/image_2.png"&gt;&lt;img height="143" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Algorithmsjoinsandperformance_F49E/image_thumb.png" width="679" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;This is actually much worse than the result of hashtable + ignore case comparison.&lt;/p&gt; &lt;p&gt;When I used &lt;em&gt;that&lt;/em&gt;, I got this horrendous result:&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Algorithmsjoinsandperformance_F49E/image_4.png"&gt;&lt;img height="174" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Algorithmsjoinsandperformance_F49E/image_thumb_1.png" width="668" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;I tried various other tricks, but none of them change the fact that making 7.5 million calls are going to cost a lot of time. And I want to support more than just 2,500 x 1,500.&lt;/p&gt; &lt;p&gt;I changed the implementation to look like this:&lt;/p&gt; &lt;blockquote&gt;&lt;pre&gt;rightRowsByJoinKey = {}
&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; rightRow &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; right:
	key = rightRow.CreateKey( rightJoinParams )
	rightRowsByJoinKey[ key ] = [] unless rightRowsByJoinKey[ key ]
	rightRowsByJoinKey[ key ].Add(rightRow)

&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; leftRow &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; left:
	key = leftRow.CreateKey( leftJoinParams )
	&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; matchingRight &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; rightRowsByJoinKey[ key ] :
		yield MergeRows( leftRow, rightRow )
&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Now I have N + M, instead on N*M.&lt;/p&gt;
&lt;p&gt;From performance perspective, it means that doing nested loop join on 2,500 x 1,500 result in 3.5 millions comparisons, which is quite a bit, even for such a small set of rows. It took over 6 seconds to run on my machine.&lt;/p&gt;
&lt;p&gt;A hash join, however,will perform  measly 5,000 operations to do the same amount of work. On my machine, 2,500 x 1,500 completes in 0.2 seconds, most of which are spend it just initialization of the framework.&lt;/p&gt;
&lt;p&gt;I try to take that to a spin on with two orders of magnitude more rows, 250,000 x 150,000 has completed in 5.48 seconds. Which is very encouraging.&lt;/p&gt;
&lt;p&gt;Hash join is not applicable if you want to join over anything but equality, which is why we need the nested loops join as well.&lt;/p&gt;</description><link>http://ayende.com/3099/algorithms-joins-and-performance?Key=96b9a257-8cd4-4cf9-900d-45f1c33611ca</link><guid>http://ayende.com/3099/algorithms-joins-and-performance?Key=96b9a257-8cd4-4cf9-900d-45f1c33611ca</guid><pubDate>Mon, 14 Jan 2008 17:25:42 GMT</pubDate></item><item><title>Performance, Joins and why you should always have a profiler</title><description>&lt;p&gt;I did some heavy duty import process yesterday, and we run into severe performance issue with Rhino ETL joins. Five joins with about 250,000 records on the initial left and a few tens of thousands on the rights took about 2 hours to complete.&lt;/p&gt; &lt;p&gt;That was unacceptable, and I decided that I have to fix this issue. I had a fairly good idea about what the issue was. Rhino ETL supports nested loops joins only at the moment, which means that the join is performed as (pseudo code):&lt;/p&gt; &lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; leftRow &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; left:
	&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; rightRow &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; right:
		&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; MatchJoinCondition(leftRow, rightRow):
			yield MergeRows(leftRow, rightRow)&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Obviously the N*M was what causing the problem right? I quickly built a trivial join test, which joined 2,500 rows on the left with 1,500 rows on the right. Trivial stuff, and should result in 1,500 rows returned.&lt;/p&gt;
&lt;p&gt;It executed in &lt;em&gt;6 seconds&lt;/em&gt;. That was a shock. &lt;/p&gt;
&lt;p&gt;Well 1,500 * 2,500  = 3,750,000, but it should be &lt;em&gt;that&lt;/em&gt; bad. &lt;/p&gt;
&lt;p&gt;Then I run the code under a profiler, and it completed in &lt;em&gt;29 seconds,&lt;/em&gt; but I also saw this:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/PerformanceJoinsandwhyyoushouldalwayshav_C1D8/image_2.png"&gt;&lt;img height="126" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/PerformanceJoinsandwhyyoushouldalwayshav_C1D8/image_thumb.png" width="801" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;It is not the nested loop that cost me all this money, it was the hash table lookups!&lt;/p&gt;
&lt;p&gt;The most expensive call was GetHashCodeOfString, we have some globalization stuff here, because I told the hashtable to be case insensitive, I tried removing that and run it under the profiler again, now it dropped to &lt;em&gt;18 seconds, &lt;/em&gt;and we had this cost structure to deal with:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/PerformanceJoinsandwhyyoushouldalwayshav_C1D8/image_4.png"&gt;&lt;img height="85" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/PerformanceJoinsandwhyyoushouldalwayshav_C1D8/image_thumb_1.png" width="822" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;We still spend almost all of our time just doing hash table lookups, although we dropped by 10 seconds this time.&lt;/p&gt;
&lt;p&gt;I don't think that I would have ever consider the cost of simply doing the hashtable lookups as the primary cost of the join operations.&lt;/p&gt;</description><link>http://ayende.com/3098/performance-joins-and-why-you-should-always-have-a-profiler?Key=669fdb4f-aef0-4bc1-8c7e-13401fbee796</link><guid>http://ayende.com/3098/performance-joins-and-why-you-should-always-have-a-profiler?Key=669fdb4f-aef0-4bc1-8c7e-13401fbee796</guid><pubDate>Mon, 14 Jan 2008 11:50:31 GMT</pubDate></item><item><title>Fluent Pipelines</title><description>&lt;p&gt;I am having a &lt;a href="http://www.ayende.com/Blog/archive/2008/01/05/Pipes-and-filters-The-IEnumerable-appraoch.aspx"&gt;discussion&lt;/a&gt; with Jon Skeet about the merits of using Linq for pipelines and delegates/lambda instead of classes.&lt;/p&gt; &lt;p&gt;I kept saying that I don't really see the point, so I went ahead and implemented this:&lt;/p&gt; &lt;blockquote&gt;&lt;pre&gt;GenerateData(10000)//enumerator from 0 .. 10000
	.Where(i =&amp;gt; i % 3 == 0)
	.Transform(i =&amp;gt; (i * 2).ToString() )
	.Act(i =&amp;gt; Console.WriteLine(i))
	.Execute();
&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;This uses the same approach as my previous pipeline, but it does it in C# 3.0, so it can use things like extension methods, which make this nicer. The same in C# 2.0 is possible, but take some ridiculous amount of code to do.&lt;/p&gt;
&lt;p&gt;This code is much simpler than the code I have shown &lt;a href="http://ayende.com/Blog/archive/2008/01/05/Pipes-and-filters-The-IEnumerable-appraoch.aspx"&gt;here&lt;/a&gt;, no?&lt;/p&gt;
&lt;p&gt;Why do I use the first approach then?&lt;/p&gt;
&lt;p&gt;Scalability.&lt;/p&gt;
&lt;p&gt;What we are seeing here is about as trivial as it can get. What happens when we have more complex semantics?&lt;/p&gt;
&lt;p&gt;Let us take writing to the database as an example. We need to do quite a bit there, more than we would put in the lambda expression, certainly. We can extract to a method, but then we run into another problem, we can't do method inheritance. This means that I have no easy way of abstracting the common stuff outside. Well, I can use template method, but that works if and only if I have a single place I want to change behavior.&lt;/p&gt;
&lt;p&gt;As an example of scaling, let us take this piece of code:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; FibonacciBulkInsert : SqlBulkInsertOperation
{
	&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; FibonacciBulkInsert() : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;("&lt;span style="color: #8b0000"&gt;test&lt;/span&gt;", "&lt;span style="color: #8b0000"&gt;Fibonacci&lt;/span&gt;")
	{
	}

	&lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; PrepareSchema()
	{
		Schema["&lt;span style="color: #8b0000"&gt;id&lt;/span&gt;"] = &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;int&lt;/span&gt;);
	}
}&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Which uses &lt;a href="https://rhino-tools.svn.sourceforge.net/svnroot/rhino-tools/trunk/rhino-etl2/Rhino.Etl.Core/Operations/SqlBulkInsertOperation.cs"&gt;this base class&lt;/a&gt; to handle the bulk of the work.&lt;/p&gt;
&lt;p&gt;One thing that Jon mentioned that was interesting was the ability to take advantage of Linq specific improvements, such as PLinq. This is indeed a consideration, but upon some reflection on it, I realized that the two are not mutually exclusive. If I want to take advantage of any of that, all I need is to modify the pipeline to iterate using PLinq rather than foreach.&lt;/p&gt;</description><link>http://ayende.com/3085/fluent-pipelines?Key=6afe8a1e-3dd7-4954-95fa-c3444e799e72</link><guid>http://ayende.com/3085/fluent-pipelines?Key=6afe8a1e-3dd7-4954-95fa-c3444e799e72</guid><pubDate>Sun, 06 Jan 2008 22:52:51 GMT</pubDate></item><item><title>My Code Sucks</title><description>&lt;p&gt;There is a point where a project goes beyond the pale, where the complexity goes so far out of line that it is simply ludicrous.&lt;/p&gt; &lt;p&gt;I had such a point today. I had enough with SSIS and decided that I want to replace it with something better. I wrote an ETL tool to handle that in a few hours. &lt;/p&gt; &lt;p&gt;Why is this relevant? Because I have &lt;em&gt;already&lt;/em&gt; build an ETL tool. Rhino ETL.&lt;/p&gt; &lt;p&gt;It is quite telling when the &lt;em&gt;author &lt;/em&gt;of a tool decide that he doesn't want to use it.&lt;/p&gt; &lt;p&gt;I was decidedly proud of Rhino ETL for a while, then the problems started to creep in. The problems were not in the code per se, the entire architecture of the code was overly complex. In order to handle this complexity, I had resorted to throwing code at the problem, and then more code, and more code yet again. &lt;/p&gt; &lt;p&gt;At the moment, the current code base has two "minor" problems, exception handling and threading. The bigger problem is that I don't want to have to wade into this stinking pile and try to figure out what is going on there. I tried to be clever, and it &lt;em&gt;is&lt;/em&gt; clever, in a horrible sort of way.&lt;/p&gt; &lt;p&gt;I don't have the time or patience to decipher code at the best of time, and at this point, it has gotten simply too complex. The project right now is at ~9,000 lines of code, so it is not that it is big, it is simply complex. &lt;/p&gt; &lt;p&gt;From the architecture perspective, I have made one huge mistake, I exposed the threading model to the application code. You can say that this stand in the root of my problems. I actually re-wrote this once already, moving from a home grown threading solution to using Retlang for threading. I made the same mistake and exposed the threading model to the application itself. Can you &lt;em&gt;say: &lt;/em&gt;Big mistake!&lt;/p&gt; &lt;p&gt;From the point of view of the project itself, I started by defining the DSL syntax, and then built the project around that. It turns out that this has the usual "let us build the whole layer at a time". It also meant that a lot of the code had deep assumptions about the way it is called, making it unusable for using in other ways. This is excusable if we are talking about the DSL mapping layer, but not for the core code base itself.&lt;/p&gt; &lt;p&gt;Anyway, I am ranting and I should stop.&lt;/p&gt; &lt;p&gt;I spend six to eight hours today rewriting it from scratch.  It doesn't do threading, and it doesn't have a DSL interface yet, but it does pretty much everything that the old project did, in a quarter of the lines of code, and in a way that is much safer and easier to handle than what we are using currently.&lt;/p&gt;</description><link>http://ayende.com/3080/my-code-sucks?Key=5f7cd172-e244-4b4a-a1f7-e245e02484ab</link><guid>http://ayende.com/3080/my-code-sucks?Key=5f7cd172-e244-4b4a-a1f7-e245e02484ab</guid><pubDate>Fri, 04 Jan 2008 00:44:02 GMT</pubDate></item><item><title>Perfoming joins without having all the data in memory</title><description>&lt;p&gt;Probably the easier way to perform a join is by a nested loop, given dataset A and dataset B, joining all the rows to dataset C is simple:&lt;/p&gt; &lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; row_a &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; A:
	&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; row_b &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; B:
		&lt;span style="color: #0000ff"&gt;if&lt;/span&gt; condition(row_a, row_b):
			add join(row_a, row_b), C
&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Supporting left/right/cross joins is simple matter from here, but this has the issue of having to have both datasets in memory. I run into it while processing big files, I don't want to have to hold them in memory, especially if I need several level of joins in order to correctly process them.&lt;/p&gt;
&lt;p&gt;I thought about bypassing the entire issue by simply writing the data down to a sqlite DB, and doing the join there. While this is possible, I would rather avoid having to do this.&lt;/p&gt;
&lt;p&gt;Any suggestions on where to look to solve this issue?&lt;/p&gt;</description><link>http://ayende.com/3013/perfoming-joins-without-having-all-the-data-in-memory?Key=7c617118-8712-4836-af52-51d995352afc</link><guid>http://ayende.com/3013/perfoming-joins-without-having-all-the-data-in-memory?Key=7c617118-8712-4836-af52-51d995352afc</guid><pubDate>Thu, 06 Dec 2007 10:22:41 GMT</pubDate></item><item><title>Rhino ETL: Importing Data into MS CRM</title><description>&lt;p&gt;Okay, so this is the "coding in anger" part for Rhino ETL. I need to import files into MS CRM entities. The files are standard CSV files, with the usual corruption of values that such files have. The CRM is accessed through the web services, although I am keeping aside the option of direct DB access, if I can't get the Web Services to perform any faster.&lt;/p&gt; &lt;p&gt;The first problem that I had was that the MS CRM Web Services are not simple services. They accept entities that are defined in the WSDL for them, not simple values. That put me in a complexity spin for a while, until I remembered that I am not working in my own little language, I am working on .NET. A quick trip to Visual Studio and an Add Web Reference + Compile later, I had integrated accessing the MS CRM into Rhino ETL.&lt;/p&gt; &lt;p&gt;Here is how it was done:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;font color="#0000ff"&gt;import &lt;/font&gt;CrmProxy.Crm &lt;font color="#0000ff"&gt;from&lt;/font&gt; CrmProxy&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Basically it means that I now had a dll that contains the proxy definitions for the web service, and I imported it. So it is incredibly easy to use.&lt;/p&gt; &lt;p&gt;Then, it was the matter of reading the file. Rhino ETL has integrated with the &lt;a href="http://www.filehelpers.com/"&gt;FileHelpers&lt;/a&gt; library, and I couldn't really be happier about it. There are several reasons for that, but the main one is that &lt;em&gt;I run into something that the library &lt;/em&gt;can't &lt;em&gt;handle, and I fixed that in 10 minutes, without changing the library code&lt;/em&gt;. Speaking of software that I like, this is one of the main criteria that I use to evaluate a piece of software. What happens when I step off the ledge? With FileHelpers, I can extend it so easily, that I really don't care about that.&lt;/p&gt; &lt;p&gt;Anyway, here is a part of the class definition for our file: &lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;[&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;DelimitedRecord&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;","&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;), &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;IgnoreFirst&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;]&lt;br /&gt;&lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;class &lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Customer:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;[&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;FieldConverter&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ConverterKind&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Date&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;, &lt;/span&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;"dd/MM/yyyy"&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)] &lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;UpdateDate &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;as &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;date&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Id &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;as &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;int&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Name &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;as &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;string&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ResponsibleEmployee &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;as &lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Nullable &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;of &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;int&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;[&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;FieldConverter&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Rhino&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ETL&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;FileHelpersExtensions&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;DateTimeConverterWithNullValue&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;, &lt;/span&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;"dd/MM/yyyy"&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;,&lt;/span&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;"00/00/0000"&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)] &lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ReceptionDate &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;as &lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Nullable &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;of &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;date&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;As you can see, there isn't much to it except defining the fields, types, etc.&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: darkorange; font-family: 'Courier New'"&gt;source &lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CustomersFile:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;     &lt;/span&gt;execute:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;file &lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;= &lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;Read&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;typeof&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Customer&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)).&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;From&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Configuration&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CustomerFile&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;file&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;OnError&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ErrorMode&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;SaveAndContinue&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;for &lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;customer &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;in &lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;file:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;print &lt;/span&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;"Source &lt;/span&gt;&lt;span style="font-size: 10pt; color: #993366; font-family: 'Courier New'"&gt;${customer.Id}&lt;/span&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;"&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;SendRow&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;( &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Row&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;FromObject&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;customer&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;) ) &lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;if &lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;file&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;HasErrors:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;file&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;OutputErrors&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Configuration&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CustomerErrorsFile&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;AddError&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;"Errors have been written to &lt;/span&gt;&lt;span style="font-size: 10pt; color: #993366; font-family: 'Courier New'"&gt;${Configuration.CustomerErrorsFile}&lt;/span&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;"&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Here I read from the file, use the Row.FromObject() to translate an entity into a row, and then send it forward. One &lt;em&gt;amazing&lt;/em&gt; thing here is that FileHelpers will generate an errors file for me on demand. And that one is clear and concise and actually useful. Comparing to the amount of effort that I know are required to pull reasonable errors from SSIS file input, that is a great pleasure.&lt;/p&gt; &lt;p&gt;Anyway, if you missed that, I am &lt;em&gt;very happy &lt;/em&gt;about FileHelpers.&lt;/p&gt; &lt;p&gt;Another thing to point out is the Configuration.CustomerFile, etc. The Configuration object is dynamically populated from a config file that you can pass to Rhino ETL (command line arg), which is a simple xml file in the format:&lt;/p&gt; &lt;blockquote&gt;&lt;pre&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;configuration&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
	&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;CustomerErrorsFile&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;D:\customers_errors.txt&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;CustomerErrorsFile&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;configuration&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Why XML? Because this seems like a place where I would want to touch with stuff like xmlpoke, etc. So it is easier to work with. It is also a flat configuration scheme, that doesn't have any semantics other than the simple key/value pair.&lt;/p&gt;
&lt;p&gt;So, now that I have the data, I can send it to the destination:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: darkorange; font-family: 'Courier New'"&gt;destination &lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Crm:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;initialize:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;Parameters&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Srv &lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;= &lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;CrmService&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Url: Configuration&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Url&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Credentials: &lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;NetworkCredential&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;                            &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Configuration&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Username&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;, &lt;br /&gt;                            &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Configuration&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Password&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;, &lt;br /&gt;                            &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Configuration&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Domain&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;),&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CallerIdValue: &lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;CallerId&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CallerGuid: &lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;Guid&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Configuration&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CallerId&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)),&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;UnsafeAuthenticatedConnectionSharing: &lt;b&gt;true&lt;/b&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;PreAuthenticate: &lt;b&gt;true&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;onRow:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;theAccount &lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;= &lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;account&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;accountnumber: Row&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Id&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;ToString&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(),&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;name: Row&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Name&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;telephone1: Row&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Phone&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;telephone2: Row&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Cellular&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;telephone3: Row&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;AdditionalPhone&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;fax: Row&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Fax&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: gray; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;accountreceptiondate: &lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;CrmDateTime&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Value: Row&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ReceptionDate&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;ToString&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;"yyyy-MM-ddT00:00:00"&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)),&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;address1_city: Row&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;City&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: gray; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;result &lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;= &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Parameters&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Srv&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;Create&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;theAccount&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;print &lt;/span&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;"Created account &lt;/span&gt;&lt;span style="font-size: 10pt; color: #993366; font-family: 'Courier New'"&gt;${Row.Id} &lt;/span&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;-&amp;gt; &lt;/span&gt;&lt;span style="font-size: 10pt; color: #993366; font-family: 'Courier New'"&gt;${result}&lt;/span&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;"&lt;/span&gt;&lt;/p&gt;
&lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: firebrick; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;cleanUp:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; line-height: 115%; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;Parameters&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; line-height: 115%; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; line-height: 115%; font-family: 'Courier New'"&gt;Srv&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; line-height: 115%; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; line-height: 115%; font-family: 'Courier New'"&gt;Dispose&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; line-height: 115%; font-family: 'Courier New'"&gt;()&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;
&lt;p&gt;As you can see, we have the initialize method, which creates the service, then we instansiate an account instance, fill it with the required parameters, and go to town. It is also notable the easy translation of types from CLR types to CRM types, such as in the case of accountreceptiondate.&lt;/p&gt;
&lt;p&gt;All in all, the only difficulities that I had during this were to make heads or tails from the inforamtion in the file, which is where I &lt;em&gt;want&lt;/em&gt; the difficulity to lie when I am dealing with ETL processes.&lt;/p&gt;</description><link>http://ayende.com/2878/rhino-etl-importing-data-into-ms-crm?Key=3a316a38-7cf0-4639-8f4a-7bcb9b2891e5</link><guid>http://ayende.com/2878/rhino-etl-importing-data-into-ms-crm?Key=3a316a38-7cf0-4639-8f4a-7bcb9b2891e5</guid><pubDate>Tue, 16 Oct 2007 10:51:23 GMT</pubDate></item><item><title>We want to build something... beautiful!</title><description>&lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Wewanttobuildsomething.beautiful_6FC/image.png" atomicselection="true"&gt;&lt;img style="border-right: 0px; border-top: 0px; margin: 0px 15px 0px 0px; border-left: 0px; border-bottom: 0px" alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/Wewanttobuildsomething.beautiful_6FC/image_thumb.png" align="left" border="0" /&gt;&lt;/a&gt;I have currently stopped working on the UI for Rhino ETL, and it is an interesting experience. In the past, I have usually started with building the functionality and then adding the UI for it. That failed. The problem wasn't that the functionality wasn't there, it was that the UI wasn't nice enough for use, or wasn't pretty enough to attract.&lt;/p&gt; &lt;p&gt;This time, I am doing it in reverse, I am building the UI first, at least the rough draft of it, and then I intend to go and hook everything up. This means that while the picture on the right looks very nice, it is mostly skeleton with nice UI, without much functionality.&lt;/p&gt; &lt;p&gt;Right now it is just an editor for Rhino ETL scripts, but I am currently hooking up the requirements for a project system that would allow me to build some really interesting functionality on top of the scripts.&lt;/p&gt; &lt;p&gt;You can see some of the ideas that I have in the live view pane, which should allow me to visualize everything in the project for ease of use.&lt;/p&gt; &lt;p&gt;Doing it the other way around is not likely to be possible, sadly, except in the most trivial cases, so I think that I will skip that.&lt;/p&gt; &lt;p&gt;Anyway, the point of this post is that by giving it a good looking UI, I make &lt;em&gt;myself&lt;/em&gt; feel much better about the application. Working on an ugly application is distasteful, and you tend to just try to get away. Working on pretty ones make you want to improve the current state. &lt;/p&gt; &lt;p&gt;That is the whole No Broken Windows mentality again, by the way, as well as some self motivation practices. Beside, and that is a secret, working on the UI allows me to consider the back end in a very detailed way without getting too low level.&lt;/p&gt; &lt;p&gt;Almost by accident, there is &lt;a href="http://worsethanfailure.com/Articles/The-Cool-Cam.aspx"&gt;this Daily WTF post&lt;/a&gt; about just this issue. Insightful is not something that I use lightly with regards to the Daily WTF posts, but this one is certainly is.&lt;/p&gt; &lt;p&gt;If you possibly can, make it pretty, you, your users, and the application will be thankful.&lt;/p&gt;</description><link>http://ayende.com/2714/we-want-to-build-something-beautiful?Key=2a459c1a-ef4e-45d2-8e21-dfc90a90c52c</link><guid>http://ayende.com/2714/we-want-to-build-something-beautiful?Key=2a459c1a-ef4e-45d2-8e21-dfc90a90c52c</guid><pubDate>Tue, 14 Aug 2007 21:50:46 GMT</pubDate></item><item><title>Rhino ETL - IDE</title><description>&lt;p&gt;Hush, it is a secret...&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ac9e53d7291c_80C0/image.png" atomicselection="true"&gt;&lt;img alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/ac9e53d7291c_80C0/image_thumb.png" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;</description><link>http://ayende.com/2711/rhino-etl-ide?Key=f25e52ae-08c8-4a58-a5e6-f3ec7cd902e0</link><guid>http://ayende.com/2711/rhino-etl-ide?Key=f25e52ae-08c8-4a58-a5e6-f3ec7cd902e0</guid><pubDate>Tue, 14 Aug 2007 06:10:10 GMT</pubDate></item><item><title>Rhino ETL: Writing to files</title><description>&lt;blockquote&gt;&lt;/blockquote&gt; &lt;p&gt;Just finished writing the tests for reading and writing files. You can check the script below. With the exception of making the connection syntax consistent with the rest of it, I am going to consider this feature complete, the next things to is to work on deployment (basically, a tool that allows to run the script :-) ). &lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;[DelimitedRecord("\t")]&lt;br /&gt;class Customers:&lt;br /&gt;    public OrderID as int&lt;br /&gt;    public CustomerID as string&lt;br /&gt;    public EmployeeID as int  &lt;/p&gt;&lt;p&gt;connection( &lt;br /&gt;    "Database",&lt;br /&gt;    ConnectionType: SqlConnection,&lt;br /&gt;    ConnectionString: "Data Source=localhost;Initial Catalog=ETL_Test; Integrated Security=SSPI;"&lt;br /&gt;    )&lt;br /&gt;source OrdersFromDatabase, Connection="Database":&lt;br /&gt;    Command: "SELECT OrderID, CustomerID, EmployeeID FROM Orders"  &lt;/p&gt;&lt;p&gt;destination OrdersFile:&lt;br /&gt;    initialize:&lt;br /&gt;        Parameters.File = Write(Customers).To("output.txt")&lt;br /&gt;    onRow:&lt;br /&gt;        cust = Customers( &lt;br /&gt;            OrderID: Row.OrderID, &lt;br /&gt;            CustomerID: Row.CustomerID,&lt;br /&gt;            EmployeeID: Row.EmployeeID&lt;br /&gt;            )&lt;br /&gt;        Parameters.File.Write(cust)&lt;br /&gt;    cleanUp:&lt;br /&gt;        Parameters.File.Dispose()  &lt;/p&gt;&lt;p&gt;pipeline OutputOrders:&lt;br /&gt;    OrdersFromDatabase &amp;gt;&amp;gt; OrdersFile&lt;br /&gt;target default:&lt;br /&gt;    Execute("OutputOrders")&lt;/p&gt;&lt;/blockquote&gt;</description><link>http://ayende.com/2709/rhino-etl-writing-to-files?Key=4c896ece-58f2-43f4-9fb5-6ed5f6ab7ec6</link><guid>http://ayende.com/2709/rhino-etl-writing-to-files?Key=4c896ece-58f2-43f4-9fb5-6ed5f6ab7ec6</guid><pubDate>Mon, 13 Aug 2007 13:10:28 GMT</pubDate></item><item><title>Rhino ETL &amp; FileHelpers Integration</title><description>&lt;p&gt;Well, this image really excites me. It excites me because I got this after integration &lt;a href="http://www.filehelpers.com/"&gt;FileHelpers&lt;/a&gt; into Rhino ETL. This image is the result of an ETL script that joined a file against a table, did some additional processing on it and push it to a table in a third database.&lt;/p&gt; &lt;p&gt;I must say that &lt;a href="http://www.filehelpers.com/"&gt;FileHelpers&lt;/a&gt; has made this ridiculously easy to do.  All I have left to do is figure out how to test such a thing effectively.&lt;/p&gt; &lt;p&gt;&lt;a href="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/RhinoETLFileHelpersIntegration_124B6/image.png" atomicselection="true"&gt;&lt;img alt="image" src="http://ayende.com/Blog/images/ayende_com/Blog/WindowsLiveWriter/RhinoETLFileHelpersIntegration_124B6/image_thumb.png" border="0" /&gt;&lt;/a&gt; &lt;/p&gt; &lt;p&gt;For reference, here is the complete script:&lt;/p&gt; &lt;blockquote&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;[&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;DelimitedRecord&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;"\t"&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)]&lt;br /&gt;&lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;class &lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Customers:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;CustomerID &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;as &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;string&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CompanyName &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;as &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;string&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ContactName &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;as &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;string&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ContactTitle &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;as &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;string&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Address &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;as &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;string&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;City &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;as &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;string&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Country &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;as &lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;string&lt;?xml:namespace prefix = o /?&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: purple; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;connection&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;( &lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;"DestinationDB"&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ConnectionType: SqlConnection&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ConnectionString: &lt;/span&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;"Data Source=localhost;Initial Catalog=ETL_Test; Integrated Security=SSPI;"&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;connection&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;( &lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;"Northwind"&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ConnectionType: SqlConnection&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ConnectionString: &lt;/span&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;"Data Source=localhost;Initial Catalog=Northwind; Integrated Security=SSPI;"&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)&lt;span style="mso-tab-count: 1"&gt;     &lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;source CustomersFile:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;execute:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;for &lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;customer &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;in &lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;Read&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;typeof&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Customers&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)).&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;From&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: green; font-family: 'Courier New'"&gt;"""Files\CustomersTab.txt"""&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 3"&gt;                  &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;SendRow&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;( &lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; font-family: 'Courier New'"&gt;Row&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;( &lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 4"&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CustomerId: customer&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CustomerID&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;, &lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 4"&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CompanyName: customer&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CompanyName&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;,&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 4"&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ContactName: customer&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ContactName&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 4"&gt;                        &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;)) &lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;source OrdersFromDatabase&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;, &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Connection&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;=&lt;/span&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;"Northwind"&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;Command: &lt;/span&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;"SELECT * FROM Orders"&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;join CustomersAndOrders:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;if &lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Left&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CustomerID &lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;== &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Right&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CustomerID:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;Row&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;OrderID &lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;= &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Right&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;OrderID&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;Row&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CompanyName &lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;= &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Left&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CompanyName&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;Row&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ContactName &lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;= &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Left&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;ContactName&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-spacerun: yes"&gt; &lt;/span&gt;destination Final&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;, &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Connection&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;=&lt;/span&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;"DestinationDB"&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;Command: &lt;/span&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;"INSERT INTO OrdersWareHousing VALUES(@OrderID, @CompanyName,@ContactName)"&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: blue; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 2"&gt;            &lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;pipeline OrdersWareHouse:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;CustomersFile &lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CustomersAndOrders&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Left&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;OrdersFromDatabase &lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;CustomersAndOrders&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;.&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Right&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;CustomersAndOrders &lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; font-family: 'Courier New'"&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;Final&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/span&gt;&lt;/p&gt; &lt;p class="MsoNormal" style="margin-bottom: 0pt; line-height: normal; mso-layout-grid-align: none"&gt;&lt;span style="font-size: 10pt; color: black; font-family: 'Courier New'"&gt;&lt;span style="mso-spacerun: yes"&gt; &lt;/span&gt;target default:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: black; line-height: 115%; font-family: 'Courier New'"&gt;&lt;span style="mso-tab-count: 1"&gt;      &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size: 10pt; color: midnightblue; line-height: 115%; font-family: 'Courier New'"&gt;Execute&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; line-height: 115%; font-family: 'Courier New'"&gt;(&lt;/span&gt;&lt;span style="font-size: 10pt; color: blue; line-height: 115%; font-family: 'Courier New'"&gt;"OrdersWareHouse"&lt;/span&gt;&lt;span style="font-size: 10pt; color: darkgreen; line-height: 115%; font-family: 'Courier New'"&gt;)&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;</description><link>http://ayende.com/2694/rhino-etl-filehelpers-integration?Key=8aab441e-9c37-461f-a4df-1952cf626b32</link><guid>http://ayende.com/2694/rhino-etl-filehelpers-integration?Key=8aab441e-9c37-461f-a4df-1952cf626b32</guid><pubDate>Thu, 09 Aug 2007 17:51:09 GMT</pubDate></item><item><title>Rhino ETL: Web Services Source</title><description>&lt;p&gt;Well, after some thinking, I figured out that I actually had only two types of sources, database and other. Since other is going to always be code, I decided to start with web services source, since that is arguably the easiest (nothing much to do there). It turned out to be more complicated than I assumed, mainly because the .Net 2.0 web service stack has no easy way to do duck typing of web services. It &lt;em&gt;requires&lt;/em&gt; compiled web services. I got around that by doing runtime compilation, but still,that is hardly elegant.&lt;/p&gt; &lt;p&gt;&lt;em&gt;Anyway&lt;/em&gt;, what I have now is this:&lt;/p&gt; &lt;blockquote&gt;&lt;pre&gt;&lt;font color="#0000ff"&gt;source&lt;/font&gt; WebServiceGenerator:
	&lt;font color="#0000ff"&gt;execute&lt;/font&gt;:
		empSrv= WebService(WsdlUrl: "&lt;span style="color: #8b0000"&gt;http://localhost:9090/GetEmployees.asmx?wsdl&lt;/span&gt;" )
		results = empSrv.GetEmployees("&lt;span style="color: #8b0000"&gt;Northwind&lt;/span&gt;")
		&lt;span style="color: #0000ff"&gt;for&lt;/span&gt; result &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; results:
			SendRow( Row(
				Id: result.Id,
				Name: result.Name
				))&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;As you can see, the only thing that I really need to do is to specify the WSDL url for the web services, and everything from there is fairly natural. The execute block is used to distinguish between database sources (which has command, parameter, etc) and the "other" sources, such as the one above.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Due to the way Rhino ETL works, the order of the sent rows and the order of their processing may differ. This means that if the web service send you Emp #1, Emp #2, Emp #3, they may be processed in Emp #1, Emp #3, Emp #2. (Actually, the issue would tend to come up with larger amount of rows, since the problem is different processing of the batches.&lt;/p&gt;
&lt;p&gt;Next step, supporting Web Service &lt;em&gt;output&lt;/em&gt;, which may require some complexity if the web service expect complex types (and since I know that I need to handle those, I have to support that with dynamic compilation, that is going to make my life interesting :-)&lt;/p&gt;
&lt;p&gt;After that, I intend to start integrating &lt;a href="http://filehelpers.sourceforge.net/"&gt;File Helpers&lt;/a&gt; as a source / destination for files. I will post separately on this, but so far I am &lt;em&gt;impressed&lt;/em&gt; with both the ease of the API and the quality of the documentation.&lt;/p&gt;</description><link>http://ayende.com/2683/rhino-etl-web-services-source?Key=c391278d-7127-40e6-a853-eb9cfd3ffd87</link><guid>http://ayende.com/2683/rhino-etl-web-services-source?Key=c391278d-7127-40e6-a853-eb9cfd3ffd87</guid><pubDate>Sun, 05 Aug 2007 01:12:23 GMT</pubDate></item><item><title>Rhino ETL: Targets</title><description>&lt;p&gt;Well, that is two items down my list already, I have added support for targets to Rhino ETL. A target is similar in concept to a target in NAnt, it specify what needs to be run when the package run. This allows to specify how we want to run the various actions that we have.&lt;/p&gt; &lt;p&gt;Here is a simple example:&lt;/p&gt; &lt;blockquote&gt;&lt;pre&gt;&lt;font color="#000000"&gt;&lt;font color="#0000ff"&gt;target&lt;/font&gt; default: &lt;br /&gt;&lt;/font&gt;&lt;font color="#000000"&gt;	Execute("&lt;/font&gt;&lt;span style="color: #8b0000"&gt;CopyOrders&lt;/span&gt;")
	Execute("&lt;span style="color: #8b0000"&gt;MoveCustomers&lt;/span&gt;")&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;As you can see, it just lists the pipelines that we want to run. By default, the target execute all the registered pipelines (or other actions) in parallel. But what happens when you want to run them in a sequence?&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;font color="#000000"&gt;&lt;font color="#0000ff"&gt;target&lt;/font&gt; &lt;/font&gt;default:
	&lt;font color="#0000ff"&gt;sequence&lt;/font&gt;:
		Execute("&lt;span style="color: #8b0000"&gt;CopyOrders&lt;/span&gt;")
		Execute("&lt;span style="color: #8b0000"&gt;MoveCustomers&lt;/span&gt;")&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Another option is that you have a dependency between two pipelines, but you don't care about the rest, you can do this as well, like this:&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;&lt;font color="#0000ff"&gt;target&lt;/font&gt; withDependencies:
	copyOrders = Execute("&lt;span style="color: #8b0000"&gt;CopyOrders&lt;/span&gt;")
	Execute("&lt;span style="color: #8b0000"&gt;MoveCustomers&lt;/span&gt;")
	Execute("&lt;span style="color: #8b0000"&gt;AfterCopyOrders&lt;/span&gt;").After(copyOrders)&lt;/pre&gt;&lt;/blockquote&gt;
&lt;p&gt;Next task, transactions...&lt;/p&gt;</description><link>http://ayende.com/2680/rhino-etl-targets?Key=49d4f1e6-eddf-4bb6-af6d-50beb9d5a0fe</link><guid>http://ayende.com/2680/rhino-etl-targets?Key=49d4f1e6-eddf-4bb6-af6d-50beb9d5a0fe</guid><pubDate>Sat, 04 Aug 2007 17:53:30 GMT</pubDate></item><item><title>Rhino ETL: Aggregates</title><description>&lt;p&gt;SoWell, that turned out to be really simple. Check out a simple RowCount:&lt;/p&gt;&lt;pre&gt;&lt;font color="#0000ff"&gt;transform&lt;/font&gt; CountRows:
	Context.Items.RowCount = 0 &lt;font color="#0000ff"&gt;unless&lt;/font&gt; Context.Items.RowCount
	Context.Items.RowCount+=1
	RemoveRow()&lt;/pre&gt;&lt;pre&gt;	OnComplete:
		SendRow( Row(RowCount: Context.Items.RowCount) )&lt;/pre&gt;&lt;pre&gt; &lt;/pre&gt;
&lt;p&gt;And then we have a more complex one, summing two columns:&lt;/p&gt;&lt;pre&gt;&lt;font color="#0000ff"&gt;transform&lt;/font&gt; CalcSumOfSalaryAndId:
	&lt;font color="#0000ff"&gt;unless&lt;/font&gt; Context.Items.IdSum:
		Context.Items.IdSum = 0 
		Context.Items.SalarySum = 0
		
	Context.Items.IdSum+=Row.Id
	Context.Items.SalarySum+=Row.Salary
	RemoveRow()
	
	OnComplete:
		SendRow( Row(
			IdSum: Context.Items.IdSum, 
			SalarySum: Context.Items.SalarySum
			) )&lt;/pre&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt; So, basically we have an initialization section, processing, and when all the processing is done, you can send new rows downward in the pipeline.&lt;/p&gt;</description><link>http://ayende.com/2676/rhino-etl-aggregates?Key=38e0e8df-01ee-41e1-b64c-4ace45fbfbd6</link><guid>http://ayende.com/2676/rhino-etl-aggregates?Key=38e0e8df-01ee-41e1-b64c-4ace45fbfbd6</guid><pubDate>Sat, 04 Aug 2007 09:44:44 GMT</pubDate></item></channel></rss>