<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://devlicio.us/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Alan Northam</title><link>http://devlicio.us/blogs/alan_northam/default.aspx</link><description /><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>Using LINQPad with NHibernate and S#arp Architecture</title><link>http://devlicio.us/blogs/alan_northam/archive/2009/12/17/using-linqpad-with-nhibernate.aspx</link><pubDate>Thu, 17 Dec 2009 22:05:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:54611</guid><dc:creator>anortham</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;(Update: Added the code to initialize Castle Windsor as well)&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve known about LINQPad for a long time but for some reason the usefulness of it just hit me yesterday.&amp;nbsp; In a moment of clarity I plopped my money down for all the bells and whistles and started playing.&amp;nbsp; I watched the &lt;a href="http://www.linqpad.com/UsingLINQPad.mov" target="_blank"&gt;video&lt;/a&gt; on the LINQPad site (you should too) and began thinking of the different ways it would most benefit my project.&amp;nbsp; Of course the first step would be getting LINQPad to use the my actual code.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;My current project is built on &lt;a href="http://www.sharparchitecture.net/" target="_blank"&gt;S#arp Architecture&lt;/a&gt; with a few modifications.&amp;nbsp; One of those modifications is the implementation of NHibernate.Linq in the repositories.&amp;nbsp; Using LINQPad to write snippets and query your database is cool but using it to query your NHibernate repositories is other-side-of-the-pillow (or Billy D. Williams) cool.&amp;nbsp; It&amp;#39;s also very easy to set up.&lt;/p&gt;
&lt;p&gt;I&amp;#39;m using the Northwind example that is included with S#harp Architecture with the addition of NHibernate.Linq to the SupplierRepository.&amp;nbsp; With LINQPad open hit F4 to open the Advanced Query Properties window and add the following additional references:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NHibernate.dll&lt;/li&gt;
&lt;li&gt;NHibernate.Linq.dll&lt;/li&gt;
&lt;li&gt;SharpArch.Core.dll&lt;/li&gt;
&lt;li&gt;SharpArch.Data.dll&lt;/li&gt;
&lt;li&gt;SharpArch.Web.Castle.dll&lt;/li&gt;
&lt;li&gt;SharpArch.Web.dll&lt;/li&gt;
&lt;li&gt;SharpArch.Testing.dll&lt;/li&gt;
&lt;li&gt;FluentNHibernate.dll&lt;/li&gt;
&lt;li&gt;log4net.dll&lt;/li&gt;
&lt;li&gt;Northwind.Core.dll&lt;/li&gt;
&lt;li&gt;Northwind.Data.dll&lt;/li&gt;
&lt;li&gt;Northwind.Web.dll&lt;/li&gt;
&lt;li&gt;Northwind.ApplicationServices.dll&lt;/li&gt;
&lt;li&gt;Castle.Core.dll&lt;/li&gt;
&lt;li&gt;Castle.Windsor.dll&lt;/li&gt;
&lt;li&gt;CommonServiceLocator.WindsorAdapter.dll&lt;/li&gt;
&lt;li&gt;Microsoft.Practices.ServiceLocation.dll&lt;/li&gt;
&lt;li&gt;Castle.MicroKernel.dll&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are for a basic setup, you might need to add additional references for your project.&lt;/p&gt;
&lt;p&gt;Next add these Additional Namespace Imports&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NHibernate.Cfg&lt;/li&gt;
&lt;li&gt;NHibernate.Linq&lt;/li&gt;
&lt;li&gt;SharpArch.Testing.NHibernate&lt;/li&gt;
&lt;li&gt;SharpArch.Data.NHibernate&lt;/li&gt;
&lt;li&gt;log4net&lt;/li&gt;
&lt;li&gt;log4net.Config&lt;/li&gt;
&lt;li&gt;Northwind.Data&lt;/li&gt;
&lt;li&gt;Northwind.Data.NHibernateMaps&lt;/li&gt;
&lt;li&gt;Castle.Windsor&lt;/li&gt;
&lt;li&gt;Microsoft.Practices.ServiceLocation&lt;/li&gt;
&lt;li&gt;CommonServiceLocator.WindsorAdapter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now all that&amp;#39;s left is to snag some code from the Global.ascx file to configure log4net, initialize NHibernate, Castle Windsor and adjust the paths to the web.config, NHibernate.config and the assembly that contains your mapped entities.&amp;nbsp; Also note the change from WebSessionStorage to SimpleSessionStorage.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/alan_5F00_northam/queryWindowNew.jpg"&gt;&lt;img width="800" border="0" src="http://devlicio.us/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/alan_5F00_northam/queryWindowNew.jpg" style="border:0;" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/alan_5F00_northam/queryWindow.jpg"&gt;&lt;br /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class="c#" name="code"&gt;var Log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType );
XmlConfigurator.Configure(new FileInfo(@&amp;quot;C:\src\Sharp-Architecture\src\NorthwindSample\app\Northwind.Web\Web.config&amp;quot;));
Log.Info( &amp;quot;Application Start&amp;quot; );
	
IWindsorContainer container = new WindsorContainer();
ComponentRegistrar.AddComponentsTo( container );
ServiceLocator.SetLocatorProvider( () =&amp;gt; new WindsorServiceLocator( container ) );

NHibernateSession.Init(
	new SimpleSessionStorage(),
	new[] {@&amp;quot;C:\src\Sharp-Architecture\src\NorthwindSample\app\Northwind.Web\bin\Northwind.Data.dll&amp;quot;},
	new AutoPersistenceModelGenerator().Generate(),
	@&amp;quot;C:\src\Sharp-Architecture\src\NorthwindSample\app\Northwind.Web\NHibernate.config&amp;quot; );
	
var repo = ( ISupplierRepository )ServiceLocator.Current.GetService( typeof( ISupplierRepository ) );

var supplier = from s in repo
				where s.CompanyName.StartsWith(&amp;quot;Bigfoot&amp;quot;)
				select s;
				
supplier.Dump();

