<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>Will Smith</title>
        <link>http://geekswithblogs.net/WillSmith/Default.aspx</link>
        <description>The Blog in Black</description>
        <language>en-US</language>
        <copyright>Will Smith</copyright>
        <managingEditor>CamperWill@comcast.net</managingEditor>
        <generator>Subtext Version 0.0.0.0</generator>
        <creativeCommons:license>http://creativecommons.org/licenses/by-nc-sa/3.0/us/</creativeCommons:license>
        <image>
            <title>Will Smith</title>
            <url>http://geekswithblogs.net/images/RSS2Image.gif</url>
            <link>http://geekswithblogs.net/WillSmith/Default.aspx</link>
            <width>77</width>
            <height>60</height>
        </image>
        <item>
            <title>Creating a comma separated list from IEnumerable&amp;lt;T&amp;gt; &amp;hellip; again</title>
            <link>http://geekswithblogs.net/WillSmith/archive/2009/11/19/creating-a-comma-separated-list-from-ienumerablelttgt-hellip-again.aspx</link>
            <description>&lt;p&gt;So in response to some comments on my &lt;a href="http://geekswithblogs.net/WillSmith/archive/2008/06/26/creating-a-comma-separated-list-from-ienumerablet.aspx"&gt;original post&lt;/a&gt; on this topic, I started playing around with some other ideas.  I figured it would be cleaner to post code here, rather than the comments.&lt;/p&gt;  &lt;p&gt;How many variations on the theme can we really have?&lt;/p&gt;  &lt;p&gt;As suggested in the comments on the previous post:&lt;/p&gt;  &lt;div id="codeSnippetWrapper" class="csharpcode-wrapper"&gt;   &lt;div id="codeSnippet" class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; string Join1&amp;lt;T&amp;gt;( this IEnumerable&amp;lt;T&amp;gt; items, string delimiter, Func&amp;lt;T,string&amp;gt; converter )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt;     &lt;span class="kwrd"&gt;return&lt;/span&gt; string.&lt;span class="kwrd"&gt;Join&lt;/span&gt;( delimiter,&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum4" class="lnum"&gt;   4:&lt;/span&gt;                         items&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum5" class="lnum"&gt;   5:&lt;/span&gt;                             .&lt;span class="kwrd"&gt;Select&lt;/span&gt;( converter )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum6" class="lnum"&gt;   6:&lt;/span&gt;                             .&lt;span class="kwrd"&gt;Where&lt;/span&gt;( s =&amp;gt; !string.IsNullOrEmpty( s ) )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum7" class="lnum"&gt;   7:&lt;/span&gt;                             .ToArray() );            &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum8" class="lnum"&gt;   8:&lt;/span&gt; }&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Using Aggregate Linq extension:&lt;/p&gt;

&lt;div id="codeSnippetWrapper" class="csharpcode-wrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; string Join2&amp;lt;T&amp;gt;( this IEnumerable&amp;lt;T&amp;gt; items, string delimiter, Func&amp;lt;T, string&amp;gt; converter )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt;     &lt;span class="kwrd"&gt;return&lt;/span&gt; items&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum4" class="lnum"&gt;   4:&lt;/span&gt;         .&lt;span class="kwrd"&gt;Aggregate&lt;/span&gt;( string.Empty,&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum5" class="lnum"&gt;   5:&lt;/span&gt;                     ( agg, &lt;span class="kwrd"&gt;next&lt;/span&gt; ) =&amp;gt;&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum6" class="lnum"&gt;   6:&lt;/span&gt;                         {&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum7" class="lnum"&gt;   7:&lt;/span&gt;                             var sNext = converter( &lt;span class="kwrd"&gt;next&lt;/span&gt; );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum8" class="lnum"&gt;   8:&lt;/span&gt;  &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum9" class="lnum"&gt;   9:&lt;/span&gt;                             &lt;span class="kwrd"&gt;return&lt;/span&gt; string.IsNullOrEmpty( sNext )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum10" class="lnum"&gt;  10:&lt;/span&gt;                                        ? agg&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum11" class="lnum"&gt;  11:&lt;/span&gt;                                        : agg + delimiter + sNext;&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum12" class="lnum"&gt;  12:&lt;/span&gt;                         } );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum13" class="lnum"&gt;  13:&lt;/span&gt; }&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Aggregate again:&lt;/p&gt;

&lt;div id="codeSnippetWrapper" class="csharpcode-wrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; string Join3&amp;lt;T&amp;gt;( this IEnumerable&amp;lt;T&amp;gt; items, string delimiter, Func&amp;lt;T, string&amp;gt; converter )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt;     &lt;span class="kwrd"&gt;return&lt;/span&gt; items&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum4" class="lnum"&gt;   4:&lt;/span&gt;         .&lt;span class="kwrd"&gt;Select&lt;/span&gt;( converter )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum5" class="lnum"&gt;   5:&lt;/span&gt;         .&lt;span class="kwrd"&gt;Aggregate&lt;/span&gt;( ( agg, sNext ) =&amp;gt; string.IsNullOrEmpty( sNext )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum6" class="lnum"&gt;   6:&lt;/span&gt;                                           ? agg&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum7" class="lnum"&gt;   7:&lt;/span&gt;                                           : agg + delimiter + sNext );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum8" class="lnum"&gt;   8:&lt;/span&gt; }&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;And again:&lt;/p&gt;

