Search code examples
nhibernatelinq-to-nhibernate

NHibernate: Fetch an association which exists only in a subclass of the Query<>'d type


I've got a table-per-subclass setup using NHibernate & I'm trying to construct a LINQ query which pre-fetches certain properties that can exist in the derived classes, but I just can't work out how to write the query. E.g. Something like:

var elements = session.Query<Element>()
        .Fetch(e => e.Design) // Fine, resides in Element
      //.Fetch(e => (e as Material)?.Category)
      //.Fetch(e => (e as Operational)?.EnergySource)
        .Where(e => elementIdList.Contains(e.Id)) // Or similar query

Obviously the above won't work; I need a statement that can actually be converted to SQL -- How can I explicitly instruct NHibernate to fetch a derived class' associations? I.e. Assume in the following classes that Design, Category and EnergySource have <many-to-one> relationships from their corresponding "Elements"

public class Element
{
    public virtual int Id { get; set; }
    public virtual Design Design { get; set; }
}

public class Material : Element
{
    public virtual Category Category { get; set; }
}

public class Operational : Element
{
    public virtual EnergySource EnergySource { get; set; }
}

I can emulate it using ToFuture queries on both subclasses & then merging the results, or with an appropriate default config + QueryOver<>, but trying to work out how to do this with Query<>.


Solution

  • Just use explicit cast to subclass:

    var query = session.Query<Element>()
          .Fetch(e => ((Material)e).Category)
          .Fetch(e => ((Operational)e).EnergySource);
    //Same applies to Where clause
        .Where( e => ((Material)e).SomeMaterialValue > 10);
    

    Note: NHibernate detects subclasses by property name (actual cast type is not used so the following .Fetch(e => ((UnrelatedClass)e).Category)) will also fetch Material.Category). It also means that if you have the same property name in different subclasses NHibernate won't be able to properly detect correct subclass.