So this seems a little complicated on my side, so I'll try and first set the scene as clearly as possible.
[ActiveRecord, JoinedBase]
abstract BaseClass
{
public x;
public y;
}
[ActiveRecord, JoinedBase]
ClassA : BaseClass { }
[ActiveRecord, JoinedBase]
ClassB : BaseClass { }
abstract GraphicBaseClass : BaseClass
{
public height;
public width;
}
[ActiveRecord, JoinedBase]
ClassC : GraphicBaseClass { }
[ActiveRecord, JoinedBase]
ClassD : GraphicBaseClass { }
[ActiveRecord, JoinedBase]
ClassE : GraphicBaseClass { }
Note: several keywords and other fluff ignored for saving on the wall of text I need to enter.
So the textual explanation of that... we have a standard base class "BaseClass" that implements a number of properties. We then have a couple of classes "ClassA" and "ClassB" that are specific types of the base. We then use an intermediate base class "GraphicBaseClass" that adds height and width properties, which the remaining 3 classes inherit from. This results in the single BaseClass common table, and the 5 specific tables for each of the concrete classes.
I have a query that in the majority works on the base properties. In certain circumstances I want to query on the height and width. As GraphicBaseClass is not an activerecord class I cannot use that as the base of the query. Currently I'm using the QueryOver syntax, but I can't find a way to query the three GraphicBaseClass derived entities with the height and width properties.
The closest I got so far was:
QueryOver<BaseClass, BaseClass> query = QueryOver.Of<BaseClass>()
.Where(bc => bc.x == something)
.TransformUsing(CriteriaSpecification.DistinctRootEntity);
if (actualTypes.All(x => x.IsSubclassOf(typeof (GraphicBaseClass))))
{
// Filter by dimensions
if (criteria.RestrictSize)
{
if (criteria.FilterByDimension)
{
query.DetachedCriteria.Add(Restrictions.Lt("Width", criteria.Width + 10));
query.DetachedCriteria.Add(Restrictions.Lt("Height", criteria.Height + 10));
}
}
}
This resulted in sql something like:
SELECT TOP (4 /* @p0 */) this_.BaseClassId as BaseClass1_97_5_,
this_.Version as Version97_5_,
this_.BaseClassType as BaseClass2_97_5_,
this_1_.Width as Width99_5_,
this_1_.Height as Height99_5_,
this_2_.Width as Width100_5_,
this_2_.Height as Height100_5_,
this_3_.X as X101_5_,
this_4_.Width as Width102_5_,
this_4_.Height as Height102_5_,
this_5_.X as X103_5_,
FROM BaseClass this_
left outer join ClassC this_1_
on this_.BaseClassId = this_1_.ClassCId
left outer join ClassD this_2_
on this_.BaseClassId = this_2_.ClassDId
left outer join ClassA this_3_
on this_.BaseClassId = this_3_.ClassAId
left outer join ClassE this_4_
on this_.BaseClassId = this_4_.ClassEId
left outer join ClassB this_5_
on this_.BaseClassId = this_5_.ClassBId
WHERE and this_1_.Width between 0 /* @p8 */ and 'Height' /* @p9 */
So it's only applying the height and width restriction to one of the 3 required classes.
I am looking for any answer here, if it can be done in HQL or the Criteria API or whatever is required to achieve the result.
Apologies for the wall of text!!
Thanks.
A bit late, I know. Here is the solution I usually use:
Create a subquery and join it with "in".
if (/* subclass required*/)
{
var subClassQuery = QueryOver.Of<GraphicBaseClass>();
subClassQuery.Where(x => x.Width == criteria.Width);
subClassQuery.Where(x => x.Height == criteria.Height);
subClassQuery.Select(x => x.Id);
query.Where(Subquery.WherePropery(x => x.Id).In(subClassQuery));
}