Tag Archive for 'nHibernate'

How to use NHibernate Lazy Initializing Proxies with Web Services or WCF

Working with object trees is risky business when combined with remoting. Object trees often have very deep branches and circular references that will clog your pipes and overflow your stack when not handled properly.

NHibernate has addressed this same problem in the object-relational space with a very cool feature called lazy initialization, implemented using the Castle DynamicProxy library. By default, when an entity is loaded, its related entities are populated with proxies. The use of a proxy allows the entity to remain uninitialized until the moment one of its non-identifying properties is accessed, which in many cases is never – thus minimizing database queries. This strategy also eradicates the problem with loading an entire object tree from the database when only a single entity is needed.

Proxies become a problem when combined with Web services or WCF. Serialization of objects to XML requires knowledge of the data type to be serialized (accomplished with the KnownType attribute in WCF). The dynamically generated nHibernate proxies are not known to the serializer and thus a request to the service results in an exception such as System.Net.WebException: The underlying connection was closed: The connection was closed unexpectedly.

In order to make these entities safe for sending through the pipes, we must “unproxy” them and impose a limit to the object tree depth. The following utility class can be used for doing both by simply calling possiblyProxiedEntity.UnproxyObjectTree(mySessionFactory, maxDepth):

using System;
using NHibernate;
using NHibernate.Metadata;
using NHibernate.Proxy;
 
namespace Trentacular.Data.NHibernate.Util
{
    public static class NHibernateProxyUtils
    {
        /// <summary>
        /// Force initialization of a proxy or persistent collection.
        /// </summary>
        /// <param name="persistentObject">a persistable object, proxy, persistent collection or null</param>
        /// <exception cref="HibernateException">if we can't initialize the proxy at this time, eg. the Session was closed</exception>
        public static T Unproxy<T>(this T persistentObject)
        {
            var proxy = persistentObject as INHibernateProxy;
 
            if (proxy != null)
                return (T)proxy.HibernateLazyInitializer.GetImplementation();
 
            return persistentObject;
        }
 
        /// <summary>
        /// Gets the underlying class type of a persistent object that may be proxied
        /// </summary>
        public static Type GetUnproxiedType<T>(this T persistentObject)
        {
            var proxy = persistentObject as INHibernateProxy;
            if (proxy != null)
                return proxy.HibernateLazyInitializer.PersistentClass;
 
            return persistentObject.GetType();
        }
 
        /// <summary>
        /// Force initialzation of a possibly proxied object tree up to the maxDepth.
        /// Once the maxDepth is reached, entity properties will be replaced with
        /// placeholder objects having only the identifier property populated.
        /// </summary>
        public static T UnproxyObjectTree<T>(this T persistentObject, ISessionFactory sessionFactory, int maxDepth)
        {
            // Determine persistent type of the object
            var persistentType = persistentObject.GetUnproxiedType();
 
            var classMetadata = sessionFactory.GetClassMetadata(persistentType);
 
            // If we've already reached the max depth, we will return a placeholder object
            if (maxDepth < 0)
                return CreatePlaceholder(persistentObject, persistentType, classMetadata);
 
            // Now lets go ahead and make sure everything is unproxied
            var unproxiedObject = persistentObject.Unproxy();
 
            // Iterate through each property and unproxy entity types
            for (int i = 0; i < classMetadata.PropertyTypes.Length; i++)
            {
                var nhType = classMetadata.PropertyTypes[i];
                var propertyName = classMetadata.PropertyNames[i];
                var propertyInfo = persistentType.GetProperty(propertyName);
 
                // Unproxy of collections is not currently supported.  We set the collection property to null.
                if (nhType.IsCollectionType)
                {
                    propertyInfo.SetValue(unproxiedObject, null, null);
                    continue;
                }
 
                if (nhType.IsEntityType)
                {
                    var propertyValue = propertyInfo.GetValue(unproxiedObject, null);
 
                    if (propertyValue == null)
                        continue;
 
                    propertyInfo.SetValue(
                        unproxiedObject,
                        propertyValue.UnproxyObjectTree(sessionFactory, maxDepth - 1),
                        null
                        );
                }
            }
 
            return unproxiedObject;
        }
 
        /// <summary>
        /// Return an empty placeholder object with the Identifier set.  We can safely access the identifier
        /// property without the object being initialized.
        /// </summary>
        private static T CreatePlaceholder<T>(T persistentObject, Type persistentType, IClassMetadata classMetadata)
        {
            var placeholderObject = (T)Activator.CreateInstance(persistentType);
 
            if (classMetadata.HasIdentifierProperty)
            {
                var identifier = classMetadata.GetIdentifier(persistentObject, EntityMode.Poco);
                classMetadata.SetIdentifier(placeholderObject, identifier, EntityMode.Poco);
            }
 
            return placeholderObject;
        }
    }
}

There are several approaches on where and when this should take place depending on if you are using ASP.Net 2.0 Web services or WCF which I am not going to go into in this post. If you are working with WCF, Tim Scott has written about a good approach here.

nHibernate in the Enterprise

I just recently received this response regarding the use of nHibernate within the division of the company I am working with:

… [nHibernate] has alot of promise I think but [coorporate] doesn’t consider it “stable” yet …

Are you kidding me? Where do these guys get their information? I guess the Microsoft Entity Framework is stable enough though.

Lets see, nHibernate is a port of the Java Hibernate Framework which was first released on November 30, 2001 (making it almost 8 years old). The major 1.2.1 version of nHibernate was released in November 2007, improving on the already stable port of the the Hibernate framework, adapting .Net 2.0 language features.

I began using the Hibernate framework in the Fall of 2005 being introduced to it by my colleague Winston Fassett. I switched over to .Net development in the Fall of 2006, and have been using nHibernate from the start.

Having used nHibernate since before the 1.2.1 release, I can safely vouch for its stability and performance … visit http://racenation.com for an example of my most recent nHibernate project.

I can’t say that some of the surrounding projects like Linq to nHibernate, although very cool, can be considered stable, but how long does a framework need to be around and used to be considered stable?