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