&lt;div id="codeSnippetWrapper" class="csharpcode-wrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; string Join4&amp;lt;T&amp;gt;( this IEnumerable&amp;lt;T&amp;gt; items, string delimiter, Func&amp;lt;T, string&amp;gt; converter )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt;     &lt;span class="kwrd"&gt;return&lt;/span&gt; items&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum4" class="lnum"&gt;   4:&lt;/span&gt;         .&lt;span class="kwrd"&gt;Select&lt;/span&gt;( converter )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum5" class="lnum"&gt;   5:&lt;/span&gt;         .&lt;span class="kwrd"&gt;Where&lt;/span&gt;( s =&amp;gt; !string.IsNullOrEmpty( s ) )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum6" class="lnum"&gt;   6:&lt;/span&gt;         .&lt;span class="kwrd"&gt;Aggregate&lt;/span&gt;( ( agg, &lt;span class="kwrd"&gt;next&lt;/span&gt; ) =&amp;gt; agg + delimiter + &lt;span class="kwrd"&gt;next&lt;/span&gt; );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum7" class="lnum"&gt;   7:&lt;/span&gt; }&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;In the comments for my previous post, there was a decent discussion about the performance of string aggregation, and the suggestion of using StringBuilder instead.  I’m not too concerned about it.  I’m not dealing with large data sets.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:247a46c1-6d34-43a1-83a5-2efab6f16a05" class="wlWriterEditableSmartContent"&gt;Tags: &lt;a href="http://technorati.com/tags/.Net" rel="tag"&gt;.Net&lt;/a&gt;, &lt;a href="http://technorati.com/tags/C%23" rel="tag"&gt;C#&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=136422"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=136422" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/WillSmith/aggbug/136422.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Will Smith</dc:creator>
            <guid>http://geekswithblogs.net/WillSmith/archive/2009/11/19/creating-a-comma-separated-list-from-ienumerablelttgt-hellip-again.aspx</guid>
            <pubDate>Thu, 19 Nov 2009 22:02:16 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/WillSmith/comments/136422.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/WillSmith/archive/2009/11/19/creating-a-comma-separated-list-from-ienumerablelttgt-hellip-again.aspx#feedback</comments>
            <wfw:commentRss>http://geekswithblogs.net/WillSmith/comments/commentRss/136422.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/WillSmith/services/trackbacks/136422.aspx</trackback:ping>
        </item>
        <item>
            <title>Oracle Update with Join &amp;ndash; Revisited</title>
            <link>http://geekswithblogs.net/WillSmith/archive/2009/10/22/oracle-update-with-join-ndash-revisited.aspx</link>
            <description>&lt;p&gt;I’ve had a lot of feedback on my &lt;a href="http://geekswithblogs.net/WillSmith/archive/2008/06/18/oracle-update-with-join-again.aspx"&gt;Oracle Update with Join&lt;/a&gt; post.  The most common problem people have encountered with this approach is the dreaded “SQL Error: ORA-01779: cannot modify a column which maps to a non key-preserved table”.  Tom Kyte has a detailed explanation of this at &lt;a title="Ask Tom" href="http://asktom.oracle.com/pls/asktom/f?p=100:11:327570042321771::::P11_QUESTION_ID:273215737113"&gt;Ask Tom&lt;/a&gt;.  However, I thought I would take a moment to address my example scenario.&lt;/p&gt;  &lt;p&gt;There are actually a couple of ways to update based on data joined from multiple tables.  The first is outlined in my first post.  But, let’s dig a little deeper into that approach.  The “key-preserved” problem comes from joining to a table without some sort of unique lookup into that table.  So, the result of the join would not guarantee zero or one entries for each row I want to update.&lt;/p&gt;  &lt;p&gt;I’m going to add a little to my test scenario.  Instead of setting the bonus to a constant value, I am going to set it to a value from a bonus rates table.  Let’s suppose we have:&lt;/p&gt;  &lt;div id="codeSnippetWrapper" class="csharpcode-wrapper"&gt;   &lt;div id="codeSnippet" class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;drop&lt;/span&gt; &lt;span class="kwrd"&gt;table&lt;/span&gt; employees &lt;span class="kwrd"&gt;cascade&lt;/span&gt; &lt;span class="kwrd"&gt;constraints&lt;/span&gt;;&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt; &lt;span class="kwrd"&gt;drop&lt;/span&gt; &lt;span class="kwrd"&gt;table&lt;/span&gt; employee_bonus &lt;span class="kwrd"&gt;cascade&lt;/span&gt; &lt;span class="kwrd"&gt;constraints&lt;/span&gt;;&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt; &lt;span class="kwrd"&gt;drop&lt;/span&gt; &lt;span class="kwrd"&gt;table&lt;/span&gt; bonus_rates &lt;span class="kwrd"&gt;cascade&lt;/span&gt; &lt;span class="kwrd"&gt;constraints&lt;/span&gt;;&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum4" class="lnum"&gt;   4:&lt;/span&gt;  &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum5" class="lnum"&gt;   5:&lt;/span&gt; &lt;span class="kwrd"&gt;create&lt;/span&gt; &lt;span class="kwrd"&gt;table&lt;/span&gt; employees&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum6" class="lnum"&gt;   6:&lt;/span&gt; ( employee_id &lt;span class="kwrd"&gt;int&lt;/span&gt; &lt;span class="kwrd"&gt;primary&lt;/span&gt; &lt;span class="kwrd"&gt;key&lt;/span&gt;,&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum7" class="lnum"&gt;   7:&lt;/span&gt;   bonus_eligible &lt;span class="kwrd"&gt;char&lt;/span&gt;(1),&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum8" class="lnum"&gt;   8:&lt;/span&gt;   rate_id &lt;span class="kwrd"&gt;int&lt;/span&gt;&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum9" class="lnum"&gt;   9:&lt;/span&gt; )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum10" class="lnum"&gt;  10:&lt;/span&gt; /&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum11" class="lnum"&gt;  11:&lt;/span&gt;  &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum12" class="lnum"&gt;  12:&lt;/span&gt; &lt;span class="kwrd"&gt;create&lt;/span&gt; &lt;span class="kwrd"&gt;table&lt;/span&gt; employee_bonus&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum13" class="lnum"&gt;  13:&lt;/span&gt; ( bonus_id &lt;span class="kwrd"&gt;int&lt;/span&gt; &lt;span class="kwrd"&gt;primary&lt;/span&gt; &lt;span class="kwrd"&gt;key&lt;/span&gt;,&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum14" class="lnum"&gt;  14:&lt;/span&gt;   employee_id &lt;span class="kwrd"&gt;int&lt;/span&gt;,&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum15" class="lnum"&gt;  15:&lt;/span&gt;   bonus_date &lt;span class="kwrd"&gt;date&lt;/span&gt;,&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum16" class="lnum"&gt;  16:&lt;/span&gt;   bonus number&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum17" class="lnum"&gt;  17:&lt;/span&gt; )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum18" class="lnum"&gt;  18:&lt;/span&gt; /&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum19" class="lnum"&gt;  19:&lt;/span&gt;  &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum20" class="lnum"&gt;  20:&lt;/span&gt; &lt;span class="kwrd"&gt;create&lt;/span&gt; &lt;span class="kwrd"&gt;table&lt;/span&gt; bonus_rates&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum21" class="lnum"&gt;  21:&lt;/span&gt; ( rate_id &lt;span class="kwrd"&gt;int&lt;/span&gt; &lt;span class="kwrd"&gt;primary&lt;/span&gt; &lt;span class="kwrd"&gt;key&lt;/span&gt;,&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum22" class="lnum"&gt;  22:&lt;/span&gt;   min_bonus number,&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum23" class="lnum"&gt;  23:&lt;/span&gt;   max_bonus number&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum24" class="lnum"&gt;  24:&lt;/span&gt; )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum25" class="lnum"&gt;  25:&lt;/span&gt; /&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum26" class="lnum"&gt;  26:&lt;/span&gt;  &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum27" class="lnum"&gt;  27:&lt;/span&gt; insert &lt;span class="kwrd"&gt;into&lt;/span&gt; employees &lt;span class="kwrd"&gt;values&lt;/span&gt; ( 100, &lt;span class="str"&gt;'N'&lt;/span&gt;, 101 );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum28" class="lnum"&gt;  28:&lt;/span&gt; insert &lt;span class="kwrd"&gt;into&lt;/span&gt; employees &lt;span class="kwrd"&gt;values&lt;/span&gt; ( 200, &lt;span class="str"&gt;'Y'&lt;/span&gt;, 102 );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum29" class="lnum"&gt;  29:&lt;/span&gt; insert &lt;span class="kwrd"&gt;into&lt;/span&gt; employee_bonus &lt;span class="kwrd"&gt;values&lt;/span&gt; ( 101, 100, &lt;span class="str"&gt;'15-DEC-09'&lt;/span&gt;, 0 );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum30" class="lnum"&gt;  30:&lt;/span&gt; insert &lt;span class="kwrd"&gt;into&lt;/span&gt; employee_bonus &lt;span class="kwrd"&gt;values&lt;/span&gt; ( 102, 200, &lt;span class="str"&gt;'15-DEC-09'&lt;/span&gt;, 2000 );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum31" class="lnum"&gt;  31:&lt;/span&gt; insert &lt;span class="kwrd"&gt;into&lt;/span&gt; bonus_rates &lt;span class="kwrd"&gt;values&lt;/span&gt; ( 101, 0, 0 );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum32" class="lnum"&gt;  32:&lt;/span&gt; insert &lt;span class="kwrd"&gt;into&lt;/span&gt; bonus_rates &lt;span class="kwrd"&gt;values&lt;/span&gt; ( 102, 500, 2000 );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum33" class="lnum"&gt;  33:&lt;/span&gt; &lt;span class="kwrd"&gt;commit&lt;/span&gt;;&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Now let’s update the employee_bonus table by copying the minimum bonus from the employees table:&lt;/p&gt;

&lt;div id="codeSnippetWrapper" class="csharpcode-wrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;update&lt;/span&gt; (&lt;span class="kwrd"&gt;select&lt;/span&gt; b.bonus &lt;span class="kwrd"&gt;as&lt;/span&gt; bonus,&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt;                br.min_bonus &lt;span class="kwrd"&gt;as&lt;/span&gt; new_bonus&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt;           &lt;span class="kwrd"&gt;from&lt;/span&gt; employee_bonus b&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum4" class="lnum"&gt;   4:&lt;/span&gt;          &lt;span class="kwrd"&gt;inner&lt;/span&gt; &lt;span class="kwrd"&gt;join&lt;/span&gt; employees e &lt;span class="kwrd"&gt;on&lt;/span&gt; b.employee_id = e.employee_id&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum5" class="lnum"&gt;   5:&lt;/span&gt;          &lt;span class="kwrd"&gt;inner&lt;/span&gt; &lt;span class="kwrd"&gt;join&lt;/span&gt; bonus_rates br &lt;span class="kwrd"&gt;on&lt;/span&gt; e.rate_id = br.rate_id&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum6" class="lnum"&gt;   6:&lt;/span&gt;          &lt;span class="kwrd"&gt;where&lt;/span&gt; e.bonus_eligible = &lt;span class="str"&gt;'Y'&lt;/span&gt; ) t&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum7" class="lnum"&gt;   7:&lt;/span&gt; &lt;span class="kwrd"&gt;set&lt;/span&gt; t.bonus = t.new_bonus&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;The query runs just fine and updates the employee_bonus record for the "eligible” employee.  The reason it works is because to update the employee_bonus table, I am looking up the employee info based on a unique index (primary key in this case), and Oracle is certain that only one employee record will be returned given the employee_bonus record.&lt;/p&gt;

