Geeks With Blogs
Rohit Gupta Engaging talk on Microsoft Technologies ....My Resume

NHibernate 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; }

Also note that if an Entity has a reference to another Entity which is part of the Table Per Hierarchy, for e.g. I have a TPHAnimal Entity and this entity self references TPHAnimal using the Parent property, as shown below:


1 public class TPHAnimal : IEntity 2 { 3 public virtual Guid Id { get; set; } 4 public virtual string FoodClassification { get; set; } 5 public virtual DateTime? BirthDate { get; set; } 6 public virtual string Genus { get; set; } 7 public virtual string Family { get; set; } 8 public virtual int RowVersion { get; set; } 9 public virtual TPHAnimal Parent { get; set; } 10 }

If such is the case, we need to insure that we dont lazy load the “Parent” reference, as shown below:

1 public class TPHAnimalMap : ClassMap<TPHAnimal> 2 { 3 public TPHAnimalMap() 4 { 5 Schema("dbo"); 6 Table("TPH_Animal"); 7 DynamicUpdate(); 8 LazyLoad(); 9 Id(x => x.Id).GeneratedBy.GuidComb().UnsavedValue(Guid.Empty); 10 DiscriminateSubClassesOnColumn("ClassType").Not.Nullable(); 11 Map(x => x.FoodClassification).Not.Nullable().Length(50); 12 Map(x => x.BirthDate).Column("BirthDate").CustomType("DateTime").Nullable(); 13 Map(x => x.Family).Column("Family").Length(50); 14 Map(x => x.Genus).Length(50); 15 References(x => x.Parent).Column("ParentId").Cascade.None().Not.LazyLoad(); 16 } 17 }
Posted on Sunday, June 1, 2014 10:41 AM | Back to top

Comments on this post: NHibernate Session Load vs Get when using Table per Hierarchy. Always use ISession.Get<T> for TPH to work.

No comments posted yet.
Your comment:
 (will show your gravatar)

Copyright © Rohit Gupta | Powered by: