Polymorphic queries

Polymorphic queries extend the polymorphic behavior of classes into the persistence layer. What I mean by this is – polymorphism gives us a base type variable that can hold a reference to a derived type and invokes methods from derives types at runtime, NHibernate is capable of loading correct instance of derived type when queried by base type. For instance, if you try to load a Benefit entity by ID from database, but the benefit record in the database corresponds to SkillsEnhancementAllowance, then NHibernate is capable of determining what the actual derived type the record needs to be mapped to (SkillsEnhancementAllowance in this example) and instantiates the correct entity type. We have seen this in Chapter 3, Let's Tell NHibernate About Our Database during mapping of inheritance hierarchy of classes. Let me take a moment to show you a unit test from that chapter which showed polymorphic nature of the ISession.Get<T> method:

public void MapsSkillsEnhancementAllowance()
{

object id = 0;
using (var transaction = Session.BeginTransaction())
{
  id = Session.Save(new SkillsEnhancementAllowance
  {
    Name = "Skill Enhacement Allowance", Entitlement = 1000,
    RemainingEntitlement = 250
  });
  transaction.Commit();
}

Session.Clear();

using (var transaction = Session.BeginTransaction())
{
  var benefit = Session.Get<Benefit>(id);
  var skillsEnhancementAllowance = benefit as
  SkillsEnhancementAllowance;
  Assert.That(skillsEnhancementAllowance, Is.Not.Null);

  transaction.Commit();
  }
}

In the preceding code listing, we persisted an instance of SkillsEnhancementAllowance into database. We then asked NHibernate to load an instance of Benefit from database using the id that we received when the SkillsEnhancementAllowance instance was saved. But the type of the entity that NHibernate loaded is SkillsEnhancementAllowance which is what we had persisted.

The polymorphic nature of queries is not limited to the Get<T> and Load<T> methods on ISession. All querying methods available in NHibernate support polymorphic queries. Moreover, there is nothing special that you need to do to enable polymorphic querying. This is default behavior of NHibernate. If you load an Employee instance from database that has a collection of Benefit entities on it and then you iterate through the collection and check the types of each item in collection, you will notice that NHibernate has hydrated correct entity types as they should be. It does not matter if the Employee instance was loaded using criteria query or LINQ.

Before we close on this topic, let me show you another flavor of polymorphic queries. Suppose you want to load employees who have opted for season ticket loan. In native SQL world, you would have joined to the SeasonTicketLoan table to get the employees having a record in that table. This is possible to do using LINQ, as shown next:

var employees = from e in Database.Session.Query<Employee>()
join b in Database.Session.Query<SeasonTicketLoan>()
on e equals b.Employee select e;

Following is another way to write this query using lambda syntax and utilizing polymorphic capabilities of NHibernate:

var employeeQuery = Database.Session.Query<Employee>()
.Where(e => e.Benefits.Any(b => b is SeasonTicketLoan));

While both queries give us the same result, the former joins the Employee table directly with SeasonTicketLoan, giving us a short and faster SQL. Depending on the inheritance mapping strategy used, the latter may involve outer joins with multiple Benefit tables. It will load all matching records in memory and then filter out the ones needed. This goes back to the point I made that there are multiple ways of writing a query and you need to see which one works best for you.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.79.20