NHibernate Session Load vs Get when using Table per Hierarchy. Always use ISession.Get<T> for TPH to work.
- by Rohit Gupta
Originally posted on: http://geekswithblogs.net/rgupta/archive/2014/06/01/nhibernate-session-load-vs-get-when-using-table-per-hierarchy.aspxNHibernate ISession has two methods on it : Load and Get. Load allows the entity to be loaded lazily, meaning the actual call to the database is made only when properties on the entity being loaded is first accessed. Additionally, if the entity has already been loaded into NHibernate Cache, then the entity is loaded directly from the cache instead of querying the underlying database. ISession.Get<T> instead makes the call to the database, every time it is invoked. With this background, it is obvious that we would prefer ISession.Load<T> over ISession.Get<T> most of the times for performance reasons to avoid making the expensive call to the database. let us consider the impact of using ISession.Load<T> when we are using the Table per Hierarchy implementation of NHibernate. Thus we have base class/ table Animal, there is a derived class named Snake with the Discriminator column being Type which in this case is “Snake”. If we load This Snake entity using the Repository for Animal, we would have a entity loaded, as shown below:
public T GetByKey(object key, bool lazy = false)
{
if (lazy)
return CurrentSession.Load<T>(key);
return CurrentSession.Get<T>(key);
}
var tRepo = new NHibernateReadWriteRepository<TPHAnimal>();
var animal = tRepo.GetByKey(new Guid("602DAB56-D1BD-4ECC-B4BB-1C14BF87F47B"), true);
var snake = animal as Snake;
snake is null
As you can see that the animal entity retrieved from the database cannot be cast to Snake even though the entity is actually a snake.
The reason being ISession.Load prevents the entity to be cast to Snake and will throw the following exception:
System.InvalidCastException : Message=Unable to cast object of type 'TPHAnimalProxy' to type 'NHibernateChecker.Model.Snake'.
Thus we can see that if we lazy load the entity using ISession.Load<TPHAnimal> then we get a TPHAnimalProxy and not a snake.
===============================================================
However if do not lazy load the same cast works perfectly fine, this is since we are loading the entity from database and the entity being loaded is not a proxy. Thus the following code does not throw any exceptions, infact the snake variable is not null:
var tRepo = new NHibernateReadWriteRepository<TPHAnimal>();
var animal = tRepo.GetByKey(new Guid("602DAB56-D1BD-4ECC-B4BB-1C14BF87F47B"), false);
var snake = animal as Snake;
if (snake == null)
{
var snake22 = (Snake) animal;
}