Paul T Davies
Paul T Davies

Reputation: 2573

Inheritance and lazy loading in NHibernate

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.

Upvotes: 0

Views: 1189

Answers (3)

WriteEatSleepRepeat
WriteEatSleepRepeat

Reputation: 3143

I had a similar question, see here: fluent nhibernate polymorphism. how to check for type of class

I chose to use a solution based on the Visitor pattern

You do not need to turn off lazy loading nor use funny properties to return the self object

Upvotes: 1

Jamie Ide
Jamie Ide

Reputation: 49291

A common workaround for this issue is to add a Self property to access the non-proxied type:

public virtual Employee Self
{
   get { return this; }
}

Then you can check Bob.Self is ShopFloorEmployee.

Personally I use inheritance very sparingly and I would use a "role" property here instead of subclassing.

Upvotes: 3

khellang
khellang

Reputation: 18112

This is a common NHibernate pitfall. Try changing the Manager reference to a No proxy association.

Upvotes: 2

Related Questions