&lt;p&gt;Just for grins, here is the other approach for updating with a join.  Keep in mind, though that the approach above should be your first try.&lt;/p&gt;

&lt;div id="codeSnippetWrapper" class="csharpcode-wrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;update&lt;/span&gt; employee_bonus b&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt;    &lt;span class="kwrd"&gt;set&lt;/span&gt; b.bonus = (&lt;span class="kwrd"&gt;select&lt;/span&gt; br.min_bonus&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt;                     &lt;span class="kwrd"&gt;from&lt;/span&gt; employees e&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum4" class="lnum"&gt;   4:&lt;/span&gt;                    &lt;span class="kwrd"&gt;inner&lt;/span&gt; &lt;span class="kwrd"&gt;join&lt;/span&gt; bonus_rates br &lt;span class="kwrd"&gt;on&lt;/span&gt; e.rate_id = br.rate_id&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum5" class="lnum"&gt;   5:&lt;/span&gt;                    &lt;span class="kwrd"&gt;where&lt;/span&gt; b.employee_id = e.employee_id&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum6" class="lnum"&gt;   6:&lt;/span&gt;                      &lt;span class="kwrd"&gt;and&lt;/span&gt; e.bonus_eligible = &lt;span class="str"&gt;'Y'&lt;/span&gt; )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum7" class="lnum"&gt;   7:&lt;/span&gt; &lt;span class="kwrd"&gt;where&lt;/span&gt; &lt;span class="kwrd"&gt;exists&lt;/span&gt; (&lt;span class="kwrd"&gt;select&lt;/span&gt; e.employee_id&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum8" class="lnum"&gt;   8:&lt;/span&gt;                 &lt;span class="kwrd"&gt;from&lt;/span&gt; employees e &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum9" class="lnum"&gt;   9:&lt;/span&gt;                &lt;span class="kwrd"&gt;where&lt;/span&gt; b.employee_id = e.employee_id&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum10" class="lnum"&gt;  10:&lt;/span&gt;                  &lt;span class="kwrd"&gt;and&lt;/span&gt; e.bonus_eligible = &lt;span class="str"&gt;'Y'&lt;/span&gt; )&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;By the way, we are using a correlated sub query in this case.  For a correlated query, any join to the outer table, must be done in the where clause and not within the “inner join … on” syntax.  Otherwise you will get an “ORA-00904 … invalid identifier”.&lt;/p&gt;

&lt;p&gt;Okay, so that’s it for a scenario that works fine because the “lookup” table (employees) is key-preserved.  So what about a scenario where the lookup table is not key preserved?  Let’s suppose the employee table has a bonus field that grabs the bonus from the employee_bonus table.  (Please keep in mind that this whole scenario is totally contrived, so I may be doing some things here that I wouldn’t normally.)&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;First, we need to add the bonus column:&lt;/p&gt;

&lt;div id="codeSnippetWrapper" class="csharpcode-wrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;drop&lt;/span&gt; &lt;span class="kwrd"&gt;table&lt;/span&gt; employees &lt;span class="kwrd"&gt;cascade&lt;/span&gt; &lt;span class="kwrd"&gt;constraints&lt;/span&gt;;&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt; &lt;span class="kwrd"&gt;create&lt;/span&gt; &lt;span class="kwrd"&gt;table&lt;/span&gt; employees&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt; ( employee_id &lt;span class="kwrd"&gt;int&lt;/span&gt; &lt;span class="kwrd"&gt;primary&lt;/span&gt; &lt;span class="kwrd"&gt;key&lt;/span&gt;,&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum4" class="lnum"&gt;   4:&lt;/span&gt;   bonus_eligible &lt;span class="kwrd"&gt;char&lt;/span&gt;(1),&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum5" class="lnum"&gt;   5:&lt;/span&gt;   rate_id &lt;span class="kwrd"&gt;int&lt;/span&gt;,&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum6" class="lnum"&gt;   6:&lt;/span&gt;   bonus number&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum7" class="lnum"&gt;   7:&lt;/span&gt; )&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum8" class="lnum"&gt;   8:&lt;/span&gt; /&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum9" class="lnum"&gt;   9:&lt;/span&gt;  &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum10" class="lnum"&gt;  10:&lt;/span&gt; insert &lt;span class="kwrd"&gt;into&lt;/span&gt; employees &lt;span class="kwrd"&gt;values&lt;/span&gt; ( 100, &lt;span class="str"&gt;'N'&lt;/span&gt;, 101, &lt;span class="kwrd"&gt;null&lt;/span&gt; );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum11" class="lnum"&gt;  11:&lt;/span&gt; insert &lt;span class="kwrd"&gt;into&lt;/span&gt; employees &lt;span class="kwrd"&gt;values&lt;/span&gt; ( 200, &lt;span class="str"&gt;'Y'&lt;/span&gt;, 102, &lt;span class="kwrd"&gt;null&lt;/span&gt; );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum12" class="lnum"&gt;  12:&lt;/span&gt;  &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum13" class="lnum"&gt;  13:&lt;/span&gt; &lt;span class="kwrd"&gt;commit&lt;/span&gt;;&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Now, let’s try to update the employees.bonus from the employee_bonus table:&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div id="codeSnippetWrapper" class="csharpcode-wrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;update&lt;/span&gt; (&lt;span class="kwrd"&gt;select&lt;/span&gt; e.bonus,&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt;                b.bonus &lt;span class="kwrd"&gt;as&lt;/span&gt; new_bonus&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt;           &lt;span class="kwrd"&gt;from&lt;/span&gt; employees e&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum4" class="lnum"&gt;   4:&lt;/span&gt;          &lt;span class="kwrd"&gt;inner&lt;/span&gt; &lt;span class="kwrd"&gt;join&lt;/span&gt; employee_bonus b &lt;span class="kwrd"&gt;on&lt;/span&gt; b.employee_id = e.employee_id) t&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum5" class="lnum"&gt;   5:&lt;/span&gt;    &lt;span class="kwrd"&gt;set&lt;/span&gt; t.bonus = new_bonus&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Oops, that didn’t work:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geekswithblogs.net/images/geekswithblogs_net/WillSmith/WindowsLiveWriter/OracleUpdatewithJoinRevisited_C7A4/image_2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://geekswithblogs.net/images/geekswithblogs_net/WillSmith/WindowsLiveWriter/OracleUpdatewithJoinRevisited_C7A4/image_thumb.png" width="448" height="129" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Again, the problem is that there is no unique constraint on the lookup table (in this case employee_bonus) by the key we are joining to (employee_id).  So we could resolve the error by adding a unique constraint to the employee_id column.  However, there could be any number of reasons why we can’t.  Perhaps it is a “legacy” table/database that we have no control over.  Perhaps, there really is no guarantee that there would be only one entry per employee.  The bonus_date certainly seems to imply that.&lt;/p&gt;

&lt;p&gt;Let’s take a look at the second approach:&lt;/p&gt;

&lt;div id="codeSnippetWrapper" class="csharpcode-wrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;update&lt;/span&gt; employees e&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt;    &lt;span class="kwrd"&gt;set&lt;/span&gt; e.bonus = (&lt;span class="kwrd"&gt;select&lt;/span&gt; b.bonus&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt;                     &lt;span class="kwrd"&gt;from&lt;/span&gt; employee_bonus b&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum4" class="lnum"&gt;   4:&lt;/span&gt;                    &lt;span class="kwrd"&gt;where&lt;/span&gt; b.employee_id = e.employee_id)&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum5" class="lnum"&gt;   5:&lt;/span&gt; &lt;span class="kwrd"&gt;where&lt;/span&gt; &lt;span class="kwrd"&gt;exists&lt;/span&gt; (&lt;span class="kwrd"&gt;select&lt;/span&gt; b.employee_id&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum6" class="lnum"&gt;   6:&lt;/span&gt;                 &lt;span class="kwrd"&gt;from&lt;/span&gt; employee_bonus b&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum7" class="lnum"&gt;   7:&lt;/span&gt;                &lt;span class="kwrd"&gt;where&lt;/span&gt; b.employee_id = e.employee_id)&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Actually this approach works fine with our given data.  However, if we had more data and there were an employee with more than one bonus, the query would fail.  Let’s see…&lt;/p&gt;

