<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-4904879802205428995</atom:id><lastBuildDate>Sun, 28 Feb 2010 00:24:03 +0000</lastBuildDate><title>Best Guess Theory</title><description>A place to discuss Development techniques, .NET, XNA, NHibernate or anything else that tickles your fancy</description><link>http://www.bestguesstheory.com/</link><managingEditor>Hudson.Akridge@gmail.com (Hudson Akridge)</managingEditor><generator>Blogger</generator><openSearch:totalResults>27</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/BestGuessTheory" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="bestguesstheory" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-7437835430921275090</guid><pubDate>Wed, 17 Feb 2010 16:42:00 +0000</pubDate><atom:updated>2010-02-17T10:43:52.041-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">XNA</category><title>Awesome 3D framework for XNA?</title><description>&lt;a href="http://xen.codeplex.com/wikipage?title=Screenshots&amp;amp;referringTitle=Home"&gt;Xen 3D XNA Framework&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Filing this under things Tuna has recommended me that I don't have time to check into yet, but which look pretty friggan sweet. I'll update later with anything I find on it. Or you guys can tell me if you've had any experience with it ;)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-7437835430921275090?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2010/02/awesome-3d-framework-for-xna.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-5919331332541702184</guid><pubDate>Fri, 12 Feb 2010 22:16:00 +0000</pubDate><atom:updated>2010-02-12T16:45:55.041-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">EReader</category><title>Converting CHM to ePUB (and a e-reader review)</title><description>Just got my &lt;a href="http://www.astak.com/product.asp?serial=05EZRED"&gt;Astak Ez Reader Pocket Pro 5"&lt;/a&gt;, and I love it. It's the perfect size, solid resolution, has all the features, all the document support you could ever want, is very fast, has 3 different places to change the page, including link navigation, supports up to a 16gb SD card (aka a metric assload of books), no bullshit DRM and has a battery life measured in months. That's right. Months. This thing just doesn't die. It's brilliant. I've been raving about it for the week or so that I've had it now.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So on to the issue. I have a few technical books as CHM files (Old school, right?), and with the advent of ePub as a standard e-reader format, I wanted a way to convert them into some spiffy epubs so I can take advantage of text reflow (which is also supported in PDFs on the Astak). ePub is an amazing format. Low size, fantastic orientation, and chapter support. Plus, it's a standard document definition, unlike PDF, which is all over the place. It's also quite a good bit faster than PDF to navigate and turn pages on. Faster in the e-reader world typically means less processing, and less processing means longer battery life (plus a happier reader not having to wait as long for the page to turn).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;i&gt;Step1: CHM to HTML.&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;You have to get the CHM into HTML somehow. There's a few tools to do this. My favorite is &lt;a href="http://www.processtext.com/abcchm.html"&gt;ABC Amber's CHM Converter&lt;/a&gt;. It does cost, but it's worth it if you've got a lot of CHMs. If you don't, you can still use the trial and get away with not having watermarks crapped out all over the result (I'll explain in a few). You can also use the HH.exe in windows (if that's your platform of choice) to decompile the CHM out into a messy website in a folder of your choice (&lt;span class="Apple-style-span" style="font-family: Consolas, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New'; font-size: 14px; border-collapse: collapse; line-height: 18px; white-space: pre; "&gt;&lt;span class="pln" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;HH&lt;/span&gt;&lt;span class="pun" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;.&lt;/span&gt;&lt;span class="pln" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;EXE &lt;/span&gt;&lt;span class="pun" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;-&lt;/span&gt;&lt;span class="pln" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;decompile C&lt;/span&gt;&lt;span class="pun" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;:\&lt;/span&gt;&lt;span class="typ" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: rgb(43, 145, 175); background-position: initial initial; background-repeat: initial initial; "&gt;Temp&lt;/span&gt;&lt;span class="pun" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;\&lt;/span&gt;&lt;span class="pln" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;decompile&lt;/span&gt;&lt;span class="pun" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;-&lt;/span&gt;&lt;span class="pln" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;folder C&lt;/span&gt;&lt;span class="pun" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;:\&lt;/span&gt;&lt;span class="typ" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: rgb(43, 145, 175); background-position: initial initial; background-repeat: initial initial; "&gt;Temp&lt;/span&gt;&lt;span class="pun" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;\&lt;/span&gt;&lt;span class="pln" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;yourCHM&lt;/span&gt;&lt;span class="pun" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;.&lt;/span&gt;&lt;span class="pln" style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; font-size: 14px; vertical-align: baseline; background-image: initial; background-attachment: initial; background-origin: initial; background-clip: initial; background-color: transparent; color: black; background-position: initial initial; background-repeat: initial initial; "&gt;chm).&lt;span class="Apple-style-span" style="border-collapse: separate; font-family: Georgia, serif; line-height: normal; white-space: normal; font-size: 16px; "&gt; You can typically convert in one of two ways:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;A single HTML file&lt;/li&gt;&lt;li&gt;Multiple HTML files (website)&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you go option 1, it's much easier to track and manage, however because of the way ereaders work, navigating pages and chapters will be a huge pain. It'll take quite a few to turn to the next page and 10-15 seconds to navigate chapters on a 600 page book. Option 2 makes turning pages and chapter navigation significantly faster, but involves more work on your end to manage.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We want to go option 2, this is the best speed, and that counts for a lot on an eReader. Now that we've got an output directory containing our "website" we want to investigate the dir. Inside, you should find a single HTML file and a folder of the same name. Open up the folder and go to the images directory (or something similar). Remove any superfluous images such as arrow navigations or whatever else might have been included in the CHM (like header seperators and such). Feel free to also remove any images that you feel might not be of a significant benefit to you reading the book.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, look for a main.html or go up a level and look at the html file in the root folder. What you're looking for is the HTML file that acts as the Menu. The menu HTML file is important because it points to all of our chapters/pages for use during the next stage. It's also the place that if you used a trial of Amber CHM, you can do a search and replace for "[Trial Version]" and replace with an empty string and remove all of the "watermarking" that's done during the trial version conversion process. At this point, it's up to you to weed out any chapters you don't want to include in your ePub, such as appendixes, which can help to reduce the "noise" you'll see when navigating the ePub's menu file. Save the file if you've made any changes and continue on to the next step.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;&lt;i&gt;Step 2: HTML to ePUB&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;Going to introduce you to an awesome piece of free OSS software. &lt;a href="http://calibre-ebook.com/"&gt;Calibre&lt;/a&gt;. This converts from almost any format into an ePub, and it's great at it. If you're using a single HTML file from step1, then all you need to do here is "Add book" point it at the HTML file, and then "Convert To" and specify ePub as the target source. Done. However that's not what we've chosen to do if you're following along. So when you go to "Add book" in Calibre, you need to select &lt;b&gt;*only*&lt;/b&gt; the MENU HTML FILE that you created in the first step. This file is going to tell Calibre where all of the rest of your "chapters" are.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Give Calibre a few moments to import and create a zip containing all of the referenced files. When it's completed, you should see the book appear in the list (hopefully with a size &gt; 0 next to it if you've done it correctly). Right click and go to "Convert". Choose ePub as your output. I'd also recommend deselecting the options for a title page/image. Also select the option in the Menu section for Calibre to generate it's own menu file (it'll clean it up a bit).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Convert. You can now copy the converted ePub to your eReader (which is hopefully an Astak! =p ). Where is it? It's in the Calibre directory created for managing your books. Can't find that? Right click on the book in the Calibre list and go to "View source folder". Viola.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now you've got a lightning quick ePub file out of a single CHM. Hopefully this helps a few people out :) Good luck!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-5919331332541702184?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2010/02/converting-chm-to-epub-and-e-reader.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-4747633222701439406</guid><pubDate>Fri, 05 Feb 2010 22:28:00 +0000</pubDate><atom:updated>2010-02-05T17:52:03.590-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">NHibernate</category><category domain="http://www.blogger.com/atom/ns#">C#</category><category domain="http://www.blogger.com/atom/ns#">Best Practice</category><category domain="http://www.blogger.com/atom/ns#">SQL</category><title>The NHibernate Dereference pattern</title><description>Sometimes, NHibernate associations are so complex that relying on cascades is not always possible or optimal. Other times, you need to ensure that your session deleted object is actually removed from your in memory reference model (e.g. The loaded entities which still reference it) without having to refresh your objects from the database. I ran into this a while back when dealing with a bi-directional ManyToMany in which neither side would allow an all-delete-orphan cascade, and created a variant of the Disposable pattern to resolve it.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm sure that other developers implement something similar during their delete process, but I haven't run across anything formally defined. This keeps coming up, and after helping several FluentNHibernate &amp;amp; NHibernate users out by giving them direction I decided to do a writeup. I'm going to try and state the pattern on here for your reference and feedback. Disclaimer: I'm not saying it's perfect, or that there's not something better, I'm just saying it works for what we need, and we haven't found anything better yet.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Intent:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Called before an NHibernate Session.Delete(). Disassociates the entity from the domain model, removing all references to the entity, thereby allowing NHibernate to generate the appropriate UPDATE/DELETE statements in the database, in the order required, so there's no Foreign Key Violations. This pattern works with inheritance.&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Implementation:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="csharpcode"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IDereferenceable&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;{&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;  &lt;span class="kwrd"&gt;void&lt;/span&gt; Dereference();&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; PersistedBase : IDereferenceable&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;{&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;  &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsDereferencing;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dereference()&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;  {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;    Dereference(IsDereferencing);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;  }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;  &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dereference(&lt;span class="kwrd"&gt;bool&lt;/span&gt; dereferencing)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt;  {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt; (dereferencing)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;     { &lt;span class="kwrd"&gt;return&lt;/span&gt;; }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;     IsDereferencing = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;     &lt;span class="rem"&gt;//Dereference Children&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;     &lt;span class="kwrd"&gt;foreach&lt;/span&gt;(Child child &lt;span class="kwrd"&gt;in&lt;/span&gt; Children.ToList())&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;     {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;          RemoveChildCore(child);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  24:  &lt;/span&gt;     }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  25:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  26:  &lt;/span&gt;     &lt;span class="rem"&gt;//Dereference Parents&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  27:  &lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt;(parent != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  28:  &lt;/span&gt;     {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  29:  &lt;/span&gt;       parent.RemoveChild(&lt;span class="kwrd"&gt;this&lt;/span&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  30:  &lt;/span&gt;       parent = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  31:  &lt;/span&gt;     }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  32:  &lt;/span&gt;  }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  33:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  34:  &lt;/span&gt;  &lt;span class="kwrd"&gt;private&lt;/span&gt; ICollection&amp;lt;Child&amp;gt; children;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  35:  &lt;/span&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; IEnumerable&amp;lt;Child&amp;gt; Children{ get { &lt;span class="kwrd"&gt;return&lt;/span&gt; children; } }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  36:  &lt;/span&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RemoveChild(Child child)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  37:  &lt;/span&gt;  {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  38:  &lt;/span&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt;(!IsDereferencing)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  39:  &lt;/span&gt;      {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  40:  &lt;/span&gt;          RemoveChildCore(child);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  41:  &lt;/span&gt;      }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  42:  &lt;/span&gt;  }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  43:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  44:  &lt;/span&gt;  &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RemoveChildCore(Child child)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  45:  &lt;/span&gt;  {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  46:  &lt;/span&gt;      children.Remove(child);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  47:  &lt;/span&gt;      IDereferenceable deref = child &lt;span class="kwrd"&gt;as&lt;/span&gt; IDereferenceable;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  48:  &lt;/span&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt;(deref ! = &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  49:  &lt;/span&gt;      {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  50:  &lt;/span&gt;          deref.Dereference();&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  51:  &lt;/span&gt;      }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  52:  &lt;/span&gt;  }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  53:  &lt;/span&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  54:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  55:  &lt;/span&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Concrete : PersistedBase&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  56:  &lt;/span&gt;{&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  57:  &lt;/span&gt;  &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dereference(&lt;span class="kwrd"&gt;bool&lt;/span&gt; dereferencing)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  58:  &lt;/span&gt;  {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  59:  &lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt; (dereferencing)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  60:  &lt;/span&gt;     { &lt;span class="kwrd"&gt;return&lt;/span&gt;; }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  61:  &lt;/span&gt;     IsDereferencing = &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  62:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  63:  &lt;/span&gt;     &lt;span class="rem"&gt;//Dereference Children&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  64:  &lt;/span&gt;     &lt;span class="kwrd"&gt;foreach&lt;/span&gt;(StepChild stepChild &lt;span class="kwrd"&gt;in&lt;/span&gt; StepChildren.ToList())&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  65:  &lt;/span&gt;     {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  66:  &lt;/span&gt;          RemoveStepChildCore(stepChild);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  67:  &lt;/span&gt;     }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  68:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  69:  &lt;/span&gt;     &lt;span class="rem"&gt;//Dereference Parents&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  70:  &lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt;(stepParent != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  71:  &lt;/span&gt;     { &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  72:  &lt;/span&gt;       stepParent.RemoveChild(&lt;span class="kwrd"&gt;this&lt;/span&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  73:  &lt;/span&gt;       stepParent = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  74:  &lt;/span&gt;     }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  75:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  76:  &lt;/span&gt;     &lt;span class="kwrd"&gt;base&lt;/span&gt;.Dereference(&lt;span class="kwrd"&gt;false&lt;/span&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  77:  &lt;/span&gt;  }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  78:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  79:  &lt;/span&gt;  &lt;span class="kwrd"&gt;private&lt;/span&gt; ICollection&amp;lt;StepChild&amp;gt; stepChildren;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  80:  &lt;/span&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; IEnumerable&amp;lt;StepChild&amp;gt; StepChildren{ get { &lt;span class="kwrd"&gt;return&lt;/span&gt; stepChildren; } }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  81:  &lt;/span&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RemoveStepChild(StepChild stepChild)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  82:  &lt;/span&gt;  {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  83:  &lt;/span&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt;(!IsDereferencing)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  84:  &lt;/span&gt;      {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  85:  &lt;/span&gt;          RemoveStepChildCore(stepChild);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  86:  &lt;/span&gt;      }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  87:  &lt;/span&gt;  }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  88:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  89:  &lt;/span&gt;  &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RemoveStepChildCore(StepChild stepChild)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  90:  &lt;/span&gt;  {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  91:  &lt;/span&gt;      stepChildren.Remove(stepChild);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  92:  &lt;/span&gt;      IDereferenceable deref = stepChild &lt;span class="kwrd"&gt;as&lt;/span&gt; IDereferenceable;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  93:  &lt;/span&gt;      &lt;span class="kwrd"&gt;if&lt;/span&gt;(deref ! = &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  94:  &lt;/span&gt;      {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  95:  &lt;/span&gt;          deref.Dereference();&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  96:  &lt;/span&gt;      }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  97:  &lt;/span&gt;  }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  98:  &lt;/span&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;Let's go down the list:&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Our abstract class/interface. This is the base class that handles basic dereference association and implements the IDereferenceable interface.&lt;/li&gt;&lt;li&gt;IsDereferencing - This is similar to the IsDisposing/Disposed flag on IDisposable objects. It's a way to ensure that we only Dereference an object once. This is only set within the protected Dereference method if it's passed in a !dereferencing parameter.&lt;/li&gt;&lt;li&gt;Dereference() - Public no-parameter. This is what is called by by the code that's about to delete the object. It's also called by other classes whenever they want to dereference this instance as a child reference. Passing in the current IsDereferencing flag prevents us from getting into a cyclic call if it's called several times by many parent classes.&lt;/li&gt;&lt;li&gt;Dereference(bool dereferencing) A.) We early escape if our dereferencing parameter is true, so we don't perform any dereference logic more than once B.) Dereference children first. Children are typically going to be defined as collections, but there are always exceptions. C.) We enumerate over a copy of the collection. Reason? We're going to get a collection cannot be modified during enumeration exception otherwise. D.) We call the private RemoveChildCore(child), which does not do a dereferencing check (otherwise nothing would happen) E.) We check first to see if Parent is null, this is primarily here for situations where a Parent is allowed to be null, or during testing where you may not popular all the parents of an entity F.) If parent is not null, then we call the public RemoveChild(this) method on the parent so we're no longer referenced in a parent collection. Important to note, that RemoveChild() on the parent does perform a !IsDereferencing check on the parent, just like we have for the child. After all, the Child's Dereference() could have been called by the Parent's Dereference(), so we want to respect this. G.) We null out the parent&lt;/li&gt;&lt;li&gt;Our collection is exposed out as a read only collection, which tells the user that we do not allow adding/removing directly on the collection. Good practice and safety precaution if you have additional association logic, which you would put into the AddChild(Child child) method (not implemented here for the sake of simplifying the example).&lt;/li&gt;&lt;li&gt;The public RemoveChild(Child child) checks if we're dereferencing, if we are, then we skip actually removing the child. This is there so that when children are being dereferenced, and call parent.RemoveChild(this), they do not enter a cyclic loop. If not dereferencing, call Core dereference.&lt;/li&gt;&lt;li&gt;RemoveChildCore(Child child) has no checks, and is private, so it should be tightly controlled by the class. This will remove the item from the private collection, cast the child as a dereferenceable, and then if the child is dereferenceable, it will proceed to call Dereference on it. NOTE: that child.Dereference() should only be called if the child dies with the parent, so if the parent is dereferenced, the child should be as well. in some cases, this is not the case, and there might only be an incidental association between them, such as is the case with a ManyToMany() association. In this case, dereferencing the child should be avoided (perhaps though you need to keep the two lists synchronized in the MTM example, so you'd call child.RemoveParents(this) in place of the child.Dereference() )&lt;/li&gt;&lt;li&gt;The Concrete implementation of the base class. Here we have a similar setup as the base class, except we've got additional information that needs to be dereferenced (another collection and parent, defined as StepChildren and StepParent)&lt;/li&gt;&lt;li&gt;Dereference(bool dereferencing). Our setup here is the same, and can be referenced from 4 A-G. However, it adds a new element at the end: H.) We call our base.Dereference(false) to continue up the dereference stack. Passing it false is important, since we know we're in the middle of dereferencing and should override the dereferencing check. If we passed the IsDereferencing field, the base Dereference would not fire, meaning that any references specific to the base class would still hold a reference to our class. As we're overriding, polymorphism dictates that our bottom level class (most concrete) will have Dereference called on it first. So it Dereferences from most specific to most generic (Covarience).&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;b&gt;Usage:&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;div class="csharpcode"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt;(var session = sessionFactory.OpenSession())&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt;(var transaction = session.BeginTransaction())&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;{&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;  var concrete = session.Get(id);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;  concrete.Dereference();&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;  session.Delete(concrete);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;  transaction.CommittTransaction();&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="csharpcode"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="csharpcode"&gt;&lt;span class="Apple-style-span"  style="font-family:arial;"&gt;So there you go, a way to manage the disassociations with NHibernate (or another ORM) and your object model. Hopefully this helps someone out, and if it doesn't, feel free to leave a comment if you've got any critiques or questions. Always open to feedback! (Also wrote all of the code in notepad, so if anything's off let me know and I'll correct it)&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-4747633222701439406?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2010/02/nhibernate-dereference-pattern.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-5987064595607189043</guid><pubDate>Fri, 15 Jan 2010 18:37:00 +0000</pubDate><atom:updated>2010-01-15T12:45:16.051-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">Speaking</category><title>CodeMash 2010 Session Materials</title><description>Just finished my second session at &lt;a href="http://www.codemash.org/"&gt;CodeMash&lt;/a&gt;. Was a good time, and had a pretty packed house. As promised:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;Here's my &lt;a href="http://sites.google.com/site/bestguesstheory/FNH_PresentationResources_CodeMash2010.zip"&gt;session materials&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Thanks for attending, and CodeMash has been pretty amazing. Will come to Ohio again ;)&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-5987064595607189043?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2010/01/codemash-2010-session-materials.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-125198002596442225</guid><pubDate>Thu, 31 Dec 2009 16:12:00 +0000</pubDate><atom:updated>2009-12-31T10:47:24.963-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">NHibernate</category><category domain="http://www.blogger.com/atom/ns#">Best Practice</category><category domain="http://www.blogger.com/atom/ns#">SQL</category><title>EAV in OO/NHibernate: Part 1 - Intro</title><description>&lt;div&gt;&lt;div&gt;I've been talking to a decent number of developers about the system that Robert and I are writing at GFX, and I'm met with many blank stares every time the acronym EAV pops up. I thought it might be worthwhile to try and explain what is probably the most double edged sword in data modeling I've ever run into. If you do a &lt;a href="http://www.google.com/search?hl=en&amp;amp;rlz=1C1GGLS_enUS321US321&amp;amp;q=EAV+problems&amp;amp;aq=f&amp;amp;oq=&amp;amp;aqi="&gt;search&lt;/a&gt; for EAV problems, you'll get 99 people out of 100 telling you one horror story after another about implementing/using it in production systems. They're not crazy, or wrong. EAV architecture is a very tricky beast to tame. Unfortunately, there's not an alternative I've found out there that gives the flexibility that an EAV system offers in an RDBMS. Knowledge is power, and in order to tame the beast, you first must understand it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://en.wikipedia.org/wiki/Entity-attribute-value_model"&gt;EAV (Entity Attribute Value) systems&lt;/a&gt; have been around for a good long while, if you're unfamiliar with the concepts, check out that wiki link, and I'll do my best to sum in about a paragraph or two here:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Basically, it takes the concept of a Table, with Columns describing the table's data and a row's context, and pivot's everything. You have your standard Entity that you're describing (a Car for example), which you use rows to describe your columns (the attributes, eg. Size, Color, WeightInLbs, # of doors, etc), and a matrix of rows to describe an individual Entity's attributes (Values, eg. Midsize, Red, 2210, 4). In a RDBMS, it's easy for users to create rows, but difficult (and almost always a bad practice) for them to create columns/tables. Using EAV offers a pretty high degree of flexibility within an application, but it's not without it's downsides: Performance, Deadlocking, and an increase in Complexity are the front runners.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There's two types of EAV systems: EAV, and EAV/CR (Class Relationships). The first, is the type of EAV system you get from most modern ecommerce sites, where you can add any number of attributes to one of your products and they're all arbitrary and weakly typed. This is the simplest implementation, and (my guess) the most common. The second is where the rabbit hole opens up. In that scenario, an attribute is given a more formal definition and contains meta attribute information. This is the EAV type I'll be talking about. A good read on EAV/CR can be &lt;a href="http://ycmi.med.yale.edu/nadkarni/eav_CR_contents.htm"&gt;found here&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The large project I have been working on at my day job, is essentially an EAV/CR system for our clients. I'll quickly state the most basic requirements of the system:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Allows users to define their own Attributes, and strongly type them both in the domain and in the database.&lt;/li&gt;&lt;li&gt;Theoretically needs to support unlimited number of attributes a user can create to describe their entity.&lt;/li&gt;&lt;li&gt;Different "sets" of EAV data, so one user could have completely different data that is not shared between the context boundaries. (Context boundary could be anything, but typically is tied to each client, so every client has their own sets of attributes for entity types)&lt;/li&gt;&lt;li&gt;Multiple Entity types, with their own unique attributes&lt;/li&gt;&lt;li&gt;Extended attribute functionality that recreates many RDBMS column properties (eg. Uniqueness, Formulas, Bind able Context menus, etc.)&lt;/li&gt;&lt;li&gt;Must be easily searchable&lt;/li&gt;&lt;li&gt;Must allow for fast and scalable operations&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;These requirements are not without their own basic implementation challenges, but those last two bullet points, in my experience, are where the majority of the complications in building a system like this arise. EAV/CR's suffer from an exponential degradation in performance. &lt;i&gt;n &lt;/i&gt;attributes with &lt;i&gt;x &lt;/i&gt;entities produces &lt;i&gt;nx&lt;/i&gt;=(&lt;i&gt;v)alues&lt;/i&gt;. With 4,000 entities of the same type, and 200 attributes for each entity, you end up with 80,000 value rows. That's just for one entity type for one contextual boundary. Extend that with 50+ clients, and 10 entity types (80000 * 50 * 10), and you can quickly see how your &lt;i&gt;v&lt;/i&gt; table gets out of control.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The complexities of re-implementing your own database in code causes searching to become an exercise in pivoting and endless sub-queries forking for each attribute data type you expose. Full text indexing goes from being a checkbox in most DB engines to a caching like framework you inject into your system.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In later parts of this series, I'm going to talk about some implementation challenges and a few ways I've found to overcome them in OO and NHibernate.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-125198002596442225?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/12/eav-in-oonhibernate-part-1-intro.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-4767696376069605427</guid><pubDate>Thu, 05 Nov 2009 21:26:00 +0000</pubDate><atom:updated>2009-11-05T16:11:59.105-06:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">NHibernate</category><category domain="http://www.blogger.com/atom/ns#">SQL</category><title>Join Fetch on NH queries returns dupes</title><description>Domain:&lt;div&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Parent&lt;br /&gt;{&lt;br /&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; ICollection&amp;lt;Children&amp;gt;&lt;children&gt;&lt;child&gt; Children {get;set;}&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Child&lt;br /&gt;{&lt;br /&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Description {get;set;}&lt;br /&gt;}&lt;/child&gt;&lt;/children&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;Say we want to retrieve all the Parents in HQL, but we want to join fetch to get children simultaniously, so we don't lazyload children. In my case, I knew I'd be working with children immediately after retrieving Parents. The HQL would be something like this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;SELECT p FROM Parent p JOIN FETCH p.Children&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;Nothing fancy. When we execute that HQL query, we're going to get a Parent row returned to us, for every child for every parent. So if we've got 3 Parents, and each one has 2 children, we will have 6 rows returned from that statment.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Each row will have all of the attributes of Parent on it (as columns), and it will also have all of the attributes of child (as columns). This is how NHibernate ensures it retrieves both objects in the database simultaneously.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, after you execute the query, NHibernate gives you a list of 6 Parents. Each parent has a duplicate of itself in the retrieved list. Why? This is because that's what was returned, for rows, when you asked for Parents. You're getting both Parent and Child, but you're only selecting the Parent as the result from the query, NHibernate is smart enough to preload each Parent's collection of Children so when you attempt to access the collection, NHibernate does not need to go back to the database to load the collection.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, my problem was, how to get just 3 Parent's back, instead of 6. Well, a few people, might suggest using DISTINCT in your HQL, so it'd look something like:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-style: italic; "&gt;SELECT DISTINCT p FROM Parent p JOIN FETCH p.Children&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;Execute that, and you'll still get 6 Parent's, each parent, along with it's dupe. Why? Because DISTINCT is a SQL based syntax, and those rows are not dupes. Only the objects that are hydrated in the object model are. So you're not going to have any luck there.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What are your options?&lt;/div&gt;&lt;div&gt;1.) Use the results transformer:&lt;/div&gt;&lt;div&gt;&lt;i&gt;query/criteria.SetResultTransformer(new DistinctRootEntityResultTransformer());&lt;/i&gt;&lt;/div&gt;&lt;div&gt;The result transformer should work after NH has retrieved the objects back from the database, and will attempt to do a comparison with your root entity (I believe on the ID) to determine if they're the same.&lt;/div&gt;&lt;div&gt;2.) Do it yourself in Linq with &lt;i&gt;results.Distinct();&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;Hopefully this helps explain the situation a bit for a few people out there that might be experiencing the issue.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-4767696376069605427?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/11/join-fetch-on-nh-queries-returns-dupes.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-7557595824064022885</guid><pubDate>Sat, 17 Oct 2009 23:52:00 +0000</pubDate><atom:updated>2009-10-17T19:03:32.196-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Speaking</category><title>It's been a while</title><description>Things have been busy, and apologies all around for not updating this as often as I should.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm doing an NHibernate presentation at the&lt;a href="http://thestrangeloop.com/sessions/nhibernate-there-and-back-again"&gt; Strange Loop conference&lt;/a&gt; in St. Louis next week, although Robert will not be co-presenting contrary to the session description. Hopefully, after I return from there, there will be more time for me to continue the NH/FNH tips and general updates. (I will end up making a post with the session materials after the session however)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Since my last post, &lt;a href="http://fluentnhibernate.org/downloads"&gt;FNH 1.0 has come out&lt;/a&gt; thanks in large efforts to James Gregory, Tuna's gotten into XNA and found &lt;a href="http://www.codeplex.com/FarseerPhysics"&gt;several physics frameworks&lt;/a&gt; for it that I need to check out and make a few XNA related posts, and NH went to &lt;a href="http://sourceforge.net/projects/nhibernate/"&gt;2.1 officially&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've also just learned that my FNH session has been accepted at &lt;a href="http://codemash.org/Sessions#0-60+with+Fluent+NHibernate"&gt;CodeMash&lt;/a&gt; for January, so I hope to see anyone I don't see in St. Louis next week, there.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Until then!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-7557595824064022885?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/10/its-been-while.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-4761046783401390658</guid><pubDate>Thu, 16 Jul 2009 13:04:00 +0000</pubDate><atom:updated>2009-07-16T08:07:30.382-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">NHibernate</category><category domain="http://www.blogger.com/atom/ns#">Speaking</category><category domain="http://www.blogger.com/atom/ns#">Fluent</category><category domain="http://www.blogger.com/atom/ns#">C#</category><title>Video: Fluent NHibernate session from Chicago's Alt.NET</title><description>&lt;div&gt;Sergio posted the video of my session from 7/8. &lt;/div&gt;&lt;a href="http://chicagoalt.net/event/July2009Meeting060withFluentNHibernate"&gt;http://chicagoalt.net/event/July2009Meeting060withFluentNHibernate&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This one was a good bit longer than the one from Chicago Code Camp, due to no hard time restrictions. Thanks Sergio!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-4761046783401390658?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/07/video-fluent-nhibernate-session-from.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-5759715331121179936</guid><pubDate>Thu, 09 Jul 2009 13:45:00 +0000</pubDate><atom:updated>2009-07-09T09:54:14.165-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">NHibernate</category><category domain="http://www.blogger.com/atom/ns#">Best Practice</category><category domain="http://www.blogger.com/atom/ns#">SQL</category><title>NHibernate Tip #3 - ID's</title><description>&lt;div&gt;(Prequalifier, this is still a subject of much Debate, please toss in your thoughts into the comments. These are Tips that I've run across that I wanted to share, it's not to say that this is the best way to do something every time, and should not be considered the catch all solution)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;A subject of much debate, especially if anyone in the debate happens to have anything resembling a background as a DBA. I'll come right out and say what I believe to be the most ideal solution in a non-legacy environment that isn't geared towards squeezing the most performance out of the database as possible:&lt;div&gt;&lt;br /&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;id&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="Id"&lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;        &lt;span class="attr"&gt;column&lt;/span&gt;&lt;span class="kwrd"&gt;="PrimaryTableID"&lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;        &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Guid"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;generator&lt;/span&gt; &lt;span class="attr"&gt;class&lt;/span&gt;&lt;span class="kwrd"&gt;="assigned"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;version&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="Version"&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;             &lt;span class="attr"&gt;unsaved-value&lt;/span&gt;&lt;span class="kwrd"&gt;="0"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I would also recommend to have all of your objects generate the ID in the non-default constructor (you typically want to leave an empty default constructor for NHibernate for it to load an object back from the database without any "Object initialization" logic)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The above mapping is, in my opinion, the most flexible ID setup to use with NHibernate. Why?&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;NHibernate never has to go back to the database to "find out" what the ID is for the object, which is a very expensive operation on an Identity generation setup. A Hi-Lo setup would be a decent second choice to address this concern&lt;/li&gt;&lt;li&gt;Assuming you generate the ID in the non-default constructors, the ID of an object created anywhere is going to be consistent, whether you're outside of a session (such as in model tests), or in a session using hydrated objects&lt;/li&gt;&lt;li&gt;It significantly simplifies the equality checks you're required to do. As someone commented in my previous post, if you're unable to rely on having a unique ID at all times, your equality logic has to start incorporating additional rules to account for the pre-persistance case scenario's&lt;/li&gt;&lt;li&gt;Version manages when an object should be inserted through a cascade or not (as opposed to an unsaved value attribute). Version is also handy to have for other reasons that I'll bring up in a later post.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A couple of cons:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Looking at Guids in the database is not a pleasing experience, but really, you shouldn't be interacting with the database at that level. It's an implementation detail.&lt;/li&gt;&lt;li&gt;Using Guids in the database &lt;a href="http://groups.google.com/group/nhibernate-development/browse_thread/thread/d3158b50fc99c319/a4206f63100eb35b?lnk=gst&amp;amp;q=A+better+guid.comb+%3F#"&gt;can increase DB fragmentation&lt;/a&gt;, but really, that's where I feel the Database Engine Tuning advisor (if you're using MsSql) or a DBA steps in. There are ways around this, and as far as we've been able to tell with millions of rows in a production application, the differences seem to be almost un-noticable. Still, there's no way to get around it, it's not the best performing scenario on the DB side.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To be honest, I was originally on the side of continuing to use Identity, although I was looking at a hi-lo generator algorithm with it. My background is in a more DBA-ish field, so the concept presented above was like garlic to a vampire. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Times, they be a-changin. We need to let go of some of our old DBA habits in favor of emerging frameworks/concepts which can hide persistence complexities.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-5759715331121179936?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/07/nhibernate-tip-3-ids.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-5848832263101191326</guid><pubDate>Wed, 08 Jul 2009 13:43:00 +0000</pubDate><atom:updated>2009-07-09T08:44:17.027-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">NHibernate</category><category domain="http://www.blogger.com/atom/ns#">Best Practice</category><category domain="http://www.blogger.com/atom/ns#">SQL</category><title>NHibernate Tip #2 - Equality Overrides</title><description>&lt;div&gt;&lt;b&gt;Override Equals, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;GetHashCode&lt;/span&gt;, and the !=/== operators - &lt;/b&gt;This is pretty basic. If you're using &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;NHibernate&lt;/span&gt;, as a general rule of thumb for a best practice, you should override all of these functions. Why? Because by default your &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_2"&gt;applications&lt;/span&gt; will attempt to do a &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_3"&gt;referential&lt;/span&gt; check to determine if they're equal, or if the object already exists in the collection. &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_4"&gt;Implementing&lt;/span&gt; your own routine allows you to check the business properties of an entity, such as the ID or business data, to determine equality. To put it simply, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;NHibernate&lt;/span&gt; won't work correctly if you don't do this.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Overriding !=/== is important when you've set your &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_6"&gt;associations&lt;/span&gt; to &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;lazyload&lt;/span&gt;, because &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;NHibernate&lt;/span&gt; will generate proxies for those objects to support the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;lazyloading&lt;/span&gt; concept. Those proxies rely on these two overrides to determine object equality based on business rules (again, such as the ID/business rules).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Also important to note, testing the ID property of a lazy loaded (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;proxied&lt;/span&gt;) object does not load the object from the database. The ID property is free, that's how the proxy knows about which entity to load from the database. In an ideal world, you should try and work all of your equality rules to use the ID so you can take advantage of all of &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;NHibernate's&lt;/span&gt; &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_12"&gt;optimizations&lt;/span&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-5848832263101191326?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/07/nhibernate-tip-2-equality-overrides.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">4</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-8098413417835907178</guid><pubDate>Tue, 07 Jul 2009 14:40:00 +0000</pubDate><atom:updated>2009-07-07T10:05:38.554-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">NHibernate</category><category domain="http://www.blogger.com/atom/ns#">Best Practice</category><category domain="http://www.blogger.com/atom/ns#">SQL</category><title>NHibernate Tip #1 - Lazy Loading</title><description>I wanted to jot down all of the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;NHibernate&lt;/span&gt; tips and tricks that I've learned over the last year of using this thing in production, so this is everything I can remember up to current. Every day until I run out of things I've encountered, I'll be publishing another tip.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Lazy Load Everything&lt;/b&gt; - Unless working in a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;remoting&lt;/span&gt; type of environment where you're not &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_2"&gt;guaranteed&lt;/span&gt; a session while working with the objects, it's best to let this default to true for all of your entities. I've been burned by this hard, there's a fundamental &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_3"&gt;misunderstanding&lt;/span&gt; that I had when starting to &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;pre&lt;/span&gt;-optimize (also a bad idea). It went something like this: If I don't lazy load an entity, my application will perform better, because it will have eagerly fetched the data that I will use 80% of the time.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The problem is that lazy loading does not eagerly fetch anything for you. All it does, is execute the same &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;SQL&lt;/span&gt; statement to get the object, that it was going to when you eventually attempted to access it, except it's going to do that 100% of the time now. Setting this option to false does &lt;b&gt;*not* &lt;/b&gt;improve performance in any way, in fact, in every case, it will actually degrade performance. This is a feature, that as far as I can tell, should only be changed to false when you've got an object graph that loses scope from the session (such as in &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;remoting&lt;/span&gt;).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What most people are looking for when they set this to false on a mapping, is the "fetch=join" attribute. This will include the associated entity in the same &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;SQL&lt;/span&gt; statement used to get the originating entity. I'll probably make another post about the join fetch, all I can say for now is to use that sparingly. It can improve performance, but should be set at a more granular level (A Criteria or &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;HQL&lt;/span&gt; query), as opposed to the &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_9"&gt;entirety&lt;/span&gt; of the application.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-8098413417835907178?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/07/nhibernate-tip-1-lazy-loading.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-1370444753700952420</guid><pubDate>Mon, 29 Jun 2009 03:39:00 +0000</pubDate><atom:updated>2009-06-29T08:17:40.740-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">NHibernate</category><category domain="http://www.blogger.com/atom/ns#">Speaking</category><category domain="http://www.blogger.com/atom/ns#">Fluent</category><category domain="http://www.blogger.com/atom/ns#">C#</category><title>FNH session from Chicago Code Camp</title><description>&lt;div&gt;The sound is horrible in all of these, I apologize. I've gotten several requests to upload it anyhow regardless of the sound/camera issues. Watch at your own risk ;)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://vimeo.com/groups/18895/videos/sort:oldest"&gt;http://vimeo.com/groups/18895/videos/sort:oldest&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;They're all broken into about 10 minute chunks, except for the last one, which was just the last 15 minutes.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-1370444753700952420?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/06/fnh-session-from-chicago-code-camp.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-478774161613861417</guid><pubDate>Mon, 15 Jun 2009 16:09:00 +0000</pubDate><atom:updated>2009-06-16T09:12:52.801-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">NHibernate</category><category domain="http://www.blogger.com/atom/ns#">C#</category><category domain="http://www.blogger.com/atom/ns#">SQL</category><title>NHibernate EAV system search performance results</title><description>We've been working on a pretty large &lt;a href="http://en.wikipedia.org/wiki/Entity-Attribute-Value_model"&gt;EAV&lt;/a&gt; system this past year, and we're ramping up to get some real clients in it. One of it's features is a search builder that allows the end user to search on any combination of values on the entity that they've defined as attributes, and also any class specific attributes that are hardcoded on the class.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;SearchBuilder's great, it works well. The problem we've had with it is performance, specifically relating to scale. E.g. 10,000 entities, with 1,000 attributes each, would be 10,000,000 rows for a user to search through, and that's just for one grouping of entities, there would be more rows than this that are actually in Sql.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Currently, we were doing a subquery of these using NHibernate's criteria using a projection with a PropertyIn. This resolves out to be an IN query in SQL, so something like this:&lt;/div&gt;&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;this_.EntityID &lt;span class="kwrd"&gt;in&lt;/span&gt; (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; this_0_.EntityID &lt;span class="kwrd"&gt;as&lt;/span&gt; y0_&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt;   &lt;span class="kwrd"&gt;Values&lt;/span&gt; this_0_&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;       &lt;span class="kwrd"&gt;left&lt;/span&gt; &lt;span class="kwrd"&gt;outer&lt;/span&gt; &lt;span class="kwrd"&gt;join&lt;/span&gt; Attributes attr1_&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;         &lt;span class="kwrd"&gt;on&lt;/span&gt; this_0_.AttributeID = attr1_.AttributeID&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;       &lt;span class="kwrd"&gt;left&lt;/span&gt; &lt;span class="kwrd"&gt;outer&lt;/span&gt; &lt;span class="kwrd"&gt;join&lt;/span&gt; ValueEntities owner3_&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;         &lt;span class="kwrd"&gt;on&lt;/span&gt; this_0_.EntityID = owner3_.EntityID&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt;  this_0_.DiscriminatorValue = &lt;span class="str"&gt;'NumericValue'&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;       &lt;span class="kwrd"&gt;AND&lt;/span&gt; attr1_.Code = &lt;span class="str"&gt;'acd3edf4-6d11-4747-8383-03a70174d72e'&lt;/span&gt; /* @p6 */&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;       &lt;span class="kwrd"&gt;and&lt;/span&gt; attr1_.OwnerType = &lt;span class="str"&gt;'EntityType'&lt;/span&gt; /* @p8 */&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;       &lt;span class="kwrd"&gt;and&lt;/span&gt; this_0_.NumericValue &gt; 1 /* @p9 */)&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This allows us to match entities that have values, and then check to see if the entity exists in the subselect. Now, using the IN operator is traditionally a DBA's worst nightmare, and since we were hitting some performance issues, I opted to attempt to refactor this away from a subselect  after refactoring the domain model restrictions that prevented me from searching directly on the collection association in the first place. This moves into a JOIN model for each value type association (There are 4 value types in the system at the moment, int, string, datetime, bool; each strongly typed in the database, so we hold 4 different collections on the entity to associate their 4 value types so the Value property is strongly typed. The searchbuilder only creates the joins required to fulfill the search, so if only an int is being searched on, only that association will be made)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thinking I would nab a huge performance increase, I twittered about the performance issues with the IN that I was having, and @tehlike (Tuna) responded back asking if I had tried an Exists. I had not, and to be fair, I was basing all of my assumptions off of DBA articles I read a while back. Enamored, I decided to set up a simple performance profiling of the three different ways that I could execute my EAV find: JOIN (the new way), IN (The old way), EXISTS (The suggested way).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I set up my environment with a LocalSql2005 instance. During each execution I restarted MsSql so it wouldn't page the query (otherwise the second time the query runs you'd get it back in 1-2 seconds). This in no way is a thorough performance test, or even the most ideal. These numbers should be taken with a grain of salt at best. But they do give some general indications of performance comparisons. Here's the results:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Query restriction: A single attribute value on the entity being &gt; 1. &lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Baseline data: 1566 rows on the left side (entity side), 141119 rows on the right side (value sub select)&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;JOIN: 7s&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;IN: 7s&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;EXISTS: 8s&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;So, right away, the JOIN didn't give me the performance improvements that I had thought were coming. At this point, I started to get somewhat worried of what was going on behind the scenes, and if I had done something wrong. I relooked at the mappings, and the sql generated by each, and it all seemed to match up to what would by typed by hand. Next I bumped up the size of the data by 4x:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Query restriction: A single attribute value on the entity being &gt; 1&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Baseline data: 6264 rows on the left side, 564476 rows on the right side&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;JOIN: 26s&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;IN: 30s&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;EXISTS: 31s&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Join seems to perform a little bit better, but only slightly. On a whole, the performance improvement is underwhelming. Now I complicate things by changing up the query and adding an additional attribute value to be searched on of a different type (Another join to the specific value type collection for the JOIN, and another sub-select just referencing a different value column for the IN/EXISTS)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Query Restriction: Single value on entity being &gt; 0, and a text value being != 'NotAValue'&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-weight: bold; "&gt;Baseline data: 6264 rows on the left side, 564476 rows on the right side&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;JOIN 35s&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;IN 32s&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;EXISTS 31&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Wait...what? Join ended up slowing down significantly as you add different joins to the various value type collections and additional criteria values, wheras the subselects did not really, because SQL had already executed the sub-select for the first value, and the execution plan was already optimized when the second value subquery was being asked.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Grant you, these numbers fluxuated by a second or two when run multiple times, I'm giving the average. But IN/EXISTS seems to scale better than JOIN, in terms of adding additional restrictions, and additional value type associations.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In terms of row data scaling, the IN and Exists seemed to hold their own admirably to the JOIN, and in any complex query scenario, performed better.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So this brings me to the final decision: We're probably going to go back to the JOIN, and may look at tuning that to an EXISTS if we run into future performance issue. It's also important to note that indexing/statistics in MsSql plays a &lt;b&gt;*HUGE*&lt;/b&gt; role in the table performance. When the properly tuned indexing was enabled for the database, all three options went to sub second response times. So in the end, why quibble about the 1% syntax performance tweaks of a problem that is 99% solved by proper database tuning.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyone else have anything to add? I know it's not a large amount of test data, with a stable environment, but discounting that, I feel much better about using IN's/EXISTS now.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;UPDATE:&lt;/span&gt;&lt;/b&gt; Robert and I talked to Ayende at length about this (Another quick round of thanks to Ayende for being willing to dedicate the time).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It's looking like RDMS is definitely the wrong way to solve this problem. Looking at a document database, like Couch DB, or Ayende's own Divan DB. Alternatively, we can try and get something going using MsSql's Xml document column type.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Of course either of those options pose huge headaches in dealing with the search options we're giving to the client, so we're also looking at utilizing Lucene.NET to perhaps manage that.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Something tells me I'll be posing some blog entries in the near future milestoning our journey.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-478774161613861417?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/06/nhibernate-eav-system-search.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">6</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-461374283524029463</guid><pubDate>Thu, 11 Jun 2009 15:51:00 +0000</pubDate><atom:updated>2009-06-11T11:52:13.039-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><title>Why do we take on side projects?</title><description>I currently contribute to the following OSS projects:&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://fluentnhibernate.org/"&gt;Fluent &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;NHibernate&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.assembla.com/wiki/show/NHibernateQueryAnalyzer"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;NHibernate&lt;/span&gt; Query Analyzer&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;And a couple of other personal at home projects involving &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;XNA&lt;/span&gt;.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I have a full time job, a wife, and in a band. So why do I spend what little time I have &lt;span class="Apple-style-span" style="font-style: italic;"&gt;working&lt;/span&gt; when I get home, much less for free? For me, it's simple. I get the opportunity to give back to the community, the pride in being a part of a great team of developers who are creating fantastic products, and the chance at incredible learning opportunities.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;But that's not enough is it? For many of us, programming is a hobby in the evenings. It's a way to do things the way they were &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;*meant*&lt;/span&gt; to be done, without all of the bureaucracy and red tape that typically clutters up our day job. I mean, this is really a chance to flex our muscles, see what we can do when the restraints are taken off.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Some of us go &lt;a href="http://thedailywtf.com/"&gt;barreling into the wall at 100mph&lt;/a&gt; , but in general, it's a way to get back to the roots that drew all of us into programming in the first place. Fun. Doing something, just because you can, and it'll make &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;someone's&lt;/span&gt; life better as a result. Pushing the limits of terse code. Seeing just how fast you can actually get that cycle to complete in. Creating that framework that lets you plug in third party modules like home appliances. It's all great fun, and in my opinion, the way everything should be.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So what went wrong? Where did we go wrong during our day jobs? Why is it so difficult to find a company that's doing software development the fun way? With so many software engineers being hired out, why is there company after company that has one &lt;a href="http://thedailywtf.com/Articles/The_Call_of_Codethulhu.aspx"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;codethulu&lt;/span&gt;&lt;/a&gt; setup after another? &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;Where'd&lt;/span&gt; the fun go?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The false prophets took it away. Who am I talking about? Anyone who got into development for the wrong reasons: &lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;They were in sales 15 years ago and had some skills with spreadsheets at a (then) small company and became the "lead technical" guy&lt;br /&gt;&lt;/li&gt;&lt;li&gt;They went to school, didn't know what to do, and were told by the campus counselor that software was a growing industry and needed more warm bodies&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The old has been that grew up knowing one language, and one way to do something, and never changed (to a man with only a hammer, every problem appears to be a nail)&lt;/li&gt;&lt;li&gt;Warm bodies trained to pump out code which gets charged per line (aka many "call center" developers)&lt;/li&gt;&lt;li&gt;The cousin of the president of the company, who's always been "Good with computers"&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Generally these people have the best intentions, sometimes they don't, and they fight learning new processes and tools like a blind man sitting on a key lime pie (this is my blog, I'll make up whatever &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_6"&gt;ridiculous&lt;/span&gt; simile's I feel like). So where did they go wrong? If we're all trying to achieve the same thing, why is it such a common obstacle to overcome to develop software the Right Way™ ?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What are your stories and reasons for getting into development, and if you're on any passion projects, what were the reasons that led to you being involved?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-461374283524029463?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/06/why-do-we-take-on-side-projects.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-5855370112571402136</guid><pubDate>Sun, 31 May 2009 21:56:00 +0000</pubDate><atom:updated>2009-05-31T16:58:46.954-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">NHibernate</category><category domain="http://www.blogger.com/atom/ns#">Speaking</category><category domain="http://www.blogger.com/atom/ns#">Fluent</category><title>Chicago Code Camp session video: Update</title><description>Well, after ripping the DV, I learned a couple things about recording sessions yourself.&lt;br /&gt;1.) Try and find a cheap wireless mic to feed into the audio port, because in a decent sized room, even though everyone in the room could hear me well, the camera in the back picked up the AC unit that was running next to it far, far better than it did anything coming from the front&lt;br /&gt;2.) Make sure the projector screen is right next to you or behind you. Sadly I couldn't change this one, there were a couple rooms in the conference with the projector screen on the other side, and I was in one of them&lt;br /&gt;3.) Make sure you get tape that fits the minutes your presentation is for. 75 min presentation, but 60 min tape. So lost 5 minutes at the 60m mark when the camera operator changed it out&lt;br /&gt;4.) Make sure whoever is doing the camera knows to go to the code instead of zooming in on you whenever you're in the process of writing code, this was my fault. It was asked of me what I wanted to do, and I didn't have an answer.&lt;br /&gt;&lt;br /&gt;I've got to fix the audio though, trying to turn it up and what not. You can hear the guy under the camera cough a couple times, and boy, does that ever get picked up by the mic...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-5855370112571402136?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/05/chicago-code-camp-session-video-update.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-3492792576669881975</guid><pubDate>Sun, 31 May 2009 02:49:00 +0000</pubDate><atom:updated>2009-05-31T16:59:31.024-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">NHibernate</category><category domain="http://www.blogger.com/atom/ns#">Speaking</category><category domain="http://www.blogger.com/atom/ns#">Fluent</category><category domain="http://www.blogger.com/atom/ns#">C#</category><title>Fluent NHibernate Session material from Chicago Code Camp</title><description>As promised, here's my &lt;a href="http://sites.google.com/site/bestguesstheory/Home/FluentNHibernatePresentationResources.zip"&gt;session material&lt;/a&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had a great group participating in the session, so thanks group :) Hopefully it was as fun for all of you as it was for me.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've also got the video for anyone who was unable to make it to the session, which I'll try and get up tomorrow. Stay tuned to my twitter or rss this for updates.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-3492792576669881975?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/05/fluent-nhibernate-session-material-from.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-1384932392215728214</guid><pubDate>Tue, 19 May 2009 14:15:00 +0000</pubDate><atom:updated>2009-05-19T09:17:59.342-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">Fluent</category><title>Apologies for the delays</title><description>I'm strapped for time right now working on the Fluent NHibernate session for &lt;a href="http://www.chicagocodecamp.com/Sessions.html"&gt;Chicago Code Camp&lt;/a&gt;. I'll be posting more consistently after May 30th. Until then, if you're in the Chicago area, feel free to stop on by for that, and the many other fantastic sessions going on that day.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-1384932392215728214?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/05/apologies-for-delays.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-7005343000632771294</guid><pubDate>Tue, 28 Apr 2009 22:23:00 +0000</pubDate><atom:updated>2009-04-28T23:28:59.952-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">Fluent</category><category domain="http://www.blogger.com/atom/ns#">C#</category><category domain="http://www.blogger.com/atom/ns#">SQL</category><title>A Fluent NHibernate Tablename convention helper</title><description>So, one of my after hours duties is being a contributor/developer on the &lt;a href="http://www.fluentnhibernate.org/"&gt;Fluent NHibernate&lt;/a&gt; project. This past week or so, I've been in the process of converting my day job company's production system to Fluent (from standard hbm mappings). In the process, I've created a couple of helper methods to assist me in standardizing table names, Primary Key names, and Foreign key names. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First, we start with the basic pluralizer:&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span 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; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetPluralOfText(&lt;span class="kwrd"&gt;string&lt;/span&gt; text)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; pluralString = text;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; lastCharacter = pluralString.Substring(pluralString.Length - 1).ToLower();&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;            &lt;span class="rem"&gt;// y's become ies (such as Category to Categories)&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.Equals(lastCharacter, &lt;span class="str"&gt;"y"&lt;/span&gt;, StringComparison.InvariantCultureIgnoreCase))&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;            {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;                pluralString = pluralString.Remove(pluralString.Length - 1);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;                pluralString += &lt;span class="str"&gt;"ie"&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;            }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;            &lt;span class="rem"&gt;// ch's become ches (such as Pirch to Pirches)&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;string&lt;/span&gt;.Equals(pluralString.Substring(pluralString.Length - 2), &lt;span class="str"&gt;"ch"&lt;/span&gt;, StringComparison.InvariantCultureIgnoreCase))&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  14:  &lt;/span&gt;            { pluralString += &lt;span class="str"&gt;"e"&lt;/span&gt;; }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  15:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  16:  &lt;/span&gt;            &lt;span class="kwrd"&gt;switch&lt;/span&gt; (lastCharacter)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  17:  &lt;/span&gt;            {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  18:  &lt;/span&gt;                &lt;span class="kwrd"&gt;case&lt;/span&gt; &lt;span class="str"&gt;"s"&lt;/span&gt;:&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  19:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;return&lt;/span&gt; pluralString + &lt;span class="str"&gt;"es"&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  20:  &lt;/span&gt;                &lt;span class="kwrd"&gt;default&lt;/span&gt;:&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  21:  &lt;/span&gt;                    &lt;span class="kwrd"&gt;return&lt;/span&gt; pluralString + &lt;span class="str"&gt;"s"&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  22:  &lt;/span&gt;            }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  23:  &lt;/span&gt;        }&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I also added a method for stripping out some of the class name suffixes that are prevalent in the project:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span 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; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetTextWithoutObjectOrientedConventions(&lt;span class="kwrd"&gt;string&lt;/span&gt; text)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; newText = text;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;            &lt;span class="kwrd"&gt;if&lt;/span&gt; (newText.Contains(&lt;span class="str"&gt;"Base"&lt;/span&gt;) &amp;amp;&amp;amp; &lt;span class="kwrd"&gt;string&lt;/span&gt;.Equals(newText.Substring(newText.Length - 4), &lt;span class="str"&gt;"base"&lt;/span&gt;, StringComparison.InvariantCultureIgnoreCase))&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;            { newText = newText.Replace(newText.Substring(newText.Length - 4), &lt;span class="kwrd"&gt;string&lt;/span&gt;.Empty); }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; newText;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;        }&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;And finally, my methods that tie it all together:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span 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; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetTablename&amp;lt;TClass&amp;gt;()&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;        {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; GetTablename(&lt;span class="kwrd"&gt;typeof&lt;/span&gt; (TClass));&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;        }&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;        &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; GetTablename(Type tClass)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;        {&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;            &lt;span class="kwrd"&gt;string&lt;/span&gt; tableName = tClass.Name;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;            tableName = GetTextWithoutObjectOrientedConventions(tableName);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;            tableName = GetPluralOfText(tableName);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt; &lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  12:  &lt;/span&gt;            &lt;span class="kwrd"&gt;return&lt;/span&gt; tableName;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  13:  &lt;/span&gt;        }&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;So far, it's worked out pretty well. All of my FNH conventions utilize these methods regularly.  Anyhow, hope this post helps someone else out there :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-7005343000632771294?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/04/fluent-nhibernate-tablename-convention.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-6361920741681559495</guid><pubDate>Tue, 28 Apr 2009 04:34:00 +0000</pubDate><atom:updated>2009-04-27T23:57:54.459-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">Best Practice</category><title>Presenting A New Acronym for Failure...</title><description>This contractor that I've mentioned before in passing, is really good at doing things the most absurdly ridiculous way possible. If there's an easy and a hard way to do something, he'll invent a new way that does both, backwards.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;By now, everyone's familiar with AJAX (Asynchronous Javascript and XML), and if you're not, this blog may not be for you.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The application that was delivered to my company had a very peculiar feature. If you're familiar with .NET's AJAX 2.0 framework, then you're probably familiar with the &lt;a href="http://www.asp.net/Ajax/Ajaxcontroltoolkit/samples/Tabs/Tabs.aspx"&gt;Tab control&lt;/a&gt;. It's a very simple AJAX control, nothing fancy. Now, if you're also familiar with the ASP.NET webform's model of postbacks for controls to maintain viewstate, then you're familiar with all of the ingredients to the recipe here. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A rational, sane man, might develop a webpage using an AJAX Tab control. A rational, sane man, might develop another page using a series of tabs that take postbacks and pass some information along in viewstate. Our developmestruction hero took the road less travelled, and picked both.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's right. He's using the AJAX Tab control, except, when you swap tabs, about half a second to a second after the tab swaps, the whole page posts back, and you end up on a different .aspx page. My co-worker Robert and I couldn't believe it. I sat there, stupefied at what was before me. I announced that this man had created Asynchronous Synchronous Javascript and XML.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To which, Robert turned to me and loudly proclaimed:&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold; "&gt;&lt;span class="Apple-style-span"  style=" ;font-size:18px;"&gt;ASSJAX!&lt;/span&gt;&lt;/span&gt; &lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;(&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;AS&lt;/span&gt;ynchronous &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;S&lt;/span&gt;ynchronous &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;J&lt;/span&gt;avascript and &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;X&lt;/span&gt;ml). &lt;/div&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: left;"&gt;There's no escaping it. This term has become standard use in our office now. So thank you, anonymous contractor. You may have developed an indecipherable, bug ridden, amateur, spaghetti code system of evil that we'll have to maintain for God knows how long; but at least you gave us the greatest gift of all. ASSJAX.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-6361920741681559495?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/04/presenting-new-acronym-for-failure.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-6997637985817193011</guid><pubDate>Wed, 22 Apr 2009 05:06:00 +0000</pubDate><atom:updated>2009-04-22T00:16:42.181-05:00</atom:updated><title>Powered by the internet!</title><description>Just received some very important news!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style:italic;"&gt;HELLO:&lt;br /&gt;Good Day,This is to officially inform you that Your email address has just won an ATM CARD worth 6.8 Million Dollars in the satellite software email lottery conducted by OCEANIC BANK E-MAIL PROMO INTERNATIONAL, In which e-mail addresses are picked randomly by software powered by the Internet., Please Contact Mr.mark Kelvin with this email (oceanicplc@8u8.com)&lt;br /&gt;&lt;br /&gt;Tell +2347060481461.&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;VEREFICATION&lt;/span&gt; FORM&lt;br /&gt;1 Your Full Name:&lt;br /&gt;2 Your Delivery Address:&lt;br /&gt;3 Your Age:&lt;br /&gt;4 Your Occupation:&lt;br /&gt;5 Your direct Phone Number:&lt;br /&gt;6 Country&lt;br /&gt;:&lt;br /&gt;Regards,Mr David Mark&lt;br /&gt;SENATE PRESIDENT&lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;---&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Indeed, Mr. David Mark. I shall be forwarding you the &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;vere&lt;/span&gt;fication information you requested, only it'll be for this guy I used to work with, who's name &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_1"&gt;rhymes&lt;/span&gt; with Chris Wells.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-6997637985817193011?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/04/powered-by-internet.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-4336556338171687336</guid><pubDate>Wed, 15 Apr 2009 03:59:00 +0000</pubDate><atom:updated>2009-04-17T08:22:48.661-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><title>Blackest Night...</title><description>There's a consultant that I've had to work with at my company, who's legitimately a nice guy, or tries to be. But regardless of that, he's a terrible coder. What he checks in is some of the most bug addled, overly complex, difficult to read and debug code I've ever seen.&lt;br /&gt;&lt;br /&gt;I'll see if I can't get some permission from my employer to submit a couple of the "Golden nuggets" of his handy work, but for now, enjoy this brief glimpse at an enum I found of his for doing an item import. Honestly, I hope I never have to figure out how this works, but hey, at least it's commented for me...&lt;br /&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&lt;span class="kwrd"&gt;Enum&lt;/span&gt; ItemField&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;        Photo = 9999    &lt;span class="rem"&gt;'positive #'s are reserved for characteristics&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;        Disgard = 0&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;        LocalItemCode = -1    &lt;span class="rem"&gt;'negative #'s are reserved for Item table values&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;        CompanyItemCode = -2&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;        Name = -3&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;        Description = -4&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;        Vendor = -5&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;        Bilingual = -6&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;        Complete = -7&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;&lt;span class="kwrd"&gt;End&lt;/span&gt; Enum&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt; I have permission to post some of his code :) Prepare!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-4336556338171687336?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/04/blackest-night.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-1571453901832645819</guid><pubDate>Sat, 04 Apr 2009 23:05:00 +0000</pubDate><atom:updated>2009-04-04T20:14:35.299-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">Best Practice</category><title>The best laid names of mice and men</title><description>&lt;div&gt;What's in a name? If you're a person, it's there to establish your uniqueness within the community you live. If your name is Frank, and your father's name is Frank, then there's usually a Jr., Third, Fourth, etc attached to the end of your name so the people in your household know how to call which one of you down to supper. If you went to school with someone who had the same first name as you, it was often common for people to use your last name, or some abbreviation of your name to tell you apart. Your name establishes you as an entity.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you lived back in times not too far gone, say starting around 10th or 11th century AD, your last name (surname) would typically describe one of &lt;a href="http://www.searchforancestors.com/surnames/origin/"&gt;four things&lt;/a&gt; about you:&lt;/div&gt;&lt;div&gt;1.) What you and your family did for a living. The Coopers were barrel makers. The Wagners were wagon makers or blue fuzzy teleporting mutants.... &lt;/div&gt;&lt;div&gt;2.) Who your father was. Johnson, Peters, Myers, "The Mailman", etc.&lt;/div&gt;&lt;div&gt;3.) Something about your locality. The Ashley's lived by ash trees (not set on fire, or maybe they were, I'm sure some Ashley's were cremated at some point).&lt;/div&gt;&lt;div&gt;4.) Nicknames. Reid's were the redheads, the Armstrongs had strong arms, and the Cox's had...um...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You can even trace your family line back hundreds, if not thousands of years based on nothing more than your name. The point is, names are important. They help define us, and what we do. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The names of your variables, classes, and methods are no less important. In fact, they're probably &lt;span class="Apple-style-span" style="font-weight: bold;"&gt;more&lt;/span&gt; important, because they have no visual features in which to distinguish themselves by. They give context to your application. Well named objects help you define how your application works just like putting the correct words in the correct order helps someone read a book.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Naming is so important, that &lt;a href="http://forums.construx.com/blogs/stevemcc/default.aspx"&gt;Steve McConnel&lt;/a&gt; dedicated 32 pages to just naming variables in chapter 11 of the foundational book "Code Complete", plus even more pages for naming methods and classes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Back in 1999/98, &lt;a href="http://192.220.96.201/about.html"&gt;Paul Haahr&lt;/a&gt;  &lt;a href="http://paulhaahr.com/"&gt;(blog here)&lt;/a&gt;, wrote a foundationally solid &lt;a href="http://192.220.96.201/essays/java-style/naming.html"&gt;article&lt;/a&gt; regarding naming that I recommend checking out.&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Example time. Which set of variable names are easier to understand:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;numBckWLinFtTtl01, numBckWLinFtTtl02, numBckWLinFtTtl03&lt;/span&gt;&lt;/div&gt;&lt;div&gt;or&lt;span class="Apple-style-span" style="font-style: italic; "&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;standardStoreBackWallLinealFeet, prototypeStoreBackWallLinealFeet, remodeledStoreBackWallLinealFeet&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So what's wrong with the first set of variables? Other than it used to be in use in one of the legacy systems at my company.&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Uses a form of Hungarian notation (putting type information, along with other prefixes) into variable names. The truth is, there's simply no need to do this anymore. With modern IDE's, all it takes is hovering over your variable to get a tooltip telling you what type it is. All it does is add more letters to the front, that developers have to train themselves to ignore, so they can get at the real info&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The abbreviations. Cripes. If I had a nickle for every time I've touched a system that was bogged down by abbreviations, I'd be able to form a stimulus package of my own for the government. If you feel like your name is too long, and should be shortened, do not "fix" it by abbreviating. There are only two times when abbreviation is acceptable. When it's a common abbreviation (such as URL, RAM, email, etc.); or when your code size matters, such as in the case of Javascript. If your reason is the second one, let me introduce you to an automated technique called &lt;a href="http://en.wikipedia.org/wiki/Minification_(programming)"&gt;Minification.&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Ttl. Another abbreviation. Total is unnecessary in this case. Use generic words like "count" and "total" sparingly, if at all. In the majority of cases, they're too generic to add value to their use, and if the rest of your application is written well, the reader will easily be able to infer that meta piece of information.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;01, 02, 03. One day, the people who append generic numeric suffixes to variable names, will be set on fire and become Ashleys. We could easily fill a book on why this is a bad practice; completely indecipherable intent, accidental confusion with integer constants (especially if one uses a variable name like that in an expression: numBckWLinFtTtl01+01), or difficulty of managing multiple variables that only differ by the number on the end. But most importantly, always program like the next guy who takes over your code may be a serial killer. Keep that in mind the next time you think this it's acceptable to have a dateLastUsed04 in the system.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, what about the second set of names? Well, those make more sense in the given system. I don't even have to tell you anything about how the system works, or what it does, for you to start to understand what those three variables do. That's really the point. I want to be able to look at a variable, method, or class name, and immediately understand the purpose and use of the object.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Before you create an object; spend a little bit of extra time and consideration to it's name. If you can't come up with a good name that describes the intent, then perhaps you should re-examine the purpose of your new entity. After all, if you can't explain what it's purpose is, how can you expect someone else to come along after you and figure it out?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-1571453901832645819?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/04/best-laid-names-of-mice-and-men.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-2919836647776402279</guid><pubDate>Fri, 27 Mar 2009 03:43:00 +0000</pubDate><atom:updated>2009-03-27T10:53:25.402-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">NHibernate</category><category domain="http://www.blogger.com/atom/ns#">Fluent</category><category domain="http://www.blogger.com/atom/ns#">C#</category><category domain="http://www.blogger.com/atom/ns#">Best Practice</category><title>Fluent Method Chaining</title><description>So, something worth noting is the concept of &lt;a href="http://dikini.net/fluent_interfaces_method_chaining"&gt;Method Chaining&lt;/a&gt;. What I mean here, is the ability to call a method on an object, have that method return us an object, which we then use to perform actions on, which returns us an object which we then use to perform actions on, which return...oh you get the idea.&lt;br /&gt;&lt;br /&gt;In general, I find this method exceptionally useful if you're creating a suite of objects that operate together to set up a configuration. A good example of this might be from the &lt;a href="http://fluentnhibernate.org/"&gt;Fluent NHibernate&lt;/a&gt; mapping API. First, lets check out how to do a subclass mapping without using fluent chaining:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;DiscriminatorPart&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, Document&amp;gt; subClassDiscriminator = DiscriminateSubClassesOnColumn&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;(&lt;span class="str"&gt;"DiscriminatorValue"&lt;/span&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;SubClassPart&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, Document, Manager&amp;gt; subClassPart = &lt;span class="kwrd"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;DiscriminatorPart&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, Document&amp;gt; discriminatorPart = subClassDiscriminator.SubClass&amp;lt;Manager&amp;gt;(&lt;span class="str"&gt;"DocumentManager"&lt;/span&gt;, x =&amp;gt; {subClassPart=x;} );&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;ManyToManyPart&amp;lt;Document&amp;gt; manyToManyPart = subClassPart.HasManyToMany(x =&amp;gt; x.Documents);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;manyToManyPart.AsMap(&lt;span class="str"&gt;"indexColumn"&lt;/span&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;manyToManyPart.Inverse();&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;manyToManyPart.Cascade.AllDeleteOrphan();&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;manyToManyPart.LazyLoad();&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;manyToManyPart.WithForeignKeyConstraintName(&lt;span class="str"&gt;"FK_Managers_Documents"&lt;/span&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Not too bad in all actuality. We've all written code like the one above. But what if there was a different way to get the same thing? Lets look at the same functional code, but this time with Fluent NHibernate's chaining:&lt;br /&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;DiscriminateSubClassesOnColumn&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;&amp;gt;(&lt;span class="str"&gt;"DiscriminatorValue"&lt;/span&gt;)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;                .SubClass&amp;lt;DocumentManager&amp;gt;(&lt;span class="str"&gt;"DocumentManager"&lt;/span&gt;, mgr =&amp;gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;{&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;mgr.HasManyToMany(x =&amp;gt; x.Documents)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;  .AsMap(&lt;span class="str"&gt;"indexColumn"&lt;/span&gt;)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;      .Inverse()&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;      .Cascade.AllDeleteOrphan()&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;      .LazyLoad()&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;      .WithForeignKeyConstraintName(&lt;span class="str"&gt;"FK_Managers_Documents"&lt;/span&gt;);&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;   });&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Let me explain the basics of what's going on here:&lt;br /&gt;1: We're calling a method on our class, which returns to us a DiscriminatorPart object.&lt;br /&gt;2: That DiscriminatorPart has a SubClass() method on it, which returns to us the same DiscriminatorPart that was created on line 1&lt;br /&gt;4: The subclass DocumentManager is being mapped in the lambda. This is chained to call a HasManyToMany method on the DocumentManager, returning us a ManyToManyPart&lt;br /&gt;5: The ManyToManyPart has a Map() method called, setting up the collection type, and returning us itself as a ManyToManyPart&lt;br /&gt;6: The ManyToManyPart has an Inverse() method on it which sets a flag telling the mapping to write an inverse="true" attribute, and then returns us itself as a ManyToManyPart&lt;br /&gt;7: The ManyToManyPart has a Cascade() attribute set on it which creates a CollectionCascadeExpression on the ManyToManyPart. The chain from the CollectionCascadeExpression sets an attribute for the type of cascade, in this case, AllDeleteOrphan. The AllDeleteOrphan returns us the original ManyToManyPart object that Cascade was called on&lt;br /&gt;8-9: Other attributes are set via chained methods returning the ManyToManyPart&lt;br /&gt;&lt;br /&gt;What's the difference? Hopefully it's obvious. But I'll list out the main points I can see:&lt;br /&gt;- Less verbose code. Simply put, the largest benefit is that you have to write less. There's less repetition on the screen regarding accessing the same object over and over&lt;br /&gt;- Reads better. Because there's less code on the screen, it's easier to focus on just the parts that convey meaning, and read intent. When debugging or reviewing code, gathering intent is most likely the highest investment you have in the code.&lt;br /&gt;- More meaningful interface. We are able to specify what is allowed to be done at what point, and control the flow of access. In effect, we can guide the subscriber to our API down the "happy path".&lt;br /&gt;&lt;br /&gt;Regarding that last point, I would highly recommend the return types to fluently chainable methods to be exclusively interfaces. This allows you to cut down on the noise and dead end paths that might appear when you return an implemented class. Even Fluent NHibernate is guilty of violating this on many occasions, so don't feel too bad if you're tossing around concretes.&lt;br /&gt;&lt;br /&gt;How to tell when to use Fluent Method Chaining? The end result should be a much more elegant way in which to interact with your model. If you don't immediately notice the improvement, or it feels like you're having to do more work than you used to when interacting with dependant operations on your class, then go back and re-evaluate your usage of this technique. Perhaps you're using too large of an interface as the return type. Perhaps you're forcing chaining in situations where it doesn't make much logical sense to.&lt;br /&gt;&lt;br /&gt;Not every situation needs this approach. With enough experience, you'll quickly find which scenario's work best and which are better left to traditional declarations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-2919836647776402279?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/03/fluent-method-chaining.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-4280040815137296669</guid><pubDate>Tue, 10 Mar 2009 13:48:00 +0000</pubDate><atom:updated>2009-03-27T01:00:02.001-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">NHibernate</category><category domain="http://www.blogger.com/atom/ns#">SQL</category><title>NHibernate and Snapshot Isolation</title><description>Isolation levels make a large difference in how scalable your application is. Pick the wrong one, and your users will experience the kind of pain you see on &lt;a href="http://thedailywtf.com/"&gt;The Daily WTF&lt;/a&gt;. But, if you're running into concurrency issues (row locks), or other scalability problems, it may be worth your time to take a look at the Snapshot isolation.&lt;br /&gt;&lt;br /&gt;Typically, with NHibernate, you have four isolation strategies to choose from:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;ReadUncommitted - The one you really want to stay away from unless you're 100% you know what you're doing. You can end up with cascaded failures on transactions. That in and of itself should steer you away.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;ReadCommitted - The default isolation level used by NHibernate, and recommended for use in &lt;a href="http://www.manning.com/kuate/"&gt;NHibernate In Action&lt;/a&gt;, and other such qualified sources&lt;/li&gt;&lt;br /&gt;&lt;li&gt;RepeatableRead - Really, you should get the majority of the benefits of this from using caching and versioning&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Serializable - The flip side to ReadUncommitted, except this encounters scalability issues&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;However, NHibernate will use any isolation level supported by the database (and to that extent, ADO.NET). Which gives us "Snapshot" (recently introduced to MsSql2005+)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Lets talk briefly about the Snapshot isolation model (ref: &lt;a href="http://msdn.microsoft.com/en-us/library/tcbchxcb(VS.80).aspx"&gt;MSDN Article&lt;/a&gt;):&lt;/p&gt;&lt;br /&gt;&lt;p&gt;When writing to rows, snapshot isolation actually copies the rows from the table, into the TempDB (or another comparable system if not using MsSql), performs the necessary modifications, assigning those rows to transaction ID's, then commits the snapshot rows back when it's done. While the first transaction is performing operations on the rows, it will not cause a read lock. So a ReadCommitted isolation level can actually read the rows the way they were before the snapshot isolation transaction began.&lt;/p&gt;&lt;p&gt;If you attempt to write to rows as a second transaction that are in a first transaction who's isolation level is set to snapshot, then the second transaction will attempt to write to the same row our isolation transaction is attempting to write to, it will raise an error and roll back the snapshot transaction.&lt;/p&gt;&lt;p&gt;This mode can be a major benefit, giving you some of the concurrency benefits of ReadUncommitted, while still maintaining the data integrity of a more Serializable approach.&lt;/p&gt;&lt;p&gt;First, you must enable snapshots on your database. For MsSql:&lt;/p&gt;&lt;p&gt;&lt;span style="color:#000099;"&gt;ALTER DATABASE&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;MyDatabase&lt;/span&gt; &lt;span style="color:#000099;"&gt;SET ALLOW_SNAPSHOT_ISOLATION ON &lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#000099;"&gt;ALTER DATABASE&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;MyDatabase&lt;/span&gt; &lt;span style="color:#000099;"&gt;SET READ_COMMITTED_SNAPSHOT ON&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Then you set the default isolation level in the NHibernate Configuration section. Add the following config element:&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;span style="color:#ff0000;"&gt;&amp;lt;property name="connection.isolation"&amp;gt;Snapshot&amp;lt;/property&amp;gt;&lt;/span&gt; &lt;p&gt;You can alternatively change the isolation level inline when a transaction first begins:&lt;/p&gt;&lt;br /&gt;&lt;div class="csharpcode"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;ISession session = NewSession();&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;session.BeginTransaction(IsolationLevel.Snapshot);&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;This recently (along with other tweaks) helped us solve a concurrency issue in a large application. Is it a fixall? No, absolutely not. As always, you should be pragmatic in your approach to improving performance.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-4280040815137296669?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/03/nhibernate-and-snapshot-isolation.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-4904879802205428995.post-6266091828809008603</guid><pubDate>Thu, 05 Mar 2009 14:12:00 +0000</pubDate><atom:updated>2009-03-05T08:54:14.542-06:00</atom:updated><title>AT&amp;T was pretty close to the truth</title><description>In 1993 AT&amp;amp;T ran a &lt;a href="http://www.youtube.com/watch?v=TZb0avfQme8"&gt;couple ads explaining what you could do in the future &lt;/a&gt;(of course, AT&amp;amp;T would bring it to you).&lt;br /&gt;&lt;br /&gt;They were pretty spot on, but to be fair, the technology trend was already heading down those paths. They of course, had the insight, because they were in the "know" due to R&amp;amp;D.&lt;br /&gt;&lt;br /&gt;All in all, when you think about it, it's pretty amazing where we are from where we came in as little as 15 years. Science and technology are progressing at a rate unheard of in the history of the world. We're curing diseases faster than they can be discovered. We're increasing the average life expectancy at a rate of 40% of the time it takes to do it (thus, if you were born today, theoretically, your ALE by the time you're intended to die at age 75, will have gone up another 40% by the time you get to D-Day, assuming the same trend continues).&lt;br /&gt;&lt;br /&gt;Of course, we were lied to. We were told we'd be making a better world. And in some respects, we have. We need more funding towards enforcing net neutrality, Stem Cell research, and exploration (space and ocean). That's our future.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.eff.org/"&gt;The internet's wonder is it's neutral platform&lt;/a&gt;, what happens when everyone on earth is able to communicate at the speed of light without worry of being jailed as a result of something they've said or  seen online.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Stem_cell_research"&gt;Stem Cell research&lt;/a&gt; (and many other scientific advances that have been blue balled by government, specifically America's last administration) is the key to improving our physical well being.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.nasa.gov"&gt;Space&lt;/a&gt; and &lt;a href="http://oceanexplorer.noaa.gov/"&gt;Ocean&lt;/a&gt; exploration is the answer to coping with an increasingly diminishing supply of natural resources.&lt;br /&gt;&lt;br /&gt;It's an uncertain future. I, for one, have faith in humanity. Perhaps these dreams won't be realized in my lifetime, but if we can affect the change required to ensure that our children, and children's children have the bright future we were promised, I'll chalk that up into the win column.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4904879802205428995-6266091828809008603?l=www.bestguesstheory.com' alt='' /&gt;&lt;/div&gt;</description><link>http://www.bestguesstheory.com/2009/03/at-was-pretty-close-to-truth.html</link><author>Hudson.Akridge@gmail.com (Hudson Akridge)</author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total></item></channel></rss>
