msonntag
msonntag

Reputation: 113

JPA Criteria API: query property of subclass

I have a class structure like this:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Article {
   private String aBaseProperty;
}

@Entity
public class Book extends Article {
   private String title;
}

@Entity
public class CartItem {
   @ManyToOne(optional = false)
   public Article article;
}

I tried the following to receive all CartItems that have a reference to a Book with title = 'Foo':

CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<CartItem> query = builder.createQuery(CartItem.class);
Root<CartItem> root = query.from(CartItem.class);
builder.equal(root.get("article").get("title"), "Foo");
List<CartItem> result = em().createQuery(query).getResultList();

But unfortunately, this results in an error (makes sense to me, as title is in Book, not in Article...):

java.lang.IllegalArgumentException: Could not resolve attribute named title
    at org.hibernate.ejb.criteria.path.SingularAttributePath.locateAttributeInternal(SingularAttributePath.java:101)
    at org.hibernate.ejb.criteria.path.AbstractPathImpl.locateAttribute(AbstractPathImpl.java:216)
    at org.hibernate.ejb.criteria.path.AbstractPathImpl.get(AbstractPathImpl.java:189)
...

However, I was able to achieve what I want using the following HQL:

SELECT c, a FROM CartItem c INNER JOIN c.article a WHERE a.title = ?

So why does the latter work and can I achieve something similar using the Criteria API?

Upvotes: 10

Views: 9401

Answers (2)

&#201;tienne Miret
&#201;tienne Miret

Reputation: 6660

I had the same issue and found a solution thanks to chris (see JPA Criteria API where subclass).

For this you need JPA 2.1, and you make use of one of the CriteriaBuilder.treat() methods. Just replace your builder.equal... line by:

builder.equal(builder.treat(root.get("article"), Book.class).get("title"), "Foo");

Upvotes: 4

gadeynebram
gadeynebram

Reputation: 725

I'm not an expert but from an OO point of view I would say that an Article does not have a property title and is therefore not found on the CarItem's property named article.

Maybe you should check if Article is of type Book.

I'm not sure how to do this using CriteriaBuilder

Criteria c=session.createCriteria(CarItem.class, "caritem");
c.add(Restrictions.eq("caritem.class", Book.class));
List<Article> list=c.list();

Upvotes: 1

Related Questions