&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Now you can use LINQPad to quickly try new code utilizing your custom assemblies.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=54611" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/NHibernate/default.aspx">NHibernate</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Sharp+Architecture/default.aspx">Sharp Architecture</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/LINQPad/default.aspx">LINQPad</category></item><item><title>Cache Revisited</title><link>http://devlicio.us/blogs/alan_northam/archive/2009/03/31/cache-revisited.aspx</link><pubDate>Wed, 01 Apr 2009 02:38:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:45315</guid><dc:creator>anortham</dc:creator><slash:comments>7</slash:comments><description>&lt;p&gt;Have you ever created a new email message with the main objective being to send someone an attachment and then forget to attach said attachment?&amp;nbsp; Apparently I did something similar to that in my last post.&amp;nbsp; At the time of the post, I couldn&amp;#39;t get the attach file method to work so I intended to add it later, but I didn&amp;#39;t.&amp;nbsp; That makes me a &lt;a target="_blank" href="http://en.wikipedia.org/wiki/Sexual_Harassment_Panda"&gt;sad panda&lt;/a&gt; :(&lt;/p&gt;
&lt;p&gt;I&amp;#39;ve been using a variant of this caching method with good results for quite some time.&amp;nbsp; So to make amends I&amp;#39;m going to post an updated version AND a proper sample solution.&amp;nbsp; And this time, I will remember to attach it.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre name="code" class="c-sharp"&gt;using System;&lt;br /&gt;using System.Reflection;&lt;br /&gt;using System.Web;&lt;br /&gt;using System.Web.Caching;&lt;br /&gt;using log4net;&lt;br /&gt;&lt;br /&gt;namespace BDI.Caching&lt;br /&gt;{&lt;br /&gt;	public class CacheHelper&lt;br /&gt;	{&lt;br /&gt;		private static readonly ILog log =&lt;br /&gt;			LogManager.GetLogger(&lt;br /&gt;				MethodBase.GetCurrentMethod().DeclaringType );&lt;br /&gt;&lt;br /&gt;		private static readonly bool isInfoEnabled = log.IsInfoEnabled;&lt;br /&gt;		private static readonly Cache cache = HttpRuntime.Cache;&lt;br /&gt;		private CacheHelper() {}&lt;br /&gt;&lt;br /&gt;		public static T GetFromCache&amp;lt;T&amp;gt;(&lt;br /&gt;			string key,&lt;br /&gt;			int cacheTimeInMinutes,&lt;br /&gt;			CacheExpiration cacheExpiration,&lt;br /&gt;			Func&amp;lt;T&amp;gt; retrieveMethod ) where T : class&lt;br /&gt;		{&lt;br /&gt;&lt;br /&gt;            var target = cache[key] as T;&lt;br /&gt;&lt;br /&gt;            if ( target == null )&lt;br /&gt;            {&lt;br /&gt;                if (isInfoEnabled)&lt;br /&gt;                    log.Info(&amp;quot;Cache miss for key:&amp;quot; + key + &amp;quot;  type:&amp;quot; + typeof (T));&lt;br /&gt;&lt;br /&gt;                target = retrieveMethod();&lt;br /&gt;&lt;br /&gt;                var absoluteExpiration = Cache.NoAbsoluteExpiration;&lt;br /&gt;                var slidingExpiration = Cache.NoSlidingExpiration;&lt;br /&gt;&lt;br /&gt;                switch (cacheExpiration)&lt;br /&gt;                {&lt;br /&gt;                    case CacheExpiration.Sliding:&lt;br /&gt;                        slidingExpiration = new TimeSpan(0, cacheTimeInMinutes, 0);&lt;br /&gt;                        break;&lt;br /&gt;                    case CacheExpiration.Absolute:&lt;br /&gt;                        absoluteExpiration = DateTime.Now.AddMinutes(cacheTimeInMinutes);&lt;br /&gt;                        break;&lt;br /&gt;                }&lt;br /&gt;&lt;br /&gt;                cache.Insert(key, target, null, absoluteExpiration, &lt;br /&gt;                    slidingExpiration, CacheItemPriority.Normal, OnRemove);&lt;br /&gt;&lt;br /&gt;            }&lt;br /&gt;            else&lt;br /&gt;            {&lt;br /&gt;                if ( isInfoEnabled )&lt;br /&gt;                    log.Info( &amp;quot;Cache hit for key:&amp;quot; + key + &amp;quot;  type:&amp;quot; + typeof( T ) );&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;		    return target;&lt;br /&gt;		}&lt;br /&gt;&lt;br /&gt;		public static void OnRemove( string key, object cacheItem, CacheItemRemovedReason reason )&lt;br /&gt;		{&lt;br /&gt;			if( isInfoEnabled )&lt;br /&gt;				log.Info( &amp;quot;Object removed from cache: Key-&amp;quot; + key + &amp;quot;: Reason-&amp;quot; + reason );&lt;br /&gt;		}&lt;br /&gt;&lt;br /&gt;		public static void RemoveFromCache( string key )&lt;br /&gt;		{&lt;br /&gt;			if( isInfoEnabled )&lt;br /&gt;				log.Info( &amp;quot;Object manually removed from cache: Key-&amp;quot; + key );&lt;br /&gt;&lt;br /&gt;			cache.Remove( key );&lt;br /&gt;		}&lt;br /&gt;	}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=45315" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Components.PostAttachments/00.00.04.53.15/AutoComplete.zip" length="2451567" type="application/zip" /><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Cache/default.aspx">Cache</category></item><item><title>Practical Implementation - spending some cache.</title><link>http://devlicio.us/blogs/alan_northam/archive/2008/03/17/practical-implementation-spending-some-cache.aspx</link><pubDate>Tue, 18 Mar 2008 01:35:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:39697</guid><dc:creator>anortham</dc:creator><slash:comments>1</slash:comments><description>&lt;p&gt;Take a look at my &lt;a href="http://devlicio.us/blogs/alan_northam/archive/2008/03/06/cold-hard-cache.aspx" target="_blank"&gt;previous post&lt;/a&gt; for the details on a cache helper method that I like to use.&amp;nbsp; In this post, we&amp;#39;ll be putting it to work (the word for today is J - O - B).&amp;nbsp; Here&amp;#39;s a look at the code for reference.&lt;/p&gt;
&lt;p&gt;
using System;
using System.Reflection;
using System.Web;
using System.Web.Caching;
using log4net;

namespace CacheManagement
{
    public delegate bool Factory&amp;lt;T&amp;gt;( out T instance );
    public class CacheHelper
    {
        private static readonly ILog log =
           LogManager.GetLogger(
               MethodBase.GetCurrentMethod().DeclaringType );

        private static readonly Cache cache = HttpRuntime.Cache;
        private CacheHelper() { }

        public static T GetFromCache&amp;lt;T&amp;gt;( string key, int cacheTimeInMinutes, Factory&amp;lt;T&amp;gt; retrieveMethod ) where T : class
        {
            T target = cache[key] as T;
            if ( target == null )
            {
                log.Info( &amp;quot;Cache miss for key:&amp;quot; + key + &amp;quot;  type:&amp;quot; + typeof( T ) );
                if ( retrieveMethod( out target ) )
                {
                    cache.Insert( key, target, null, DateTime.Now.AddMinutes( cacheTimeInMinutes ),
                        Cache.NoSlidingExpiration, CacheItemPriority.Normal, OnRemove );
                }
            }
            else
            {
                log.Info( &amp;quot;Cache hit for key:&amp;quot; + key + &amp;quot;  type:&amp;quot; + typeof( T ) );
            }
            return target;
        }

        public static void OnRemove( string key, object cacheItem, CacheItemRemovedReason reason )
        {
            log.Info( &amp;quot;Object removed from cache: Key-&amp;quot; + key + &amp;quot;: Reason-&amp;quot; + reason );
        }
    }
}
&lt;/p&gt;
&lt;p&gt;
Enter the &lt;a href="http://asp.net/AJAX/AjaxControlToolkit/Samples/AutoComplete/AutoComplete.aspx" target="_blank"&gt;ASP.NET AJAX AutoComplete Extender&lt;/a&gt;.&amp;nbsp; It&amp;#39;s a perfect candidate for a little cache help.&amp;nbsp; I certainly wouldn&amp;#39;t want the database being hit every time a user typed the next letter in the autocomplete box.&amp;nbsp; I apologize for wearing you down with all this talk.&amp;nbsp; I think I&amp;#39;ve said too much.&amp;nbsp; Let&amp;#39;s look at the code for autocomplete webservice.&lt;/p&gt;
&lt;p&gt;
using log4net;
using System.Reflection;
using System.Web.Services;
using System.Collections.Generic;
using CacheManagement;

