Tim Roberts
Tim Roberts

Reputation: 782

HQL query over sub-classes

I have the following entities defined in my Entity Model:

public class MyContainer
{
   public virtual ICollection<Base> Subs { get; set; }
}

public abstract class Base
{
   public virtual Guid Id { get; set; }
}
public abstract class Sub1 : Base
{
   public virtual int MyValue { get; set; }
}
public abstract class Sub2 : Base
{
   public virtual int MyValue { get; set; }
}

and the following FluentNHibernate mappings for the above entities:

public sealed class BaseMap : ClassMap<Base>
{
   public BaseMap()
   {
      Table("BaseTable");
      Id(e => e.Id);
   }
}

public sealed class Sub1Map : SubClassMap<Sub1>
{
   public Sub1Map()
   {
      Table("Sub1Table");
      KeyColumn("BaseId");

      Map(e => e.Myvalue);
   }
}

public sealed class Sub2Map : SubClassMap<Sub2>
{
   public Sub2Map()
   {
      Table("Sub2Table");
      KeyColumn("BaseId");

      Map(e => e.Myvalue);
   }
}

When I run the following HQL:

select sub
   from MyContainer container
        join fetch container.Subs sub
   where sub.MyValue = :p1

the SQL generated only applies a constraint in the WHERE clause for one of the sub-classes, however, the generated JOINS are correct, i.e., the following skeletal SQL is generated:

SELECT ...
FROM BaseTable bt
     INNER JOIN Sub1Table st1 ON ...
     INNER JOIN Sub2Table st2 ON ...
WHERE st1.MyValue = @p1

where as I'm expecting an additional OR in the WHERE clause:

SELECT ...
FROM BaseTable bt
     INNER JOIN Sub1Table st1 ON ...
     INNER JOIN Sub2Table st2 ON ...
WHERE st1.MyValue = @p1
      OR st2.MyValue = @p2

Is there something I'm missing, or is there a way to re-write the HQL so that I can reference each sub-class in the WHERE clause and apply the constraint directly (assuming that it would then generate the additional constraint in the generated SQL)?

I'm using NHibernate 3.0.0.

Upvotes: 5

Views: 2144

Answers (1)

Jakub Linhart
Jakub Linhart

Reputation: 4072

MyValue should be declared and mapped in Base. It is not possible to filter base class by properties that are defined in subclasses without casting to the particular class:

where (b.class = Sub1 and b.MyValue = :p1) or (b.class = Sub2 and b.MyValue = :p1)

EDIT: Or in FNH1.2 union subclassing can be used:

public class BaseMap : ClassMap<Base>
{
    public BaseMap()
    {
        UseUnionSubclassForInheritanceMapping();
        Table("BaseTable");
        Id(e => e.Id);
    }
}

Upvotes: 1

Related Questions