JPA Criteria API: query property of subclass
Asked Answered
D

2

10

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?

Downbow answered 1/8, 2011 at 20:3 Comment(2)
Aren't you missing builder.select(root)? Plus your criteria query does not correspond with the JPQL query.Pali
Thanks for your comment! Hmm, my builder (from hibernate-jpa-2.0-api-1.0.0.Final.jar) does not have a select() method. Yeah, they don't correspond because I am missing sth obviously ;-) Are you saying that I would have to add the JOIN to the Article on my own?Downbow
S
4

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");
Sac answered 15/8, 2014 at 12:2 Comment(1)
Worked like a charm :)Lacour
U
1

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();
Unionize answered 21/4, 2012 at 13:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.