[WebService( Namespace = &amp;quot;http://tempuri.org/&amp;quot; )]
[WebServiceBinding( ConformsTo = WsiProfiles.BasicProfile1_1 )]
[System.Web.Script.Services.ScriptService]
public class AutoCompleteWebService : WebService
{
    private static readonly ILog log =
       LogManager.GetLogger(
           MethodBase.GetCurrentMethod().DeclaringType );

    private static readonly int cacheTTL = 15;
    private static readonly int minimumPrefixLength = 3;

    public AutoCompleteWebService()
    {

        //Uncomment the following line if using designed components 
        //InitializeComponent(); 
    }

    [WebMethod]
    public string[] GetWordList( string prefixText, int count )
    {
        //minimumPrefixLength should never be greater than prefixText.Length
        //this is a sanity check to insure the minimumPrefixLength field was set corretly
        string prefixKey = prefixText.Substring( 0,
            minimumPrefixLength &amp;gt; prefixText.Length
                ? prefixText.Length : minimumPrefixLength );

        //get the working list
        List&amp;lt;string&amp;gt; searchList = CacheHelper.GetFromCache&amp;lt;List&amp;lt;string&amp;gt;&amp;gt;(
            prefixKey,
            cacheTTL,
            delegate( out List&amp;lt;string&amp;gt; instance )
            {
                return DataAccess.GetWordList( prefixKey, out instance );
            } );

        log.Debug( &amp;quot;searchList full count: &amp;quot; + searchList.Count );

        //narrow the results if the prefixText is longer than prefixKey
        if ( prefixText.Length &amp;gt; prefixKey.Length )
        {
            searchList = searchList.FindAll(
                delegate( string s )
                {
                    return s.Substring( 0, prefixText.Length &amp;gt; s.Length
                        ? s.Length : prefixText.Length ) == prefixText;
                } );
        }

        //only return at maximum the number of results requested by count
        if ( searchList.Count &amp;gt; count )
            searchList = searchList.GetRange( 0, count );

        return searchList.ToArray();
    }
}
&lt;/p&gt;
&lt;p&gt;The webservice takes the first part of the prefixText (minimumPrefixLength should match the value in the autocomplete extender control) and queries the database for all matches.&amp;nbsp; It stores that result set in cache and then filters the list by prefixText if needed.&amp;nbsp; Finally it will take the top X (count is specified by the control) and return it to the control.&lt;/p&gt;
&lt;p&gt;If a user was searching for &amp;quot;automobile&amp;quot;, after typing a-u-t all possible results would be cache so that each successive letter will not hit the database.&amp;nbsp; Another database hit will be incurred when a user searches for a different 3 letter prefix.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I&amp;#39;m attaching the full sample code along with a Sql Express database that contains some huge word list I found online (to be attached later, technical difficulties).&amp;nbsp; Enjoy and try not to spend it all in one place.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=39697" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Featured/default.aspx">Featured</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Cache/default.aspx">Cache</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/AJAX/default.aspx">AJAX</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/AutoComplete/default.aspx">AutoComplete</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/HttpRuntime.Cache/default.aspx">HttpRuntime.Cache</category></item><item><title>Cold, Hard, Cache!</title><link>http://devlicio.us/blogs/alan_northam/archive/2008/03/06/cold-hard-cache.aspx</link><pubDate>Fri, 07 Mar 2008 04:04:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:39576</guid><dc:creator>anortham</dc:creator><slash:comments>9</slash:comments><description>&lt;p&gt;Don&amp;#39;t get me wrong, I really like the Asp.Net Cache (or HttpRuntime.Cache or Uncle Daddy if you want to call it that... you&amp;#39;re a little odd aren&amp;#39;t you?), but sometimes it just can&amp;#39;t be trusted.&amp;nbsp; I mean, I just gave you (the cache) my precious object a second ago and now you claim you don&amp;#39;t have it?&amp;nbsp; Did you lose it?&amp;nbsp; Did you sell it on eBay?&amp;nbsp; Did you pawn it to support your habit?&amp;nbsp; Please at least tell me you got a decent price for it.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;One of the great things about the cache is also what makes it so untrustworthy. &amp;nbsp; Objects stored there are referenced with &lt;a href="http://msdn2.microsoft.com/en-us/library/system.weakreference.aspx" target="_blank"&gt;WeakReference&lt;/a&gt; so if your sever starts getting low on memory GC will collect objects from the cache to free some up.&amp;nbsp; Also take into account that if you put an object in Cache and set it to expire after X minutes, when you go back to retreive it, do you really know how long it&amp;#39;s been?&lt;/p&gt;
&lt;p&gt;So what we want is a way to tell the cache &amp;quot;I want this specific object (a yellow Tonka dumptruck, metal, not plastic) and if you don&amp;#39;t have it, here are instructions on how to get it&amp;quot;.&lt;/p&gt;
&lt;p&gt;Something like this:&lt;/p&gt;
&lt;p&gt;

using System;
using System.Reflection;
using System.Web;
using System.Web.Caching;
using log4net;
public delegate bool Factory&amp;lt;T&amp;gt;( out T instance );
public class CacheHelper
{
    private static readonly ILog log =
        LogManager.GetLogger(
            MethodBase.GetCurrentMethod().DeclaringType );

    private static readonly Cache cache = HttpRuntime.Cache;
    private CacheHelper(){}

    public static T GetFromCache&amp;lt;T&amp;gt;(string key, int cacheTimeInMinutes, Factory&amp;lt;T&amp;gt; retrieveMethod) where T:class
    {
        T target = cache[key] as T;
        if(target == null)
        {
            log.Info( &amp;quot;Cache miss for key:&amp;quot; + key + &amp;quot;  type:&amp;quot; + typeof(T));
            if(retrieveMethod(out target))
            {
                cache.Insert( key, target, null, DateTime.Now.AddMinutes( cacheTimeInMinutes ),
                    Cache.NoSlidingExpiration, CacheItemPriority.Normal, OnRemove );
            }            
        }
        else
        {
            log.Info( &amp;quot;Cache hit for key:&amp;quot; + key + &amp;quot;  type:&amp;quot; + typeof(T));
        }
        return target;
    }

    public static void OnRemove( string key, object cacheItem, CacheItemRemovedReason reason )
    {
        log.Info( &amp;quot;Object removed from cache: Key-&amp;quot; + key + &amp;quot;: Reason-&amp;quot; + reason);
    }

    public static void RemoveFromCache(string key)
    {
        cache.Remove( key );
    }
}&lt;/p&gt;
&lt;p&gt;
Usage would look like this:
&lt;/p&gt;
&lt;p&gt;
List&amp;lt;string&amp;gt; searchList = CacheHelper.GetFromCache&amp;lt;List&amp;lt;string&amp;gt;&amp;gt;(
            key,
            5,
            delegate( out List&amp;lt;string&amp;gt; instance ) { return SomeClass.GetSearchList( key, out instance ); } );
&lt;/p&gt;
&lt;p&gt;
I call it the code equivalent of &amp;quot;Trust but verify&amp;quot;.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=39576" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/ASP.NET/default.aspx">ASP.NET</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Cache/default.aspx">Cache</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/HttpRuntime.Cache/default.aspx">HttpRuntime.Cache</category></item><item><title>ADO.NET, Nullable Types, Casting DBNull and You</title><link>http://devlicio.us/blogs/alan_northam/archive/2008/03/06/ado-net-nullable-types-casting-dbnull-and-you.aspx</link><pubDate>Fri, 07 Mar 2008 03:21:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:39575</guid><dc:creator>anortham</dc:creator><slash:comments>10</slash:comments><description>&lt;p&gt;I know this may be a little too scary for some of you so I apologize in advance.&amp;nbsp; Take a deep breath and try to imagine that you can&amp;#39;t use NHibernate and you&amp;#39;re stuck using ADO.NET (circa 2001, did they even have computers back then?).&amp;nbsp;&lt;/p&gt;
&lt;p&gt;If you&amp;#39;ve ever tried to read the value from a column in a datarow, you&amp;#39;ve probably run into something like this (a quick Google search will bring up page after page of variations):&lt;/p&gt;
&lt;p&gt;
myValue = (int)row[&amp;quot;ColumnName&amp;quot;]; //wait, what if it&amp;#39;s null?
if( row[&amp;quot;ColumnName&amp;quot;] == DBNull.Value)
    myValue = 0; //or maybe null if myValue is nullable int?
else
    myValue = Convert.ToInt32(row[&amp;quot;ColumnName&amp;quot;]); 
//lot of code for something simple, hope I don&amp;#39;t have to do this too many times...
//what about
if(row.IsNull(&amp;quot;ColumnName&amp;quot;))
//blah blah blah
&lt;/p&gt;
&lt;p&gt;
Wow, that&amp;#39;s ugly.  What if I have several nullable columns?  What if I have a lot of nullable columns?  There has to be a better way.
&lt;/p&gt;
&lt;p&gt;Let&amp;#39;s suppose I have a class MyClass (original huh?) and it has a nullable DateTime property and a nullable integer property.  
&lt;br /&gt;
//snip from MyClass
public DateTime? Property1;
public int? Property2;
//end snip
//some contrived ado.net code
List&amp;lt;MyClass&amp;gt; list = new List&amp;lt;MyClass&amp;gt;();
foreach(DataRow row in dataTable.Rows)
{
    MyClass instance = new MyClass();
    instance.Property1 = row[&amp;quot;Column1&amp;quot;] as DateTime?;
    instance.Property2 = row[&amp;quot;Column2&amp;quot;] as int?;
    list.Add(instance);
}
&lt;/p&gt;
&lt;p&gt;
&lt;br /&gt;
I like a good one line solution.&amp;nbsp; Of course, you really can&amp;#39;t cast DBNull.Value (which would be the value of row[&amp;quot;ColumnX&amp;quot;]&amp;nbsp; if the column is null in the database) as a nullable int (or DateTime?).&amp;nbsp; (edit: thanks Chris) The cast above is actually failing but casting with &amp;quot;as&amp;quot; doesn&amp;#39;t throw an exception and returns a null value which is just what we want.&lt;/p&gt;
&lt;p&gt;&amp;quot;as&amp;quot;... you&amp;#39;re my hero...*sniff*&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=39575" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Casting/default.aspx">Casting</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/ADO.NET/default.aspx">ADO.NET</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Nullable+Types/default.aspx">Nullable Types</category></item><item><title>Databinding performance tip in ASP.NET</title><link>http://devlicio.us/blogs/alan_northam/archive/2007/10/08/databinding-performance-tip-in-asp-net.aspx</link><pubDate>Mon, 08 Oct 2007 15:14:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:38637</guid><dc:creator>anortham</dc:creator><slash:comments>5</slash:comments><description>&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In my &lt;a href="http://devlicio.us/blogs/alan_northam/archive/2007/10/07/casting-options-in-c.aspx" target="_blank"&gt;last post&lt;/a&gt; I mentioned the use of C style casting when databinding in ASP.NET.&amp;nbsp;&amp;nbsp;That got me thinking about the performance differences between the two main ways to bind data in controls with custom templates (GridView, DataList, Repeater, etc).&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In my example I&amp;#39;m using a DataList and by default, Visual Studio will bind the data to your template controls using the &amp;quot;Eval&amp;quot; method.&lt;/p&gt;
&lt;p&gt;&amp;lt;asp:Label ID=&amp;quot;FirstNameLabel&amp;quot; runat=&amp;quot;server&amp;quot; Text=&amp;#39;&amp;lt;%# Eval(&amp;quot;FirstName&amp;quot;) %&amp;gt;&amp;#39;&amp;gt;&amp;lt;/asp:Label&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; This method uses reflection and can be considerably slower depending on the complexity of your template and the number of properties you are binding.&amp;nbsp; The attached code uses a very simple DataList with simple data.&amp;nbsp; To see the difference in performance you&amp;#39;ll need to increase the size of the data using the&amp;nbsp;drop down list&amp;nbsp;at the top.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Compare the performance using&amp;nbsp;the &amp;quot;Eval&amp;quot;&amp;nbsp;method to using the C style cast to access your object&amp;#39;s properties.&lt;/p&gt;
&lt;p&gt;&amp;lt;asp:Label ID=&amp;quot;FirstNameLabel&amp;quot; runat=&amp;quot;server&amp;quot; Text=&amp;#39;&amp;lt;%# ((Person)DataBinder.GetDataItem(Container)).FirstName %&amp;gt;&amp;#39;&amp;gt;&amp;lt;/asp:Label&amp;gt; &lt;/p&gt;
&lt;p&gt;EDIT:&amp;nbsp; As Bill pointed out in the comments, the call to DataBinder.GetDataItem() isn&amp;#39;t necessary as you have access through the container already.&amp;nbsp; I&amp;#39;ve updated the attached test code to include all three methods.&amp;nbsp; These last two being equal in performance in my testing.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&amp;lt;asp:Label ID=&amp;quot;FirstNameLabel&amp;quot; runat=&amp;quot;server&amp;quot; Text=&amp;#39;&amp;lt;%# ((Person)Container.DataItem).FirstName %&amp;gt;&amp;#39;&amp;gt;&amp;lt;/asp:Label&amp;gt; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In my testing this method (the last two methods, actually)&amp;nbsp;was (were)&amp;nbsp;3 - 4 times faster.&amp;nbsp; As I said, this depends on the complexity of your control.&amp;nbsp; &lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=38637" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us" length="35842" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Casting/default.aspx">Casting</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Databinding/default.aspx">Databinding</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/ASP.NET/default.aspx">ASP.NET</category></item><item><title>Casting options in C#</title><link>http://devlicio.us/blogs/alan_northam/archive/2007/10/07/casting-options-in-c.aspx</link><pubDate>Sun, 07 Oct 2007 19:27:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:38628</guid><dc:creator>anortham</dc:creator><slash:comments>9</slash:comments><description>&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; What is the best way to cast from one type to another in C#?&amp;nbsp; This question came up at work last week while I was looking through some older code.&amp;nbsp; The code in question was using the C style casting syntax.&amp;nbsp; I have started to use the &amp;quot;as&amp;quot; style cast more often and rewrote it.&amp;nbsp; Then I decided to do some research into the differences between the two styles to find out if one really is better than the other.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The most obvious difference is that a C style case will throw and exception if the cast fails and the &amp;quot;as&amp;quot; style cast will simply return null.&amp;nbsp; So first you need to take into consideration what these differences will have on your code.&amp;nbsp; Will you need to wrap every cast in try/catch blocks?&amp;nbsp; Not if you use the &amp;quot;as&amp;quot; style, but you will need to check for null.&amp;nbsp; What about performance?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; I read a dozen or so blog posts on the subject and they seemed to be pretty evenly divided with half insisting that one style was obviously superior and the other half convinced their chosen style was better.&amp;nbsp; That didn&amp;#39;t really help so I decided to do some testing on my own.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; I&amp;#39;ve attached a small test project for reference, it will allow you to select the number of casts to perform and the style and return the total time and average for each cast.&amp;nbsp; First let&amp;#39;s see what the difference looks like in IL (o is of type object in these examples).&lt;/p&gt;
&lt;p&gt;

((Person) o).Name
becomes:
IL_0036:  castclass  CastTest.Person
Person p = o as Person;
becomes:
IL_0036:  isinst     CastTest.Person
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;So there is a difference at the IL level but is one a better performer?&amp;nbsp; I wrote three different test projects, the last of which you will find attached to this post.&amp;nbsp; Why did I write three?&amp;nbsp; Because with each test I was convinced that my results must be skewed because I was not seeing the&amp;nbsp; performance difference I expected.&amp;nbsp; I ran test casting 100,000, 1,000,000, 10,000,000 and 100,000,000 objects many times in difference orders, restarting the application between tests, not restarting between tests, clicking the button with my left hand, clicking with my right hand, every combination I could think of.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; What did I discover?&amp;nbsp; It was pretty anticlimactic.&amp;nbsp; In my opinion the difference was completely negligible.&amp;nbsp; That is, negligible if you aren&amp;#39;t throwing exceptions when casting with the C style cast.&amp;nbsp; The most stable set of test results I could get were casting 1,000,000 objects.&amp;nbsp; In this case, either style averaged 10.1 seconds total and averaged 0.0101 milliseconds.&amp;nbsp; We&amp;#39;re talking about a difference of 0.00005 milliseconds per cast.&amp;nbsp; I can&amp;#39;t really get worked up over that.&amp;nbsp; Of course, if you throw exceptions for each C style cast in that test, it&amp;#39;s over 10 times slower.&amp;nbsp; That&amp;#39;s something to consider!&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;  So will I pick one over the other?&amp;nbsp; The answer is an emphatic &amp;quot;meh&amp;quot;.&amp;nbsp; In code I will probably use the &amp;quot;as&amp;quot; style.&amp;nbsp; When doing things in markup related to databinding it&amp;#39;s extremely useful to be able to use the C style cast and I will continue to do so.&lt;br /&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=38628" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us" length="75060" type="application/zip" /><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/IL/default.aspx">IL</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/C_2300_/default.aspx">C#</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Casting/default.aspx">Casting</category></item><item><title>WCF and NHibernate</title><link>http://devlicio.us/blogs/alan_northam/archive/2007/09/25/wcf-and-nhibernate.aspx</link><pubDate>Tue, 25 Sep 2007 20:27:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:38480</guid><dc:creator>anortham</dc:creator><slash:comments>7</slash:comments><description>&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; If you&amp;#39;ve tried to pass NHibernate objects over the wire using a webservice before, you know how painful it can be.&amp;nbsp; But what about WCF?&amp;nbsp; Can it ease your pain?&amp;nbsp; Well, yes, of course it can.&amp;nbsp; This wouldn&amp;#39;t be a very interesting post if the answer was no.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; There are three main issues that needed to be fixed:&amp;nbsp; serializing circular references, passing generic list to the client (and not having them converted to arrays), and serializing NHibernate/Castle proxy objects.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Serializing circular references.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; An example of a circular reference would be a User object that has a collection of Roles and each of those Role objects has a collection of User objects.&amp;nbsp; In the past (with webservices) this meant you had to decorate the offending properties with [XMLIgnore] to serialize your objects.&amp;nbsp; This meant that your object graph would be quite different over the wire.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Let&amp;#39;s not dwell on the past.&amp;nbsp; The DataContractSerializer can preserve your object references, but not by default.&amp;nbsp; You&amp;#39;re going to need to extend DataContractSerializerOperationBehavior as described &lt;a href="http://www.jameskovacs.com/blog/CommentView.aspx?guid=477b077c-e65e-4547-8289-4e1bc17b3de7" target="_blank"&gt;here&lt;/a&gt; in an excellent article by &lt;a href="http://www.jameskovacs.com/blog/" target="_blank"&gt;James Kovacs&lt;/a&gt;.&amp;nbsp; The code included with this post is built using his example.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Passing generic collections to the client.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Specifically, I&amp;rsquo;m talking about passing objects that contain collections implemented as IList&amp;lt;T&amp;gt; as is necessary to use generics with NHibernate.&amp;nbsp; This was actually a two part problem.&amp;nbsp; The default serialization in ASP.NET webservices (XMLSerializer) could not serialize an interface and even when casting to List&amp;lt;T&amp;gt; the client would see the collection as an array, not a generic list.&amp;nbsp; In WCF, the DataContractSerializer can serialize IList&amp;lt;T&amp;gt;.&amp;nbsp; Getting the client to see the collection properly requires you to generate your service proxies using the command line utility svcutil.exe (you can&amp;rsquo;t do it using the IDE in VS2005, but you will be able to in VS2008).&amp;nbsp; The command will look something&amp;nbsp;like this (notice the /ct switch, a shortened form of the switch /collectiontype):&lt;/p&gt;
&lt;p&gt;svcutil /language:cs /ct:System.Collections.Generic.List`1&amp;nbsp; /out:AdministrationClient http://localhost:3796/NHBlog.WebUI/Administration.svc&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Serializing NHibernate/Castle proxies.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; I&amp;rsquo;m going to save this topic for a separate post.&amp;nbsp; Actually, I&amp;rsquo;m still testing and getting some unexpected results that I need to quantify first.&amp;nbsp; For now, download the sample code included with this post and try it for yourself.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&lt;b&gt;Notes about the sample code.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; If this is the first time you are running this app (it&amp;rsquo;s an extension of the sample code from my previous posts) you will need to make sure and add an initial application to the &amp;ldquo;Applications&amp;rdquo; table in the database setting the application name to &amp;ldquo;NHBlog&amp;rdquo;.&amp;nbsp; This is a requirement of the custom MembershipProvider included in the sample.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; This code has been used and reused and modified many times.&amp;nbsp; As a result, it may have some rough edges in the presentation but the underlying framework should be solid.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=38480" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us" length="3377785" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/NHibernate/default.aspx">NHibernate</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/WCF/default.aspx">WCF</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Serialization/default.aspx">Serialization</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Featured/default.aspx">Featured</category></item><item><title>Custom Profile Provider with NHibernate</title><link>http://devlicio.us/blogs/alan_northam/archive/2007/08/09/custom-profile-provider-with-nhibernate.aspx</link><pubDate>Thu, 09 Aug 2007 13:29:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:37508</guid><dc:creator>anortham</dc:creator><slash:comments>9</slash:comments><description>&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; I&amp;#39;ve updated the NHibernate blog example code to include a custom profile provider.&amp;nbsp; This provider stores the profile information using the XML data type in SQL Server 2005.&amp;nbsp; New profile properties can be added to the web.config file in same way as the Microsoft SqlProfileProvider.&amp;nbsp; The included web.config contains examples showing how to add new properties and their types.&amp;nbsp;  If adding a custom type be sure to include the full type name (i.e. NHBlog.BusinessEntities.Security.Application.).&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The example now includes custom NHibernate based providers for Membership, Roles, and Profiles.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=37508" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us" length="4151325" type="application/zip" /><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/NHibernate/default.aspx">NHibernate</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Sql+Server/default.aspx">Sql Server</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Tutorial/default.aspx">Tutorial</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/ProfileProvider/default.aspx">ProfileProvider</category></item><item><title>Getting Started with NHibernate: Part IV</title><link>http://devlicio.us/blogs/alan_northam/archive/2007/07/26/getting-started-with-nhibernate-part-iv.aspx</link><pubDate>Thu, 26 Jul 2007 20:07:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:35358</guid><dc:creator>anortham</dc:creator><slash:comments>11</slash:comments><description>&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; I&amp;#39;ve made some major changes to the blog application example.&amp;nbsp; The users and roles now use custom membership and role providers  that supports NHibernate.&amp;nbsp; Session context is maintained with a custom implementation of ICurrentSessionContext (a new NHibernate 1.2 feature).&amp;nbsp; The session and session factory management classes have also undergone some minor modifications.&amp;nbsp; I&amp;#39;ve also included a very basic web user interface that uses Ajax for Asp.Net (previously Atlas).&amp;nbsp; I&amp;#39;ll cover some of these topics in more detail in upcoming posts.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The attached zip file contains the VS2005 solution and a SQL script to generate the database schema (SQL 2005 or SQL Express 2005 only).&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=35358" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us" length="3421081" type="application/x-zip-compressed" /><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/NHibernate/default.aspx">NHibernate</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Sql+Server/default.aspx">Sql Server</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Tutorial/default.aspx">Tutorial</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/MembershipUser/default.aspx">MembershipUser</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/RoleProvider/default.aspx">RoleProvider</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/MembershipProvider/default.aspx">MembershipProvider</category></item><item><title>Getting Started with NHibernate: Part III - Updated</title><link>http://devlicio.us/blogs/alan_northam/archive/2007/05/30/getting-started-with-nhibernate-part-iii-updated.aspx</link><pubDate>Wed, 30 May 2007 19:49:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:26912</guid><dc:creator>anortham</dc:creator><slash:comments>0</slash:comments><description>&lt;p&gt;I&amp;#39;ve updated the mapping files for Comment and BlogPost in &lt;a href="http://devlicio.us/blogs/alan_northam/archive/2007/05/23/getting-started-with-nhibernate-part-iii.aspx" title="Getting Started with NHibernate: Part III"&gt;Part III&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The changes are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The named query GetCommentsByBlogPostID has been moved into the BlogPost.hbm.xml file, it just makes more sense for it to be there.&lt;/li&gt;
&lt;li&gt;&amp;lt;loader query-ref=&amp;quot;GetCommentsByBlogPostID&amp;quot;/&amp;gt; was added to the Comments collection mapping in the BlogPost.hbm.xml file, NHibernate will use this query when loading the collection.&lt;/li&gt;
&lt;li&gt; cascade=&amp;quot;delete&amp;quot;, and inverse=&amp;quot;true&amp;quot; attributes were added to the Comments collection mapping in the BlogPost.hbm.xml file, the combination of these two setting ensure that when a BlogPost is deleted all of the comments associated with it will also be deleted.&amp;nbsp; It is unlikely that you would want to delete a BlogPost and all it&amp;#39;s comments in a live blog application (although you might want to archive or hide them) but here it serves the purpose of demonstrating these attributes usage.&lt;/li&gt;
&lt;li&gt;The Comment mapping file (Comment.hbm.xml) was updated to include a stored procedure call for loading comment entities by ID.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These changes will be covered in greater detail as the application progresses.&amp;nbsp; Part IV is coming soon and will include all updates, source code, and SQL Express database.&lt;br /&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=26912" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/NHibernate/default.aspx">NHibernate</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Sql+Server/default.aspx">Sql Server</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Tutorial/default.aspx">Tutorial</category></item><item><title>Getting Started with NHibernate: Part III</title><link>http://devlicio.us/blogs/alan_northam/archive/2007/05/23/getting-started-with-nhibernate-part-iii.aspx</link><pubDate>Wed, 23 May 2007 18:11:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:26324</guid><dc:creator>anortham</dc:creator><slash:comments>13</slash:comments><description>&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; When mapping objects to the database in NHibernate you can either use XML files or decorate your classes with mapping attributes (NHibernate.Mapping.Attributes).&amp;nbsp; I&amp;#39;ve used both but I usually choose XML files simply as a matter of personal preference.&amp;nbsp; Either method works well and both provide many options for defining the relationship between class and table and configuring it&amp;#39;s function.&amp;nbsp; I&amp;#39;ll be using XML files in this tutorial but may work in some mapping attributes later in the process.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; To get intellisense working with the mapping files you can copy the nhibernate-*.xsd files from the NHibernate source (NHibernate\src\NHibernate\) to C:\Program Files\Microsoft Visual Studio 8\Xml\Schemas (or wherever you installed VS).&amp;nbsp; There are a few tools that can help by generating the mapping files based on an existing database schema, one that I&amp;#39;ve had the most success with is &lt;a href="http://www.mygenerationsoftware.com" target="_blank"&gt;MyGeneration&lt;/a&gt; (try the template by lujan99).&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; As I go through each mapping I&amp;#39;ll point out how certain features work but for detailed information on the available options check the &lt;a href="http://www.hibernate.org/hib_docs/nhibernate/html_single/#mapping-declaration" target="_blank"&gt;official documentation here&lt;/a&gt;.&amp;nbsp; Each of these mapping files will follow the naming convention classname.hbm.xml as this is what NHibernate expects to find when the SessionFactory is initialized (more on this in Part IV).&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;BlogPost mapping:&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;
&amp;lt;hibernate-mapping xmlns=&amp;quot;urn:nhibernate-mapping-2.2&amp;quot; 
      assembly=&amp;quot;NHBlog.Domain&amp;quot; namespace=&amp;quot;NHBlog.Domain&amp;quot;&amp;gt;
  &amp;lt;class name=&amp;quot;BlogPost&amp;quot; table=&amp;quot;BlogPost&amp;quot;&amp;gt;
    &amp;lt;id name=&amp;quot;ID&amp;quot; column=&amp;quot;ID&amp;quot; type=&amp;quot;int&amp;quot;&amp;gt;
      &amp;lt;generator class=&amp;quot;native&amp;quot; /&amp;gt;
    &amp;lt;/id&amp;gt;
    &amp;lt;property name=&amp;quot;Title&amp;quot; column=&amp;quot;Title&amp;quot; type=&amp;quot;string&amp;quot; not-null=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;property name=&amp;quot;Body&amp;quot; column=&amp;quot;Body&amp;quot; type=&amp;quot;string&amp;quot; not-null=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;property name=&amp;quot;PublishedOn&amp;quot; column=&amp;quot;PublishedOn&amp;quot; type=&amp;quot;DateTime&amp;quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;many-to-one name=&amp;quot;PublishedBy&amp;quot; column=&amp;quot;PublishedByID&amp;quot; class=&amp;quot;BlogUser&amp;quot; not-null=&amp;quot;true&amp;quot; /&amp;gt;
    &amp;lt;bag name=&amp;quot;Comments&amp;quot; cascade=&amp;quot;delete&amp;quot; inverse=&amp;quot;true&amp;quot; &amp;gt;
      &amp;lt;key column=&amp;quot;BlogPostID&amp;quot; /&amp;gt;
      &amp;lt;one-to-many class=&amp;quot;Comment&amp;quot; /&amp;gt;
      &amp;lt;loader query-ref=&amp;quot;GetCommentsByBlogPostID&amp;quot;/&amp;gt;
    &amp;lt;/bag&amp;gt;
  &amp;lt;/class&amp;gt;
  &amp;lt;sql-query name=&amp;quot;GetCommentsByBlogPostID&amp;quot;&amp;gt;
    &amp;lt;load-collection alias=&amp;quot;Comments&amp;quot; role=&amp;quot;BlogPost.Comments&amp;quot; /&amp;gt;
    exec GetCommentsByBlogPostID :blogPostID
  &amp;lt;/sql-query&amp;gt;
&amp;lt;/hibernate-mapping&amp;gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; At the beginning of the file I&amp;#39;m setting the assembly and namespace values.&amp;nbsp; They aren&amp;#39;t required, but if they are not set you will need to fully qualify any class names used including the assembly ( i.e., NHBlog.Domain.BlogPost, NHBlog.Domain).&amp;nbsp; The class element tells NHibernate what the name of the class is and which table that class maps to, in this case both are named BlogPost.&amp;nbsp; The id element defines the primary key of the table and which property in the class it maps to.&amp;nbsp; It&amp;#39;s also includes the type (.net data type) and which class is generating these values.&amp;nbsp; NHibernate includes many different &lt;a href="http://www.hibernate.org/hib_docs/nhibernate/html_single/#mapping-declaration-id-generator" target="_blank"&gt;generator&lt;/a&gt; classes.&amp;nbsp; In our example we are using the identity function in SQL Server so the generator is set to native.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Each BlogPost will also have a collection of Comments seen here mapped using the bag element.&amp;nbsp; This mapping is a bit different than normal in that the&amp;lt;loader query-ref=&amp;quot;GetCommentsByBlogPostID&amp;quot;/&amp;gt; attribute specifies which query to use to load the collection of comments, in this case a stored
procedure.&amp;nbsp; At the bottom of the file a
sql-query is defined to execute the stored procedure
GetCommentsByBlogPostID and pass in the value blogPostID.&amp;nbsp; The
load-collection element instructs NHibernate what type of entities to expect as the result of this query.
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Why am I using a stored procedure here?&amp;nbsp; I don&amp;#39;t have to, I
could load the collection like any other but doing it this way serves
two purposes; to demonstrate the use of stored procedures (a new
feature in NHibernate 1.2), and to assist in loading the comments in a
threaded conversational manner (see the requirements in &lt;a href="http://devlicio.us/blogs/alan_northam/archive/2007/05/22/getting-started-with-nhibernate-part-ii.aspx" target="_blank"&gt;Part II&lt;/a&gt;).&amp;nbsp;
GetCommentsByBlogPost uses a feature in Sql Server 2005 (and Sql
Express 2005) called Common Table Expressions.&amp;nbsp; More information can be
found &lt;a href="http://msdn2.microsoft.com/en-us/library/ms345144.aspx" target="_blank"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;BlogUser mapping:&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;
&amp;lt;hibernate-mapping xmlns=&amp;quot;urn:nhibernate-mapping-2.2&amp;quot; 
      assembly=&amp;quot;NHBlog.Domain&amp;quot; namespace=&amp;quot;NHBlog.Domain&amp;quot;&amp;gt;
  &amp;lt;class name=&amp;quot;BlogUser&amp;quot; table=&amp;quot;BlogUser&amp;quot;&amp;gt;
    &amp;lt;id name=&amp;quot;ID&amp;quot; column=&amp;quot;ID&amp;quot; type=&amp;quot;int&amp;quot;&amp;gt;
      &amp;lt;generator class=&amp;quot;native&amp;quot; /&amp;gt;
    &amp;lt;/id&amp;gt;
    &amp;lt;property name=&amp;quot;FirstName&amp;quot; column=&amp;quot;FirstName&amp;quot; type=&amp;quot;string&amp;quot; not-null=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;property name=&amp;quot;LastName&amp;quot; column=&amp;quot;LastName&amp;quot; type=&amp;quot;string&amp;quot; not-null=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;property name=&amp;quot;Alias&amp;quot; column=&amp;quot;Alias&amp;quot; type=&amp;quot;string&amp;quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;property name=&amp;quot;EmailAddress&amp;quot; column=&amp;quot;EmailAddress&amp;quot; type=&amp;quot;string&amp;quot; not-null=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;property name=&amp;quot;CreatedOn&amp;quot; column=&amp;quot;CreatedOn&amp;quot; type=&amp;quot;DateTime&amp;quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;bag name=&amp;quot;BlogPosts&amp;quot;&amp;gt;
      &amp;lt;key column=&amp;quot;PublishedByID&amp;quot; /&amp;gt;
      &amp;lt;one-to-many class=&amp;quot;BlogPost&amp;quot; /&amp;gt;
    &amp;lt;/bag&amp;gt;
    &amp;lt;bag name=&amp;quot;Comments&amp;quot;&amp;gt;
      &amp;lt;key column=&amp;quot;MadeByID&amp;quot; /&amp;gt;
      &amp;lt;one-to-many class=&amp;quot;Comment&amp;quot; /&amp;gt;
    &amp;lt;/bag&amp;gt;
    &amp;lt;bag name=&amp;quot;BlogRoles&amp;quot; table=&amp;quot;UserRole&amp;quot;&amp;gt;
      &amp;lt;key column=&amp;quot;BlogUserID&amp;quot; /&amp;gt;
      &amp;lt;many-to-many class=&amp;quot;BlogRole&amp;quot; column=&amp;quot;BlogRoleID&amp;quot; /&amp;gt;
    &amp;lt;/bag&amp;gt;
  &amp;lt;/class&amp;gt;
&amp;lt;/hibernate-mapping&amp;gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In BlogUser we have three collections mapped; BlogPosts, Comments, and BlogRoles.&amp;nbsp; The first two are one-to-many relationships meaning that a single BlogUser can have posted many BlogPosts and made many Comments.&amp;nbsp; The last is a many-to-many relationship meaning that a BlogUser can belong to many BlogRoles and a BlogRole can contain many BlogUsers.&amp;nbsp; The table UserRole defines this relationship in the database.&amp;nbsp; The mapping instructs NHibernate what type of class makes up this collection, which table to use to look up the collection members and which column holds the key for each.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;BlogRole mapping:&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;
&amp;lt;hibernate-mapping xmlns=&amp;quot;urn:nhibernate-mapping-2.2&amp;quot; 
      assembly=&amp;quot;NHBlog.Domain&amp;quot; namespace=&amp;quot;NHBlog.Domain&amp;quot;&amp;gt;
  &amp;lt;class name=&amp;quot;BlogRole&amp;quot; table=&amp;quot;BlogRole&amp;quot;&amp;gt;
    &amp;lt;id name=&amp;quot;ID&amp;quot; column=&amp;quot;ID&amp;quot; type=&amp;quot;int&amp;quot;&amp;gt;
      &amp;lt;generator class=&amp;quot;native&amp;quot; /&amp;gt;
    &amp;lt;/id&amp;gt;
    &amp;lt;property name=&amp;quot;Name&amp;quot; column=&amp;quot;Name&amp;quot; type=&amp;quot;string&amp;quot; not-null=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;bag name=&amp;quot;BlogUsers&amp;quot; table=&amp;quot;UserRole&amp;quot;&amp;gt;
      &amp;lt;key column=&amp;quot;BlogRoleID&amp;quot; /&amp;gt;
      &amp;lt;many-to-many class=&amp;quot;BlogUser&amp;quot; column=&amp;quot;BlogUserID&amp;quot; /&amp;gt;
    &amp;lt;/bag&amp;gt;
  &amp;lt;/class&amp;gt;
&amp;lt;/hibernate-mapping&amp;gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; BlogRole has a collection of BlogUsers which represents the other side of the many-to-many relationship defined in BlogUser.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp; &lt;b&gt;Comment mapping:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;
&amp;lt;hibernate-mapping xmlns=&amp;quot;urn:nhibernate-mapping-2.2&amp;quot;
      assembly=&amp;quot;NHBlog.Domain&amp;quot; namespace=&amp;quot;NHBlog.Domain&amp;quot;&amp;gt;
  &amp;lt;class name=&amp;quot;Comment&amp;quot; table=&amp;quot;Comment&amp;quot;&amp;gt;
    &amp;lt;id name=&amp;quot;ID&amp;quot; column=&amp;quot;ID&amp;quot; type=&amp;quot;int&amp;quot;&amp;gt;
      &amp;lt;generator class=&amp;quot;native&amp;quot; /&amp;gt;
    &amp;lt;/id&amp;gt;
    &amp;lt;property name=&amp;quot;Subject&amp;quot; column=&amp;quot;Subject&amp;quot; type=&amp;quot;string&amp;quot; not-null=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;property name=&amp;quot;Body&amp;quot; column=&amp;quot;Body&amp;quot; type=&amp;quot;string&amp;quot; not-null=&amp;quot;true&amp;quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;property name=&amp;quot;MadeOn&amp;quot; column=&amp;quot;MadeOn&amp;quot; type=&amp;quot;DateTime&amp;quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;many-to-one name=&amp;quot;MadeBy&amp;quot; column=&amp;quot;MadeByID&amp;quot; class=&amp;quot;BlogUser&amp;quot; not-null=&amp;quot;true&amp;quot; /&amp;gt;
    &amp;lt;many-to-one name=&amp;quot;InReplyTo&amp;quot; column=&amp;quot;InReplyToID&amp;quot; class=&amp;quot;Comment&amp;quot; /&amp;gt;
    &amp;lt;many-to-one name=&amp;quot;BlogPost&amp;quot; column=&amp;quot;BlogPostID&amp;quot; class=&amp;quot;BlogPost&amp;quot; not-null=&amp;quot;true&amp;quot; /&amp;gt;
    &amp;lt;bag name=&amp;quot;Replies&amp;quot;&amp;gt;
      &amp;lt;key column=&amp;quot;InReplyToID&amp;quot; /&amp;gt;
      &amp;lt;one-to-many class=&amp;quot;Comment&amp;quot; /&amp;gt;
    &amp;lt;/bag&amp;gt;
    &amp;lt;property name=&amp;quot;IsVisible&amp;quot; column=&amp;quot;IsVisible&amp;quot; type=&amp;quot;Boolean&amp;quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;property name=&amp;quot;Depth&amp;quot; column=&amp;quot;Depth&amp;quot; type=&amp;quot;int&amp;quot; insert=&amp;quot;false&amp;quot; update=&amp;quot;false&amp;quot;&amp;gt;&amp;lt;/property&amp;gt;
    &amp;lt;loader query-ref=&amp;quot;GetCommentByID&amp;quot;/&amp;gt;
  &amp;lt;/class&amp;gt;
  &amp;lt;sql-query name=&amp;quot;GetCommentByID&amp;quot;&amp;gt;
    &amp;lt;return class=&amp;quot;Comment&amp;quot;&amp;gt;&amp;lt;/return&amp;gt;
    exec GetCommentByID :id
  &amp;lt;/sql-query&amp;gt;
&amp;lt;/hibernate-mapping&amp;gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; A Comment has a reference to the BlogUser who made it (MadeBy), the Comment it is replying to (InReplyTo), if any, the BlogPost it is a comment on (BlogPost), and a collection of comments replying to it (Replies).&amp;nbsp; Also, notice the &amp;quot;Depth&amp;quot; property doesn&amp;#39;t allow inserting or updating of this value.&amp;nbsp; That&amp;#39;s because this value/column doesn&amp;#39;t actually exist in the database, it&amp;#39;s generated when loading a collection of comments.&amp;nbsp; If you load an individual Comment this value will always be zero.&amp;nbsp; This mapping is also using a stored procedure but in this case it will be used when loading a comment by id.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;GetCommentsByBlogPostID stored procedure code:&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;
CREATE PROCEDURE [dbo].[GetCommentsByBlogPostID] 
(
	@blogPostID int = 0
)
AS
	
SET NOCOUNT ON;
WITH CommentList ( ID, [Subject], Body, MadeOn, 
			        MadeByID, InReplyToID, BlogPostID, 
					IsVisible, Depth, sortcol) 
AS 
( SELECT  ID, [Subject], Body, MadeOn, 
  MadeByID, InReplyToID, BlogPostID, IsVisible, 0, CAST(ID AS VARBINARY(900)) 
FROM    Comment
WHERE   (InReplyToID IS NULL) AND (BlogPostID = @blogPostID)
                              
UNION ALL
                              
SELECT  c.ID, c.Subject, c.Body, c.MadeOn, 
  c.MadeByID, c.InReplyToID, c.BlogPostID, c.IsVisible, cl.depth + 1, 
      CAST(cl.sortcol + CAST(c.ID AS BINARY(4)) AS VARBINARY(900))
FROM    Comment AS c INNER JOIN
      CommentList AS cl ON c.InReplyToID = cl.ID)
               
SELECT  ID, [Subject], Body, MadeOn, 
  MadeByID, InReplyToID, BlogPostID, IsVisible, Depth
FROM    CommentList
ORDER BY sortcol
	              
RETURN
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;b&gt;GetCommentByID stored procedure code:&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;
CREATE PROCEDURE dbo.GetCommentByID(
@id int
)
AS
SET NOCOUNT ON
SELECT ID, Subject, Body, MadeOn, MadeByID, InReplyToID, BlogPostID, IsVisible, 0 as Depth
FROM Comment
WHERE ID = @id
RETURN

&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In Part IV we will configure NHibernate and begin building the supporting framework needed to use what we have done so far.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=26324" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us" length="228798" type="application/zip" /><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/NHibernate/default.aspx">NHibernate</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Sql+Server/default.aspx">Sql Server</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Tutorial/default.aspx">Tutorial</category></item><item><title>Getting Started with NHibernate: Part II</title><link>http://devlicio.us/blogs/alan_northam/archive/2007/05/22/getting-started-with-nhibernate-part-ii.aspx</link><pubDate>Wed, 23 May 2007 01:26:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:26234</guid><dc:creator>anortham</dc:creator><slash:comments>4</slash:comments><description>&lt;div class="ExternalClass290CB33CC9034E9F9D9E0EA6EFAED5FA"&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; While writing the code necessary for this installment, I found myself 
falling prey to feature-creep.&amp;nbsp; So I&amp;#39;ve decided to keep it fairly simple in the 
beginning.&amp;nbsp; However, once the basic components are working I&amp;#39;ll start 
introducing more features.&amp;nbsp; I thought this might be a good way to demonstrate 
what is and isn&amp;#39;t required to add new functionality to a working NHibernate 
application.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The application&amp;#39;s initial functionality will consist of blog users being 
able to post new blog posts, comment on posts,&amp;nbsp; and reply to other comments.&amp;nbsp; 
Only users with the correct role membership will be able to post, all users will 
be able to comment and reply to comments.&amp;nbsp; Also, the comments should be threaded 
so conversations can be followed more easily.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The domain model has just 4 classes (for now):&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;img src="http://devlicio.us/photos/devlicious/images/26312/original.aspx" title="NHBlog UML diagram" alt="NHBlog UML diagram" height="376" width="375" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; The Sql Express 2005 database&amp;nbsp;will have 5 tables&amp;nbsp;persisting our 4 
classes.&amp;nbsp; The extra database table&amp;nbsp;UserRole&amp;nbsp;will persist the many-to-many 
relationship between BlogUser and BlogRole.&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://devlicio.us/photos/devlicious/images/26313/original.aspx" title="NHBlog database diagram" alt="NHBlog database diagram" height="561" width="430" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Also notice that the&amp;nbsp;&amp;quot;Depth&amp;quot; property in the Comment class is not 
actually persisted, it is a read-only value that is generated when a collection 
of comments for a BlogPost is loaded and represents the&amp;nbsp;level of the comment in 
the comment hierarchy (threaded convesations!).&amp;nbsp; See the attachment for the database script.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In Part III we will create the mapping glue that binds the model and 
database together.&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=26234" width="1" height="1"&gt;</description><enclosure url="http://devlicio.us" length="1722" type="application/zip" /><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/NHibernate/default.aspx">NHibernate</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Tutorial/default.aspx">Tutorial</category></item><item><title>Getting Started with NHibernate: Part I</title><link>http://devlicio.us/blogs/alan_northam/archive/2007/05/19/getting-started-with-nhibernate-part-i.aspx</link><pubDate>Sun, 20 May 2007 02:22:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:25898</guid><dc:creator>anortham</dc:creator><slash:comments>12</slash:comments><description>&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; When I first started learning and using NHibernate, I read every tutorial, downloaded every example, and studied every code snippet I could get my hands on.&amp;nbsp; There are some great resources available with one of the best being &lt;a href="http://devlicio.us/blogs/billy_mccafferty/default.aspx" target="_blank"&gt;Billy McCafferty&amp;#39;s&lt;/a&gt; &lt;a href="http://www.codeproject.com/aspnet/NHibernateBestPractices.asp" target="_blank"&gt;NHibernate Best Practices.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In my opinion, the majority of the resources available fall into one of three categories:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Articles that expect and require some familiarity with NHibernate.&lt;/li&gt;
&lt;li&gt;Articles or snippets/sample code that are written at such a low level, you&amp;#39;re left wondering how the technique demonstrated would be implemented in real world code.&lt;/li&gt;
&lt;li&gt;Open source code that dissecting and learning from would be a daunting and tedious task for users new to the concept of NHibernate.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; Each of the resources I refer to provide a lot of useful information.&amp;nbsp; However, I like to learn by doing and I think a tutorial that provides a step by step guide to implementing NHibernate in a real world application would be beneficial to a lot of prospective NHibernate users.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In an attempt to fill this void, this is the first article in a series of many.&amp;nbsp; Each article will cover a bite-sized (byte-sized?) step in the process as we design and implement a blog.&amp;nbsp; We will finish with an application that is simple enough that we don&amp;#39;t get bogged down in unrelated topics but complex enough that in the end we will have a framework that can be used as the foundation for future projects.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; In Part II we will build our domain classes.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://devlicio.us/aggbug.aspx?PostID=25898" width="1" height="1"&gt;</description><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/NHibernate/default.aspx">NHibernate</category><category domain="http://devlicio.us/blogs/alan_northam/archive/tags/Tutorial/default.aspx">Tutorial</category></item></channel></rss>