&lt;div id="codeSnippetWrapper" class="csharpcode-wrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; insert &lt;span class="kwrd"&gt;into&lt;/span&gt; employee_bonus &lt;span class="kwrd"&gt;values&lt;/span&gt; ( 103, 200, &lt;span class="str"&gt;'15-DEC-08'&lt;/span&gt;, 1000 );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt;  &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt; &lt;span class="kwrd"&gt;commit&lt;/span&gt;;&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;and now if we run the same update statement:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://geekswithblogs.net/images/geekswithblogs_net/WillSmith/WindowsLiveWriter/OracleUpdatewithJoinRevisited_C7A4/image_4.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://geekswithblogs.net/images/geekswithblogs_net/WillSmith/WindowsLiveWriter/OracleUpdatewithJoinRevisited_C7A4/image_thumb_1.png" width="363" height="129" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I believe that older versions of Oracle would not produce this error, they would simply update the employee record twice, yielding unpredictable results.  I’m using 10g in my tests.&lt;/p&gt;

&lt;p&gt;Let’s review what we’ve seen so far.  Basically, no matter how I cut it, the update I am attempting is flawed.  I’m trying to update one table data from another that is not guaranteed to be unique.  Maybe we “know” it always will be unique, but it would be best if we go ahead and add the necessary constraint.  In my scenario, there is something obviously wrong with my logic.  Perhaps, I was trying to get the total bonus or the max bonus.  Then, updating the employee table might make more sense.  But even updating from an aggregate sub query has its quirks.&lt;/p&gt;

&lt;p&gt;Another scenario you may encounter is updating based on a join to a view.  It is highly unlikely that you will be able to “guarantee” (from Oracle’s perspective) uniqueness from the view.  The second approach is probably your only option in this case.&lt;/p&gt;

&lt;p&gt;Anyway, I hope that I’ve gone into enough detail to help those who have been having trouble implementing the approach from my original post.  I’ll update this one if other common scenarios pop up.&lt;/p&gt;

&lt;p&gt;Happy updating.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:92ef36c6-e033-47bf-bf97-c808aa8fd9fa" class="wlWriterEditableSmartContent"&gt;Tags: &lt;a href="http://technorati.com/tags/Oracle" rel="tag"&gt;Oracle&lt;/a&gt;, &lt;a href="http://technorati.com/tags/SQL" rel="tag"&gt;SQL&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=135661"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=135661" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/WillSmith/aggbug/135661.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Will Smith</dc:creator>
            <guid>http://geekswithblogs.net/WillSmith/archive/2009/10/22/oracle-update-with-join-ndash-revisited.aspx</guid>
            <pubDate>Thu, 22 Oct 2009 21:27:35 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/WillSmith/comments/135661.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/WillSmith/archive/2009/10/22/oracle-update-with-join-ndash-revisited.aspx#feedback</comments>
            <slash:comments>4</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/WillSmith/comments/commentRss/135661.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/WillSmith/services/trackbacks/135661.aspx</trackback:ping>
        </item>
        <item>
            <title>Company Website</title>
            <link>http://geekswithblogs.net/WillSmith/archive/2009/10/13/company-website.aspx</link>
            <description>&lt;p&gt;I’ve been spending the last couple of weeks working on our company website.  We are trying to get more exposure to grow our consulting presence.  Visit our site (&lt;a href="http://www.xcis-software.com"&gt;www.xcis-software.com&lt;/a&gt;) and let me know what you think.&lt;/p&gt;  &lt;p&gt;Also, if you are in the Houston, TX area and are in need of experienced consultants, we would be glad to hear from you.  Check out the site for more details.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:4656ef11-7353-46f0-8a04-2b1317a8015d" class="wlWriterEditableSmartContent"&gt;Tags: &lt;a href="http://technorati.com/tags/Corporate" rel="tag"&gt;Corporate&lt;/a&gt;, &lt;a href="http://technorati.com/tags/Consulting" rel="tag"&gt;Consulting&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=135435"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=135435" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/WillSmith/aggbug/135435.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Will Smith</dc:creator>
            <guid>http://geekswithblogs.net/WillSmith/archive/2009/10/13/company-website.aspx</guid>
            <pubDate>Tue, 13 Oct 2009 13:42:40 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/WillSmith/comments/135435.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/WillSmith/archive/2009/10/13/company-website.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/WillSmith/comments/commentRss/135435.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/WillSmith/services/trackbacks/135435.aspx</trackback:ping>
        </item>
        <item>
            <title>Don&amp;rsquo;t Be Lazy: Test First</title>
            <link>http://geekswithblogs.net/WillSmith/archive/2009/09/15/donrsquot-be-lazy-test-first.aspx</link>
            <description>&lt;p&gt;Okay, so recently I was working on a new suggestion for my client.  It was a fairly simple request; create a snapshot of data to be used in monthly calculations, with the option to regenerate the snapshot at a later time.  The snapshot was easy.  I thought regenerating the snapshot would be easy too, but somehow I found a way to make it hard.&lt;/p&gt;  &lt;p&gt;The first mistake I made was not writing a test first.  Really this had a lot to do with laziness.  The data that I am capturing is only available via a view into a proprietary database.  Somehow, I needed to figure out how to modify the data behind the view.  It seemed really hard, so I skipped it.&lt;/p&gt;  &lt;p&gt;That decision came back to bite me.  I submitted the changes to the customer and soon they reported that they weren’t working.  Perhaps there was a little more than laziness here (perhaps arrogance).  I manually tested my changes, but I didn’t cover every aspect.  As it turns out, the snapshot was being updated correctly, but, the monthly calculations weren’t getting updated.&lt;/p&gt;  &lt;p&gt;So now that I got a feature returned as a failure, I decided I better write that test.  In fact, following TDD principles, I knew I should write a test that would fail due to the reported defect.  I started on the test and hit a roadblock and was about to give up on it again.  I mean, this testing stuff is hard!&lt;/p&gt;  &lt;p&gt;I chatted with a coworker asking his advice on how to test the data change behind the view.  He provided a simple and elegant solution.  We set up a test data script that would create a “test” table that duplicates the structure of the view.  Then we simply redirected the synonym from the view to the test table.  Now we essentially have a fake view.  And since it is a table, we can manipulate the data to our hearts content.&lt;/p&gt;  &lt;p&gt;From this point I was able to continue writing my test.  Everything looked good.  I was sure to test all of the aspects of the new requirements that I could think of.  When I was done, I ran the tests and verified the defect.&lt;/p&gt;  &lt;p&gt;Finally, I could fix the problem.  I figured out the problem and was able to fix it fairly easily.  Well, not so fast.  My test was still failing!  I spent hours on the issue.  I knew that the fix was correct.  I tried all kinds of debugging attempts.  I even changed to code to force it to be wrong for a different reason.  Everything seemed to be fine, except my test was still failing.  I was beginning to think that there was a bug in the test itself.&lt;/p&gt;  &lt;p&gt;As it turns out, there was more than one problem with the original code.  The second issue was that I had an update statement that performed a join to the snapshot data, but was missing a critical condition in the join.  To uniquely identify the snapshot data, I needed to join to two fields and I forgot one.  So, the update was actually executing multiple times and the last time wasn’t the one I was expecting.&lt;/p&gt;  &lt;p&gt;Had I persisted in my laziness and simply added the fix and sent it to the customer, I’d be embarrassed yet again.  But this time, the test saved me.  How many times do I have to learn this lesson?&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:54a9b993-5d19-40e6-a046-f9944c0c5b96" class="wlWriterEditableSmartContent"&gt;Tags: &lt;a href="http://technorati.com/tags/TDD" rel="tag"&gt;TDD&lt;/a&gt;, &lt;a href="http://technorati.com/tags/Testing" rel="tag"&gt;Testing&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=134827"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=134827" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/WillSmith/aggbug/134827.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Will Smith</dc:creator>
            <guid>http://geekswithblogs.net/WillSmith/archive/2009/09/15/donrsquot-be-lazy-test-first.aspx</guid>
            <pubDate>Tue, 15 Sep 2009 16:05:31 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/WillSmith/comments/134827.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/WillSmith/archive/2009/09/15/donrsquot-be-lazy-test-first.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/WillSmith/comments/commentRss/134827.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/WillSmith/services/trackbacks/134827.aspx</trackback:ping>
        </item>
        <item>
            <title>Rhino Mocks: Meaningful failure messages on expectations</title>
            <link>http://geekswithblogs.net/WillSmith/archive/2009/09/09/rhino-mocks-meaningful-failure-messages-on-expectations.aspx</link>
            <description>&lt;p&gt;Recently, &lt;a href="http://ayende.com/blog/"&gt;Ayende Rahien&lt;/a&gt; (Oren Eini) blogged about &lt;a href="http://ayende.com/Blog/archive/2009/09/03/planning-for-rhino-mocks-4.0.aspx"&gt;Planning for Rhino Mocks 4.0&lt;/a&gt;.  He’s calling for all of us to contribute our ideas on how to improve Rhino Mocks.  He set up a &lt;a href="http://nhprof.uservoice.com/pages/28152-rhino-mocks-4-0"&gt;forum&lt;/a&gt; where we can submit our ideas and vote on them as well.&lt;/p&gt;  &lt;p&gt;This lead me to review some of my more complex tests involving &lt;a href="http://www.ayende.com/projects/rhino-mocks.aspx"&gt;Rhino Mocks&lt;/a&gt; (I’m on version 3.6).  Were there mocking difficulties that I could propose a solution to?  Let’s find out… &lt;/p&gt;  &lt;p&gt;A frequent pattern in my tests is verifying that my controllers pull properties from the views correctly.  The controller would construct a new entity object, providing the values from various view properties.  The entity object then would be passed to the data provider to save the entity.&lt;/p&gt;  &lt;p&gt;The first attempt to test that a particular property was passed through correctly went something like this:&lt;/p&gt;  &lt;div id="codeSnippetWrapper"&gt;   &lt;div id="codeSnippet" class="csharpcode"&gt;     &lt;div id="codeSnippetWrapper"&gt;       &lt;div id="codeSnippet" class="csharpcode"&gt;         &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; _model.AssertWasCalled( m =&amp;gt; m.Add&amp;lt;Job&amp;gt;( &lt;span class="kwrd"&gt;null&lt;/span&gt; ),&lt;/pre&gt;
&lt;!--CRLF--&gt;

        &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt;                         o =&amp;gt; o.Constraints(&lt;/pre&gt;
&lt;!--CRLF--&gt;

        &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt;                                  Is.Matching&amp;lt;Job&amp;gt;( j =&amp;gt; j.Account.Id == _accountId ) ) );&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Fairly straight forward, but the failure message doesn’t provide much information:&lt;/p&gt;

