Take the following classes:
public class Employee
{
public Employee Manager { get; set; }
}
public class ShopFloorEmployee : Employee { ... }
public class OfficeEmployee : Employee { ... }
public class Department
{
public Employee Manager { get; set; }
}
and here are the NHibernate mapping files:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="Domain.Entities"
assembly="Domain">
<class name="Employee">
<id name="Id" column="Id" type="long">
<generator class="identity"/>
</id>
<discriminator column="Type" type="string"/>
<many-to-one name="Manager" class="Employee" column="ManagerId" lazy="proxy" />
<subclass name="ShopFloorEmployee" discriminator-value="ShopFloorEmployee" extends="Employee"/>
</subclass>
<subclass name="OfficeEmployee" discriminator-value="OfficeEmployee" extends="Employee"/>
</subclass>
</class>
</hibernate-mapping>
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
namespace="Domain.Entities"
assembly="Domain">
<class name="Department">
<id name="Id" column="Id" type="long">
<generator class="identity"/>
</id>
<discriminator column="Type" type="string"/>
<many-to-one name="Manager" class="Employee" column="ManagerId" lazy="proxy" />
</class>
</hibernate-mapping>
These proxies seem to be causing me problems. For instance, if I load a Department, the Manager of that department (let's call him Bob, who is a ShopFloorEmployee) will be of type EmployeeProxy. Then, in the same session, if I specifically load a list of all ShopFloorEmployees, they will all be of type ShopFloorEmployee except Bob, who will be of type EmployeeProxy. I then can't cast Bob as a ShopFloorEmployee at all, because it has followed a different inheritance path.
The proxies are necassary to avoid recursively loading loads of Employees via their manager each time I load either a Department or Employee.
Am I doing something fundamentally wrong here, or is this a quirk of NHibernate? If it is a quirk then is there a work around? I have considered explicitly closing the session after loading the department but this seems just too hacky.