Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA - Criteria API and EmbeddedId

I want to use criteria to make the following query. I have an Entity with EmbeddedId defined:

 @Entity  @Table(name="TB_INTERFASES")  public class Interfase implements Serializable {    @EmbeddedId   private InterfaseId id;  }   @Embeddable  public class InterfaseId implements Serializable {   @Column(name="CLASE")   private String clase;  } 

And the criteria query that i am trying to do is:

 CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();  CriteriaQuery<Interfase> criteriaQuery = criteriaBuilder.createQuery(Interfase.class);  Root<Interfase> entity = criteriaQuery.from(Interfase.class);  criteriaQuery.where(    criteriaBuilder.equal(entity.get("clase"), "Clase"),  ); 

But this is throwing an IllegalArgumentException:

java.lang.IllegalArgumentException: Not an managed type: class InterfaseId 

i've tried with this queries too:

 Root<Interfase> entity = criteriaQuery.from(Interfase.class);  criteriaQuery.where(    criteriaBuilder.equal(entity.get("id").get("clase"), "Clase"),  ); 

and this one too...

 Root<Interfase> entity = criteriaQuery.from(Interfase.class);  criteriaQuery.where(    criteriaBuilder.equal(entity.get("id.clase", "Clase"),  ); 

with no luck. So my question is how can i make a query with criteria when my classes are using Embedded and EmbeddedId annotations?

Thanks!. Mauro.

like image 605
Mauro Monti Avatar asked Nov 03 '10 05:11

Mauro Monti


People also ask

What is JPA Criteria API?

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.

What is EmbeddedId?

The EmbeddedId annotation is applied to a persistent field or property of an entity class or mapped superclass to denote a composite primary key that is an embeddable class. The embeddable class must be annotated as Embeddable .

Why We Use Criteria API in Hibernate?

In Hibernate, the Criteria API helps us build criteria query objects dynamically. Criteria is a another technique of data retrieval apart from HQL and native SQL queries. The primary advantage of the Criteria API is that it is intuitively designed to manipulate data without using any hard-coded SQL statements.

Which of the following is the correct use case for @EmbeddedId annotation?

The use of @Id with a class marked as @Embeddable is the most natural approach. The @Embeddable tag can be used for non-primary key embeddable values anyway. It allows you to treat the compound primary key as a single property, and it permits the reuse of the @Embeddable class in other tables.


1 Answers

You need to use path navigation to access the attribute(s) of the Embeddable. Here is an example from the JPA 2.0 specification (using the static metamodel):

6.5.5 Path Navigation

...

In the following example, ContactInfo is an embeddable class consisting of an address and set of phones. Phone is an entity.

CriteriaQuery<Vendor> q = cb.createQuery(Vendor.class); Root<Employee> emp = q.from(Employee.class); Join<ContactInfo, Phone> phone =     emp.join(Employee_.contactInfo).join(ContactInfo_.phones); q.where(cb.equal(emp.get(Employee_.contactInfo)                     .get(ContactInfo_.address)                     .get(Address_.zipcode), "95054"))     .select(phone.get(Phone_.vendor)); 

The following Java Persistence query language query is equivalent:

SELECT p.vendor FROM Employee e JOIN e.contactInfo.phones p WHERE e.contactInfo.address.zipcode = '95054' 

So in your case, I think you'll need something like this:

criteriaBuilder.equal(entity.get("id").get("clase"), "Referencia 111") 

References

  • JPA 2.0 Specification
    • Section 6.5.5 "Path Navigation"

Update: I've tested the provided entities with Hibernate EntityManager 3.5.6 and the following query:

CriteriaBuilder builder = em.getCriteriaBuilder();  CriteriaQuery<Interfase> criteria = builder.createQuery(Interfase.class); Root<Interfase> interfaseRoot = criteria.from(Interfase.class); criteria.select(interfaseRoot); criteria.where(builder.equal(interfaseRoot.get("id").get("clase"),      "Referencia 111"));  List<Interfase> interfases = em.createQuery(criteria).getResultList(); 

runs fine and generates the following SQL:

 17:20:26.893 [main] DEBUG org.hibernate.SQL -      select         interfase0_.CLASE as CLASE31_      from         TB_INTERFASES interfase0_      where         interfase0_.CLASE=? 17:20:26.895 [main] TRACE org.hibernate.type.StringType - binding 'Referencia 111' to parameter: 1 

Works as expected.

like image 154
Pascal Thivent Avatar answered Sep 20 '22 17:09

Pascal Thivent