views:

50

answers:

1

Using NHibernate; is it possible to query against a super class while performing restrictions at the subclass level?

For example (appologies for the psuedo-code):

Class A
   Property Prop1
End Class

Class B
   Inherits Class A
   Property Prop2
End Class

Class C
   Inherits Class A
   Property Prop3
End Class

How would I perform a query as follows:

from A where Prop1 = 'foo' AND 
((if A is B) then B.Prop2 = 'bar' OR
 (if A is C) then C.Prop3 = 'bar')

Is something like this possible using Nhibernate.Linq? What about hql or the criteria API?

+1  A: 

Since HQL and ICriteria are Domain-query tools i find it hard to expect such a functionality.

AFAIK the only close thing is using ICriteria's Expression.Sql() where you query the superclass but inject subclass specific fragments with pure sql. There, the expression would be like

crit.Add(
  Expression.Sql(@"(({alias}.DiscrimCol = :subClassADiscrimVal AND {alias}.Col2 = :barVal) 
    OR ({alias}.DiscrimCol = :subClassBDiscrimVal AND {alias}.Col3 = :barVal))", 
    new object[] { "subA", "subB", "bar" }, 
    new IType[] { NHibernateUtil.String,NHibernateUtil.String,NHibernateUtil.String } )
);

not nice but it works

The other way would be using an ISQLQuery which at least allows the SELECT part to be domain specific (and using .AddEntity()) so you can still select your managed superclass and the WHERE part contains subclass specific fragments

========= UPDATE ==========

On a second thought, there is a way to implement this via HQL or ICriteria but it more of a workaround and is less performant because it involves subqueries. example in ICriteria:

    nhSes.CreateCriteria(typeof(Super))
        .Add(
            Restrictions.Disjunction()
                .Add(Subqueries.PropertyIn("Id", DetachedCriteria.For(typeof(ChildA))
                                                    .SetProjection(Projections.Id())
                                                    .Add(Restrictions.Eq("ChildAProp", barVal))))
                .Add(Subqueries.PropertyIn("Id", DetachedCriteria.For(typeof(ChildB))
                                                    .SetProjection(Projections.Id())
                                                    .Add(Restrictions.Eq("ChildBProp", barVal))))
        )

i am quering each child, project its id and then select the super class, limiting the ids with IN from the projected child ids.

Jaguar
Thanks for this; unfortunate that there isn't a cleaner approach other than using native sql. I wonder if performing a union operation would be a better option?
DanP
chech the update
Jaguar