Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 405
msonntag Avatar asked Aug 01 '11 20:08

msonntag


People also ask

How use JPA Criteria API?

Let's see it step by step: Create an instance of Session from the SessionFactory object. Create an instance of CriteriaBuilder by calling the getCriteriaBuilder() method. Create an instance of CriteriaQuery by calling the CriteriaBuilder createQuery() method.

What is Criteria query in JPA?

The Criteria API is a predefined API used to define queries for entities. It is the alternative way of defining a JPQL query. These queries are type-safe, and portable and easy to modify by changing the syntax. Similar to JPQL it follows abstract schema (easy to edit schema) and embedded objects.

Why We Use Criteria API in Hibernate?

Criteria in Hibernate API can be used for fetching results with conditions, useful methods are add() where we can add Restrictions. Hibernate Criteria API provides addOrder() method that we can use for ordering the results.

What is predicate in JPA?

The type of a simple or compound predicate: a conjunction or disjunction of restrictions. A simple predicate is considered to be a conjunction with a single conjunct. Since: Java Persistence 2.0.


2 Answers

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");
like image 76
Étienne Miret Avatar answered Oct 16 '22 22:10

Étienne Miret


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();
like image 20
gadeynebram Avatar answered Oct 16 '22 23:10

gadeynebram