Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HQL query over sub-classes

Tags:

hql

nhibernate

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.

like image 469
Tim Roberts Avatar asked Nov 14 '22 10:11

Tim Roberts


1 Answers

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);
    }
}
like image 187
Jakub Linhart Avatar answered Dec 19 '22 19:12

Jakub Linhart