&lt;div id="codeSnippetWrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; failed: Rhino.Mocks.Exceptions.ExpectationViolationException : IMyModel.Add&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Job&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;(Predicate (TestClass.&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Test&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;b__12(obj);)); Expected #1, Actual #0.&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Marginally better is the use of the Arg helper class:&lt;/p&gt;

&lt;div id="codeSnippetWrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; var arg = Arg&amp;lt;Job&amp;gt;.Matches( j =&amp;gt; j.Account.Id == _accountId );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt; _model.AssertWasCalled( m =&amp;gt; m.Add&amp;lt;Job&amp;gt;( arg ) );&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;…with this failure message:&lt;/p&gt;

&lt;div id="codeSnippetWrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; failed: Rhino.Mocks.Exceptions.ExpectationViolationException : IMyModel.Add&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Job&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;(j =&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; (j.Account.Id = (value(TestClass)._accountId ))); Expected #1, Actual #0.&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;This gave me a better idea as to the check that was failing (honestly that is what my test method name is for), but without helpful details.&lt;/p&gt;

&lt;p&gt;So I changed the original approach slightly by adding an assertion within the constraint delegate, like so:&lt;/p&gt;

&lt;div id="codeSnippetWrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; _model.AssertWasCalled( m =&amp;gt; m.Add&amp;lt;Job&amp;gt;( &lt;span class="kwrd"&gt;null&lt;/span&gt; ),&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt;                         o =&amp;gt; o.Constraints(&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt;                                  Is.Matching&amp;lt;Job&amp;gt;( j =&amp;gt;&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum4" class="lnum"&gt;   4:&lt;/span&gt;                                      {&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum5" class="lnum"&gt;   5:&lt;/span&gt;                                          j.Account.Id.ShouldEqual( _accountId );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum6" class="lnum"&gt;   6:&lt;/span&gt;                                          &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum7" class="lnum"&gt;   7:&lt;/span&gt;                                      } ) ) );&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Now I am using an explicit “ShouldEqual”, and I get:&lt;/p&gt;

&lt;div id="codeSnippetWrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; failed: &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt;   Expected: 143&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt;   But was:  142&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;But, that “return true” is just ugly, and there’s a lot going on just to test that the account id was passed through correctly.&lt;/p&gt;

&lt;p&gt;Then I discovered the Rhino Mock extension method GetArgumentsForCallsMadeOn:&lt;/p&gt;

&lt;div id="codeSnippetWrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; var arg = (Job)(_model.GetArgumentsForCallsMadeOn( m =&amp;gt; m.Add&amp;lt;Job&amp;gt;( &lt;span class="kwrd"&gt;null&lt;/span&gt; ) )[0][0]);&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt; arg.Account.Id.ShouldEqual( _accountId );&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;After all, I didn’t really want to assert that the Add method was called.  I wanted to assert that the method was called with the correct parameters, but, with each parameter under a different test:&lt;/p&gt;

&lt;div id="codeSnippetWrapper" class="csharpcode-wrapper"&gt;
  &lt;div id="codeSnippet" class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span id="lnum1" class="lnum"&gt;   1:&lt;/span&gt; [Specification]&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum2" class="lnum"&gt;   2:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; the_job_should_be_add_to_the_queue()&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum3" class="lnum"&gt;   3:&lt;/span&gt; {&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum4" class="lnum"&gt;   4:&lt;/span&gt;     _model.AssertWasCalled( m =&amp;gt; m.Add&amp;lt;Job&amp;gt;( Arg&amp;lt;Job&amp;gt;.Is.Anything ) );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum5" class="lnum"&gt;   5:&lt;/span&gt; }&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum6" class="lnum"&gt;   6:&lt;/span&gt;  &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum7" class="lnum"&gt;   7:&lt;/span&gt; [Specification]&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum8" class="lnum"&gt;   8:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; the_selected_account_id_should_be_used()&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum9" class="lnum"&gt;   9:&lt;/span&gt; {&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum10" class="lnum"&gt;  10:&lt;/span&gt;     var jobArg = (Job)(_model.GetArgumentsForCallsMadeOn( m =&amp;gt; m.Add&amp;lt;Job&amp;gt;( &lt;span class="kwrd"&gt;null&lt;/span&gt; ) )[0][0]);&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum11" class="lnum"&gt;  11:&lt;/span&gt;     jobArg.Account.Id.ShouldEqual( _accountId );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum12" class="lnum"&gt;  12:&lt;/span&gt; }&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum13" class="lnum"&gt;  13:&lt;/span&gt;  &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum14" class="lnum"&gt;  14:&lt;/span&gt; [Specification]&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum15" class="lnum"&gt;  15:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; the_selected_from_date_should_be_used()&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum16" class="lnum"&gt;  16:&lt;/span&gt; {&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum17" class="lnum"&gt;  17:&lt;/span&gt;     var jobArg = (Job)(_model.GetArgumentsForCallsMadeOn( m =&amp;gt; m.Add&amp;lt;Job&amp;gt;( &lt;span class="kwrd"&gt;null&lt;/span&gt; ) )[0][0]);&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum18" class="lnum"&gt;  18:&lt;/span&gt;     jobArg.FromDate.ShouldEqual( _fromDate );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum19" class="lnum"&gt;  19:&lt;/span&gt; }&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum20" class="lnum"&gt;  20:&lt;/span&gt;  &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum21" class="lnum"&gt;  21:&lt;/span&gt; [Specification]&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum22" class="lnum"&gt;  22:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; the_selected_to_date_should_be_used()&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum23" class="lnum"&gt;  23:&lt;/span&gt; {&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum24" class="lnum"&gt;  24:&lt;/span&gt;     var jobArg = (Job)(_model.GetArgumentsForCallsMadeOn( m =&amp;gt; m.Add&amp;lt;Job&amp;gt;( &lt;span class="kwrd"&gt;null&lt;/span&gt; ) )[0][0]);&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum25" class="lnum"&gt;  25:&lt;/span&gt;     jobArg.ToDate.ShouldEqual( _toDate );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum26" class="lnum"&gt;  26:&lt;/span&gt; }&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum27" class="lnum"&gt;  27:&lt;/span&gt;  &lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum28" class="lnum"&gt;  28:&lt;/span&gt; [Specification]&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum29" class="lnum"&gt;  29:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; the_selected_line_items_should_be_used()&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum30" class="lnum"&gt;  30:&lt;/span&gt; {&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum31" class="lnum"&gt;  31:&lt;/span&gt;     var jobArg = (Job)(_model.GetArgumentsForCallsMadeOn( m =&amp;gt; m.Add&amp;lt;Job&amp;gt;( &lt;span class="kwrd"&gt;null&lt;/span&gt; ) )[0][0]);&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alteven"&gt;&lt;span id="lnum32" class="lnum"&gt;  32:&lt;/span&gt;     jobArg.LineItems.Select( li =&amp;gt; li.LineItem.Id ).ShouldHaveSameElements( _lineItems );&lt;/pre&gt;
&lt;!--CRLF--&gt;

    &lt;pre class="alt"&gt;&lt;span id="lnum33" class="lnum"&gt;  33:&lt;/span&gt; }&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;That’s good enough for me.  I guess I will have to search for some other ideas to improve Rhino Mocks.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:23d365d0-788b-40c9-9cbf-f65eefc580d2" class="wlWriterEditableSmartContent"&gt;Tags: &lt;a href="http://technorati.com/tags/Testing" rel="tag"&gt;Testing&lt;/a&gt;, &lt;a href="http://technorati.com/tags/Mocking" rel="tag"&gt;Mocking&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=134581"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=134581" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/WillSmith/aggbug/134581.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Will Smith</dc:creator>
            <guid>http://geekswithblogs.net/WillSmith/archive/2009/09/09/rhino-mocks-meaningful-failure-messages-on-expectations.aspx</guid>
            <pubDate>Wed, 09 Sep 2009 18:08:15 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/WillSmith/comments/134581.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/WillSmith/archive/2009/09/09/rhino-mocks-meaningful-failure-messages-on-expectations.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/WillSmith/comments/commentRss/134581.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/WillSmith/services/trackbacks/134581.aspx</trackback:ping>
        </item>
        <item>
            <title>Alternative to Dynamic Data: A Follow-Up</title>
            <link>http://geekswithblogs.net/WillSmith/archive/2009/06/30/alternative-to-dynamic-data-a-follow-up.aspx</link>
            <description>&lt;p&gt;A few weeks ago, I blogged about building an alternative to Dynamic Data.  I have to say, it’s pretty sweet.  I added a new entity type yesterday, including a couple of minor overrides and I was done.&lt;/p&gt;  &lt;p&gt;Here are the steps I had to take (testing left out for clarity):&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Create the entity:&lt;/li&gt;    &lt;div class="csharpcode-wrapper" id="codeSnippetWrapper"&gt;     &lt;div class="csharpcode" id="codeSnippet"&gt;       &lt;pre class="alt"&gt;&lt;span class="lnum" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ExcludedCounterparty : IAuditedWithId&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alteven"&gt;&lt;span class="lnum" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alt"&gt;&lt;span class="lnum" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Id { get; set; }&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alteven"&gt;&lt;span class="lnum" id="lnum4"&gt;   4:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; Counterparty Counterparty {get; set;}&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alt"&gt;&lt;span class="lnum" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; CreatedByUser { get; set; }&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alteven"&gt;&lt;span class="lnum" id="lnum6"&gt;   6:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; DateTime? CreatedOnDate { get; set; }&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alt"&gt;&lt;span class="lnum" id="lnum7"&gt;   7:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ModifiedByUser { get; set; }&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alteven"&gt;&lt;span class="lnum" id="lnum8"&gt;   8:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; DateTime? ModifiedOnDate { get; set; }&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alt"&gt;&lt;span class="lnum" id="lnum9"&gt;   9:&lt;/span&gt; }&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
  &lt;/div&gt;

  &lt;li&gt;Override the Fluent NHibernate conventions:&lt;/li&gt;

  &lt;div class="csharpcode-wrapper" id="codeSnippetWrapper"&gt;
    &lt;div class="csharpcode" id="codeSnippet"&gt;
      &lt;pre class="alt"&gt;&lt;span class="lnum" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Override( AutoMap&amp;lt;ExcludedCounterparty&amp;gt; mapping )&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alteven"&gt;&lt;span class="lnum" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alt"&gt;&lt;span class="lnum" id="lnum3"&gt;   3:&lt;/span&gt;     mapping.References( ec =&amp;gt; ec.Counterparty, &lt;span class="str"&gt;"FK_CounterpartyId"&lt;/span&gt; );&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alteven"&gt;&lt;span class="lnum" id="lnum4"&gt;   4:&lt;/span&gt; }&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
  &lt;/div&gt;

  &lt;li&gt;Override the UI conventions:&lt;/li&gt;

  &lt;div class="csharpcode-wrapper" id="codeSnippetWrapper"&gt;
    &lt;div class="csharpcode" id="codeSnippet"&gt;
      &lt;pre class="alt"&gt;&lt;span class="lnum" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Override()&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alteven"&gt;&lt;span class="lnum" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alt"&gt;&lt;span class="lnum" id="lnum3"&gt;   3:&lt;/span&gt;     Config.AllowEdit = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alteven"&gt;&lt;span class="lnum" id="lnum4"&gt;   4:&lt;/span&gt;     Config.AllowDelete = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alt"&gt;&lt;span class="lnum" id="lnum5"&gt;   5:&lt;/span&gt;     Field( ec =&amp;gt; ec.ModifiedByUser ).ShouldDisplay = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alteven"&gt;&lt;span class="lnum" id="lnum6"&gt;   6:&lt;/span&gt;     Field( ec =&amp;gt; ec.ModifiedOnDate ).ShouldDisplay = &lt;span class="kwrd"&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;!--CRLF--&gt;

      &lt;pre class="alt"&gt;&lt;span class="lnum" id="lnum7"&gt;   7:&lt;/span&gt; }&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
  &lt;/div&gt;

  &lt;li&gt;Add the menu configuration&lt;/li&gt;

  &lt;div id="codeSnippetWrapper"&gt;
    &lt;div class="csharpcode" id="codeSnippet"&gt;
      &lt;pre class="alt"&gt;&lt;span class="lnum" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;siteMapNode&lt;/span&gt; &lt;span class="attr"&gt;url&lt;/span&gt;&lt;span class="kwrd"&gt;="~/../ManageEntities.aspx?type=ExcludedCounterparty"&lt;/span&gt; &lt;span class="attr"&gt;title&lt;/span&gt;&lt;span class="kwrd"&gt;="Counterparty Exclusions"&lt;/span&gt; &lt;span class="attr"&gt;roles&lt;/span&gt;&lt;span class="kwrd"&gt;="…"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;siteMapNode&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;!--CRLF--&gt;&lt;/div&gt;
  &lt;/div&gt;

  &lt;li&gt;Update security&lt;/li&gt;

  &lt;li&gt;Done.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice that nowhere did I say that I had to create a aspx page or ascx control.  How sweet is that!  Also, both Fluent and my UI automation automatically pick up the new entity based on the assembly configuration.  It’s days like this that makes software development fun.&lt;/p&gt;

