Mike Nichols - Son of Nun Technology

Understanding NHibernate Proxies Revisited

In an earlier post I journaled some discoveries I was making while tooling around with using lazy loading in NHibernate.  Steve asked a great question that (if I understand correctly) justifies demonstrating a test to see how NHibernate delivers proxy interfaces using the 'proxy="IMyInterface"' approach:

Can you elaborate on suggestion #2 above? Making the setter protected doesn't eliminate the need to declare a setter in the interface, and if you do that, the concrete class has to make the setter public.
What am I missing here - how can this really work without exposing the property publicly through the interface?

From what I understand, NHibernate is actually returning a object that, while implementing the proxy interface you determine, it is still a subclass of the object in your mapping. A test and its output should explain all this.

First the interface..note that there are no setters:

 

namespace Cei.eMerge.Core.Domain.HumanResources

{

    public interface IJobPosition : IDomainObject<int>

    {

        string Name { get; }

        string Description { get; }

    }

}


And it's implementation:

namespace Cei.eMerge.Core.Domain.HumanResources

{

    public class JobPosition : DomainObject<int>, IJobPosition

    {

        protected  JobPosition():this(string.Empty,string.Empty)

        {

        }

        public JobPosition(string name, string description)

        {

            _name = name;

            _description = description;

        }

 

        private string _name;

        private string _description;

 

        public string Name

        {

            get { return _name; }

        }

 

        public string Description

        {

            get { return _description; }

        }

 

    }

}


My mapping...note the use of access='nosetter.camelcase-underscore' and remember that the proxy object is a SUBCLASS of JobPosition

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="@core.assembly@"   

    default-access="nosetter.camelcase-underscore">

 

  <class name="Cei.eMerge.Core.Domain.HumanResources.JobPosition"

      table="JobPosition" proxy="Cei.eMerge.Core.Domain.HumanResources.IJobPosition" lazy="true" >

 

    <id name="Id" access="property" unsaved-value="0" >

      <column name="Id"/>

      <generator class="native" />

    </id>

 

    <property name="Name">

      <column name="Name" not-null="true" unique-key="JobPositionName_Enterprise" sql-type="nvarchar(50)"/>

    </property>

 

    <property name="Description">

      <column name="Description" not-null="false" unique="false" sql-type="nvarchar(100)"/>

    </property>

 

  </class>

 

</hibernate-mapping>

Now a test

        [Test]

        public void CanProxyJobPosition()

        {

            UnitOfWork.Current.Dispose();

 

            IJobPosition jp = new JobPosition("JobTest", "BLAH");

            int jpId = 0;

            using(UnitOfWork.Start())

            {

                ISession session = ((Cei.eMerge.Common.NHibernateUnitOfWorkAdapter)UnitOfWork.Current).Session;

                session.SaveOrUpdate(jp);

                jpId = jp.Id;

            }

            using(UnitOfWork.Start())

            {

                ISession session = ((Cei.eMerge.Common.NHibernateUnitOfWorkAdapter)UnitOfWork.Current).Session;

                Console.WriteLine("Getting object...");

                object fromDb = session.Load(typeof (JobPosition), jpId);

                Console.WriteLine("Is Initialized = " + NHibernateUtil.IsInitialized(fromDb) );

                Console.WriteLine("Type of object is " + fromDb.GetType().ToString());

                Console.WriteLine("Attempting to have proxy fetch property value..");

                Console.WriteLine(((IJobPosition) fromDb).Name);

                Assert.AreEqual("JobTest",((IJobPosition)fromDb).Name);

            }

        }

And the output

NHibernate: INSERT INTO JobPosition (Name, Description) VALUES (@p0, @p1); @p0 = 'JobTest', @p1 = 'BLAH'

NHibernate: select @@IDENTITY

Getting object...

Is Initialized = False

Type of object is ProxyInterfaceSystemSystemObject_Cei_eMerge_Core_Domain_HumanResourcesIJobPosition_NHibernate_ProxyINHibernateProxy_System_Runtime_SerializationISerializable

Attempting to have proxy fetch property value..

NHibernate: SELECT jobpositio0_.Id as Id46_0_, jobpositio0_.Name as Name46_0_, jobpositio0_.Description as Descript3_46_0_ FROM JobPosition jobpositio0_ WHERE jobpositio0_.Id=@p0; @p0 = '1'

JobTest