Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I write a Hibernate Criteria query, for a super-class, and check for a certain sub-class?

How can I write a Hibernate Criteria query, for a super-class, and check for a certain sub-class? Let's imagine we have the following classes all mapped up with Hibernate-JPA:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Bar {
    @Id
    @Column(name = "id")
    private Long id;
}

@Entity
@PrimaryKeyJoinColumn(name="bar_id")
public class Foo extends Bar {
}

@Entity
@PrimaryKeyJoinColumn(name="bar_id")    
public class Goo extends Bar {
}

When writing a Criteria query like this, I would like, for performance, to use a left-join with the sub-class:

getSession()
    .createCriteria(Bar.class)
    .createAlias("Foo", "foo", CriteriaSpecification.LEFT_JOIN)
    .add(Restrictions.isNotNull("foo.bar_id"))
    .list();

This fails, because the association path "Foo" doesn't work obviously, but it will illustrate what I want. Or is there another way of doing this type of query? I need the query to be performed on the superclass. If I would have done it in SQL it would look like this:

select b.*
from bar b left join foo f on f.bar_id = b.id
where f.bar_id is not null;

The SQL query above is just to illustrate what I mean, I know it would be easier to use a "normal" join in that specific case.

like image 403
crunchdog Avatar asked Jul 02 '11 12:07

crunchdog


1 Answers

It's really not clear what you want to do.

First of all, since Foo inherits from Bar, searching for Bar instances will automatically return Foo instances. Hibernate takes care of joining the tables by itself.

Second: your SQL query is really strange. You're doing a left join (which means that you're searching for bars who might not have an associated foo), but you also have a where close on foo.bar_id being not null. This in fact constitutes an inner join, and could be rewritten as

select b.* from bar b inner join foo f on f.bar_id = b.id

If what you want to do is search for Foos, and Foos only, then use a Criteria with Foo as root entity:

getSession()
    .createCriteria(Foo.class)
    .list();

You will get Foo instances, but since Foo extends Bar, these Foo instances are also Bar instances. That's what inheritance is.

Now if you're building your Criteria instance dynamically, and realize at some point that the search must only return instances of Foo, you have to use the implicit class property:

Criteria c = getSession().createCriteria(Bar.class, "bar")
// ...
if (limitToFoos) {
    c.add(Restrictions.eq("bar.class", Foo.class));
}
like image 105
JB Nizet Avatar answered Oct 27 '22 13:10

JB Nizet