&lt;div class="wlWriterEditableSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:dad204fb-3794-4d61-b1f0-4f994766bdd5" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Tags: &lt;a href="http://technorati.com/tags/ASP.Net" rel="tag"&gt;ASP.Net&lt;/a&gt;, &lt;a href="http://technorati.com/tags/UI" rel="tag"&gt;UI&lt;/a&gt;, &lt;a href="http://technorati.com/tags/Convention+over+Configuration" rel="tag"&gt;Convention over Configuration&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=133160"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=133160" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/WillSmith/aggbug/133160.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Will Smith</dc:creator>
            <guid>http://geekswithblogs.net/WillSmith/archive/2009/06/30/alternative-to-dynamic-data-a-follow-up.aspx</guid>
            <pubDate>Tue, 30 Jun 2009 17:48:51 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/WillSmith/comments/133160.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/WillSmith/archive/2009/06/30/alternative-to-dynamic-data-a-follow-up.aspx#feedback</comments>
            <wfw:commentRss>http://geekswithblogs.net/WillSmith/comments/commentRss/133160.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/WillSmith/services/trackbacks/133160.aspx</trackback:ping>
        </item>
        <item>
            <title>An alternative to Dynamic Data</title>
            <link>http://geekswithblogs.net/WillSmith/archive/2009/06/08/an-alternative-to-dynamic-data.aspx</link>
            <description>&lt;p&gt;A couple of weeks ago I was searching for an alternative to Dynamic Data.  My motivation was simple.  Integrating Dynamic Data with Oracle and/or NHibernate would be challenging.  I was amazed at how little I could find that would solve this problem.  Surely Dynamic Data wasn’t the first or only.  Eventually, I gave up and worked with a coworker to develop our own alternative.&lt;/p&gt;  &lt;p&gt;Fresh off a Fluent Nhibernate implementation, we decided to take the convention-over-configuration approach.  The Fluent interface worked very well for us, in particular the auto-mapping feature.  This is what we wanted to accomplish with our UI automation.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Configuration Points:      &lt;br /&gt;&lt;/strong&gt;First we had to identify the configuration points.  Things like, label or header text, visibility, formatting, editor, among others.  We introduced two basic configuration objects, one for the entity and one for the fields (properties).  Our goal was to have a simple CRUD user interface that would be completed automated by reading information from these configuration objects.  Everything from subtitles, to actions, to data grids would be automated.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Conventions:      &lt;br /&gt;&lt;/strong&gt;To avoid wasting time configuring individual entity classes, we decided to “auto-map” our UI.  We started off with simple conventions.  For example, deriving the subtitle from the class name.  The subtitle for “BookStore” would be “Book Stores” by convention.  We handled the singular case as well to support our actions, like “Add Book Store” or “Edit Book Store”.  Also, fields would follow a similar convention for labels and headers.&lt;/p&gt;  &lt;p&gt;Eventually as our needs grew, we defined more conventions.  The nice thing about this approach is that we are following the Open/Closed Principle.  If we need something new, we simply add another convention.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Overrides:      &lt;br /&gt;&lt;/strong&gt;Clearly, there will be exceptions to these conventions.  We took another page out of the Fluent Nhibernate book and implemented an Override model.  We simple allow implementations of IOverride&amp;lt;T&amp;gt; that provide an opportunity to change the auto-mapping behavior.   For example, IOverride&amp;lt;Party&amp;gt; might include “config.PluralLabel = "Parties"”.  When the automation service is initialized, we register the assembly containing our overrides.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Consumption:      &lt;br /&gt;&lt;/strong&gt;We created a few automation aware web controls that bring our entities to life.  Really all we needed was a custom grid view and data entry table.  Presenting the data in the grid view was really quite simple since grid views already support simple data binding.  Data entry turned out to be not so difficult as well, we simply kept track of a list of properties and values.  Then it was a matter of getting values from the entities with reflection, and later setting those values before persisting the entity.  &lt;/p&gt;  &lt;p&gt;Of course, the fact that we are using Nhibernate with methods like Save&amp;lt;T&amp;gt;( object ) helped with generic CRUD a lot.&lt;/p&gt;  &lt;p&gt; &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Cost Effectiveness:      &lt;br /&gt;&lt;/strong&gt;Many will question, “Why reinvent the wheel?”  Others will ask, “Have you really saved that much development time by building this framework?”  &lt;/p&gt;  &lt;p&gt;First, I felt that Dynamic Data would not meet our needs and I searched long and hard for an alternative to Dynamic Data and couldn’t find one.  So, I don’t feel like I am reinventing the wheel here.  Perhaps there are Nhibernate integrations now available for Dynamic Data, but there weren’t at the time.  Also, even if there were, being an infant, Dynamic Data would likely have problems that would take too long to resolve.  With our in house solution, we built only what we need.  And with the tests in place, we feel confident that we can make a change quickly if necessary.&lt;/p&gt;  &lt;p&gt;Second, we already experienced productivity gains more than once since adding the UI automation.  After defining a new entity, a simple one line override, and a menu item we were able to perform all CRUD on that entity because of the automation both on the UI side and the data side.  We didn’t have to write a single additional line of ASP.Net code.  In fact, my coworker wrote a prototype that takes an existing Java application (not web) and port it to our web interface.  He basically plugged in the new web application to a Java web service and the rest was cake.  When my boss saw the prototype, he about fell out of his chair.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:92f14cff-020c-4491-ac76-5e4d5d093d2e" class="wlWriterEditableSmartContent"&gt;Tags: &lt;a href="http://technorati.com/tags/UI" rel="tag"&gt;UI&lt;/a&gt;, &lt;a href="http://technorati.com/tags/ASP.Net" rel="tag"&gt;ASP.Net&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=132697"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=132697" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/WillSmith/aggbug/132697.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Will Smith</dc:creator>
            <guid>http://geekswithblogs.net/WillSmith/archive/2009/06/08/an-alternative-to-dynamic-data.aspx</guid>
            <pubDate>Mon, 08 Jun 2009 22:36:06 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/WillSmith/comments/132697.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/WillSmith/archive/2009/06/08/an-alternative-to-dynamic-data.aspx#feedback</comments>
            <slash:comments>1</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/WillSmith/comments/commentRss/132697.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/WillSmith/services/trackbacks/132697.aspx</trackback:ping>
        </item>
        <item>
            <title>What The People Want</title>
            <link>http://geekswithblogs.net/WillSmith/archive/2009/05/12/what-the-people-want.aspx</link>
            <description>&lt;p&gt;&lt;a href="http://geekswithblogs.net/images/geekswithblogs_net/WillSmith/WindowsLiveWriter/WhatThePeopleWant_A24A/image_8.png"&gt;&lt;img style="border-right-width: 0px; margin: 0px 10px 0px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" align="left" src="http://geekswithblogs.net/images/geekswithblogs_net/WillSmith/WindowsLiveWriter/WhatThePeopleWant_A24A/image_thumb_3.png" width="439" height="365" /&gt;&lt;/a&gt; &lt;font color="#ffff00"&gt;[Oct ’09 Update: &lt;em&gt;web views have approximately doubled since May.&lt;/em&gt;]&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;I was looking through my blog history to see which posts were visited the most.  To give you a point of reference, the next closest post to has around 3000 visits.  I’ve had more comments on “&lt;a href="http://geekswithblogs.net/WillSmith/archive/2008/06/18/oracle-update-with-join-again.aspx"&gt;Oracle Update with Join&lt;/a&gt;” than any other as well.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Ironically, I’ve been using NHibernate more heavily and these types of Oracle statements/queries hold less value in my daily activities.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:157d1fa6-8e32-43b4-9dbf-cfd64c46cd07" class="wlWriterEditableSmartContent"&gt;Tags: &lt;a href="http://technorati.com/tags/blogging" rel="tag"&gt;blogging&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=132061"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=132061" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/WillSmith/aggbug/132061.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Will Smith</dc:creator>
            <guid>http://geekswithblogs.net/WillSmith/archive/2009/05/12/what-the-people-want.aspx</guid>
            <pubDate>Tue, 12 May 2009 16:26:01 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/WillSmith/comments/132061.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/WillSmith/archive/2009/05/12/what-the-people-want.aspx#feedback</comments>
            <wfw:commentRss>http://geekswithblogs.net/WillSmith/comments/commentRss/132061.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/WillSmith/services/trackbacks/132061.aspx</trackback:ping>
        </item>
        <item>
            <title>Snapshot: My Life (Personal and Professional)</title>
            <link>http://geekswithblogs.net/WillSmith/archive/2009/05/12/snapshot-my-life-personal-and-professional.aspx</link>
            <description>&lt;p&gt;It’s a little hard to believe that I haven’t posted a blog in over a month.  Where have I been?  Frankly, doing my job and trying to keep up with my personal life at the same time.  I’ve been hesitant to include personal jabbering in my mostly technical blog.  But, I want to express what is most important to me.  I hope that most of you have similar priorities.&lt;/p&gt;  &lt;p&gt;At the beginning of the year, the church I attend lost it’s music director.  While we were looking for a replacement, I filled in as temporary director.  Suddenly, I had added a part-time job to my already busy schedule.  For Lent, I chose to participate in a bible study each Monday evening.  Also, I am involved with the Pastoral Council and we have been recently working very hard to prepare for discernment of new members.  &lt;/p&gt;  &lt;p&gt;Finally, I ran completely out of one of our most precious resources, time.  I had been singing with the Archdiocesan Choir for special liturgies throughout the year.  I also, volunteered to direct music for a men’s retreat at our church.  When, the music director left our church, I became so overwhelmed, that I could not fulfill my obligations to both the Archdiocesan Choir and the men’s retreat.&lt;/p&gt;  &lt;p&gt;All the while, I was trying to ensure my face was familiar to my family.  A few years ago, I returned from a business trip, at which time my younger daughter looked at me very inquisitively.  The look on her face is something I will scarcely forget.  It was the look of “who are you?”  I knew then that I needed to find a different job.&lt;/p&gt;  &lt;p&gt;I’ve held two jobs since then.  Both have been great (so far).  I have been able to spend more time with my family.  I’ve been able to meet my daughters’ teachers, and attend other school and church functions.  I even directed the children’s choir (at church) for a month or so.  &lt;/p&gt;  &lt;p&gt;One of the most rewarding things I’ve been able to do is go on daddy-daughter walks weekly, with my girls (individually).  It’s special time for them and for me.  Unfortunately, the events over the last couple of months put a strain on that time together, and I missed a few weeks.&lt;/p&gt;  &lt;p&gt;I couldn’t have a better wife.  She is the most patient person I know.  And she is always looking out for me and my health.  Without her support, I suspect the stress would have overwhelmed me.  It sounds cliché, but she truly does make me a better person, and makes me &lt;em&gt;want&lt;/em&gt; to be a better person.&lt;/p&gt;  &lt;p&gt;On top of all of this, at work, I completed one project in late February, and started another at the same time.  The last project was pretty much a solo endeavor.  I am pleased that I’ve got a teammate for the new one.  We’ve been able to accomplish things in the last couple of months that I had put off on the previous project.  In the next few weeks I hope to share some of the things we have been working on.  &lt;/p&gt;  &lt;p&gt;We recently incorporated a more BDD style to our testing, using SpecUnit.  Also, we are now using StructureMap to help manage dependencies.  We are using Nhibernate (including the Fluent interface) for the first time on our new project.  We started building our own brand of UI automation/templates for CRUD (Dynamic Data just didn’t cut it for us).  Finally, we decided to incorporate the Enterprise Library Validation Block as well.  We brought all of this together and still hit our deadline for the first milestone of the project.&lt;/p&gt;  &lt;p&gt;The order in which I covered things in this blog was very purposeful.  What should be clear is that this blog is not one of my top priorities.  In fact, my job and career are, at best, third on my list.  So the question is, how do you keep it all together?  Can you give each aspect of your life adequate attention?  I think the key is to give proper attention at the proper time.  My wife humors me when I talk shop at home, but I know she appreciates it much more when I leave work at the office.  Similarly, taking breaks at work to talk about your personal life is fine, just don’t overdo it.&lt;/p&gt;  &lt;p&gt;Live Better, Code Better.&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:2073d990-e36a-45f0-85eb-9be0d24a72c4" class="wlWriterEditableSmartContent"&gt;Tags: &lt;a href="http://technorati.com/tags/Priorities" rel="tag"&gt;Priorities&lt;/a&gt;, &lt;a href="http://technorati.com/tags/Community" rel="tag"&gt;Community&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=132046"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=132046" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/WillSmith/aggbug/132046.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Will Smith</dc:creator>
            <guid>http://geekswithblogs.net/WillSmith/archive/2009/05/12/snapshot-my-life-personal-and-professional.aspx</guid>
            <pubDate>Tue, 12 May 2009 05:10:07 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/WillSmith/comments/132046.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/WillSmith/archive/2009/05/12/snapshot-my-life-personal-and-professional.aspx#feedback</comments>
            <wfw:commentRss>http://geekswithblogs.net/WillSmith/comments/commentRss/132046.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/WillSmith/services/trackbacks/132046.aspx</trackback:ping>
        </item>
        <item>
            <title>Why I am not using ASP.Net MVC</title>
            <category>Asp.Net</category>
            <link>http://geekswithblogs.net/WillSmith/archive/2009/04/01/why-i-am-not-using-asp.net-mvc.aspx</link>
            <description>&lt;p&gt;About a year ago, I started to evaluate &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=53289097-73ce-43bf-b6a6-35e00103cb4b&amp;amp;displaylang=en"&gt;ASP.Net MVC&lt;/a&gt;, but decided to put it aside because it was still in heavy-duty development.  With the official release a couple of weeks ago, I decided to check it out once again.&lt;/p&gt;  &lt;p&gt;MVC has a lot of things to offer, but there are a few critical things that we couldn’t overlook.  We have a few web applications that all have quite a lot invested in server controls (both third-party and developed in-house).  &lt;/p&gt;  &lt;p&gt;In ASP.Net WebForms, for something as simple as a GridView with a ObjectDataSource, there is a lot handled behind the scenes.  The time it would take to mimic the necessary behavior in MVC appears to be unmanageable at this point.  I’ve done my share of HTML, and am comfortable doing it again, but it certainly feels like a step backward.  We would have to write a lot of HTML and JavaScript (with the help of &lt;a title="" href="http://jquery.com/" rel="" target="_blank"&gt;jQuery&lt;/a&gt;) to accomplish what takes just a few lines with server controls.&lt;/p&gt;  &lt;p&gt;Another issue that we cannot overcome is the fact that WebParts are basically server controls and are mostly incompatible with MVC.  One of our applications is highly dependent on WebParts.  Again, there is a lot of work handled for us by simply leveraging the WebPartManager.&lt;/p&gt;  &lt;p&gt;So, it was easy to rule MVC out in regard to existing applications.  But, what about something new?  Well, for all the same reasons we’ve decided to stick with ASP.Net WebForms.  Basically, we have invested a lot in server controls, like menus, tree views, grid views, and in-house controls to promote common look and feel between our applications.  Moving to MVC would be no small task.&lt;/p&gt;  &lt;p&gt;There is one place that I am considering MVC within our existing framework.  I’m wondering if we can leverage MVC to better handle our Ajax needs.  In a couple of occasions, we are using WebForms with no markup, that simply return xml data.  We also use Page Methods in a couple of places.  It seems like MVC could handle these types of requests more cleanly.&lt;/p&gt;  &lt;p&gt;Perhaps in a few months the community will develop some slick MVC controls that save a lot of work.  Unfortunately, I don’t have the time (money) to build these controls myself.&lt;/p&gt;  &lt;p&gt;Anyway, if I am totally off the mark, please someone pick me up and set me straight.&lt;/p&gt;  &lt;div class="wlWriterEditableSmartContent" id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:a71174ba-1fab-44e0-81da-a2cdb4b9ac24" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"&gt;Tags: &lt;a href="http://technorati.com/tags/MVC.Net" rel="tag"&gt;MVC.Net&lt;/a&gt;, &lt;a href="http://technorati.com/tags/ASP.Net" rel="tag"&gt;ASP.Net&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;a href="http://www.pheedo.com/click.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=130649"&gt;&lt;img src="http://www.pheedo.com/img.phdo?x=6cda6ad746d942b9a1110d0715a4fa12&amp;u=130649" border="0"/&gt;&lt;/a&gt;&lt;/p&gt;&lt;iframe src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;PageID=31016&amp;amp;SiteID=1" width=1 height=1 Marginwidth=0 Marginheight=0 Hspace=0 Vspace=0 Frameborder=0 Scrolling=No&gt;
