tags:

views:

994

answers:

5

Hi all,

I'm using Hibernate 3.1.1, and in particular, I'm using HQL queries.

According to the documentation, Hibernate's queries are polymorphic:

A query like: from Cat as cat returns instances not only of Cat, but also of subclasses like DomesticCat.

How can I query for instances of Cat, but not of any of its subclasses?

I'd like to be able to do it without having to explicitly mention each subclass.

I'm aware of the following options, and don't find them satisfactory:

  1. Manually filtering the instances after the query, OR:
  2. Manually adding a WHERE clause on the discriminator column.

It would make sense for Hibernate to allow the user to decide whether a query should be polymorphic or not, but I can't find such an option.

Thanks in advance!

A: 
SELECT cat FROM Cat cat WHERE cat.class='cat'

where the value 'cat' is the discriminator value of the Cat class.

If you are using TABLE_PER_CLASS, then try cat.class='Cat') (the name of the class)

This is not exactly a where clause on the discriminator column, because such a query will fail (the discriminator column is available only in native queries).

Bozho
Thanks, but I'm trying to avoid editing the WHERE clause. If I go with your suggestion, Hibernate will add its own portion to the WHERE, and it'll end up being "WHERE c.class='cat' AND c.class IN ('cat', 'domesticCat')". I'd rather have a way to tell a Query to "turn off" its polymorphic ability for once (if such a thing exists).
Eli Acherkan
And congratulations on your 10k rep!
Eli Acherkan
why do you want to not specify the where clause?
Bozho
Becuase I have a piece of generic, framework code that executes different queries on different entities. I'd like to be able to pass a configuration parameter to the generic code, to switch between polymorphic and non-polymorphic mode. The generic code __will__ modify the where clause if it has to, but that would require to look up the discriminator value (although it's not difficult), and it will probably result in unnecessary parts in the where clause (see my previous comment).
Eli Acherkan
A: 

The ORM mimics the Java Model: if an object is an instance of another type (if an instance of PersianCat is an instance of Cat also), any query on Cat will have to be polymorphic (imagine you querying a List and asking if the entries match instanceof Cat.

Even Bozho's solution is somewhat impure, since the 'class' column is supposedly opaque to your hibernate mapping, although I admit its a very good compromise. You can simply get the discriminator through the classe's simple name.

If you're comfy and are using table per class you can always do a native query to the Cat table to get the ids and then get the entries through hibernate.

Miguel Ping
You're right, 99% of the time you should treat an instance of a subclass just like any other instance of the base class - just like using `x instanceof Cat` in Java.My question, however, is about the other 1%, when there's a reason you don't want to load the subtype - just like using `x.getClass() == Cat.class` in Java. In my case, it's during system bootstrap, when I can't yet instantiate subtype objects.
Eli Acherkan
Can you share your design? Normally when things are this hard there is a change the design can have a flaw or a better way of doing things.
Miguel Ping
+5  A: 

Use polymorphism="explicit" in the class mapping. This will cause queries to return only instances of the named class and not its subclasses.

Implicit polymorphism means that instances of the class will be returned by a query that names any superclass or implemented interface or class, and that instances of any subclass of the class will be returned by a query that names the class itself. Explicit polymorphism means that class instances will be returned only by queries that explicitly name that class.

Rob H
+1 good find...
skaffman
Awesome! In my case, I need it to be on per-query basis, and not per-entity, but I think I see a way to do it - by overriding the `isExplicitPolymorphism` method on my `EntityPersister`. You certainly gave me a push in the right direction.
Eli Acherkan
A: 

Look at BaseQueryReturnFieldsCalculatorGC; it dynamically adds a condition to the 'where' which selects only where class=XXX; you can duplicate this logic to the HQLQueryTemplate and have the user define 'isNonPolymorphic'.

Note that it will only work with table-per-hierarchy, cos only then does the implicit class column exist and is selectable.

friendlyfire
Welcome back! :-)
Eli Acherkan
A: 

Hi

JPA 2 (Hibernate 3.5) adds support for non-polymorphic queries, this is very similar to Hibernates .class property (as Bozho answered above) but it is not Hibernate specific. This is done using the TYPE operator. As in

Select b from Book b where TYPE(b) Book

You can read more about here it in my blog

Eyal

Eyal Lupu