&lt;script language='javascript1.1' src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Browser=NETSCAPE4&amp;amp;NoCache=True&amp;PageID=31016&amp;amp;SiteID=1"&gt;&lt;/script&gt;
&lt;noscript&gt;&lt;a href="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Click&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" target="_blank"&gt;
&lt;img src="http://ads.geekswithblogs.net/a.aspx?ZoneID=5&amp;amp;Task=Get&amp;amp;Mode=HTML&amp;amp;SiteID=1&amp;amp;PageID=31016" width="1" height="1" border="0"  alt=""&gt;&lt;/a&gt;
&lt;/noscript&gt;
&lt;/iframe&gt;
&lt;img src="http://geekswithblogs.net/WillSmith/aggbug/130649.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>Will Smith</dc:creator>
            <guid>http://geekswithblogs.net/WillSmith/archive/2009/04/01/why-i-am-not-using-asp.net-mvc.aspx</guid>
            <pubDate>Wed, 01 Apr 2009 20:37:34 GMT</pubDate>
            <wfw:comment>http://geekswithblogs.net/WillSmith/comments/130649.aspx</wfw:comment>
            <comments>http://geekswithblogs.net/WillSmith/archive/2009/04/01/why-i-am-not-using-asp.net-mvc.aspx#feedback</comments>
            <slash:comments>6</slash:comments>
            <wfw:commentRss>http://geekswithblogs.net/WillSmith/comments/commentRss/130649.aspx</wfw:commentRss>
            <trackback:ping>http://geekswithblogs.net/WillSmith/services/trackbacks/130649.aspx</trackback:ping>
        </item>
    </channel>
</rss>