37

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.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Mauro Monti
  • 1,068
  • 2
  • 12
  • 21

3 Answers3

67

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.

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • Hi Pascal, I tried that without luck. As i said in the post, when i do entity.get("id"), i get an IllegalArgumentException. Any Suggestion? – Mauro Monti Nov 03 '10 at 12:02
  • @Mauro No you didn't say that in your question. What JPA implementation are you using? – Pascal Thivent Nov 03 '10 at 16:19
  • @Pascal, thanks for your response again... i'm using Hibernate version 3.5.0-Beta2. The exception say that the InterfaseId it's a not managed entity. Specifically **IllegalArgumentException: Not an managed type: class InterfaseId** – Mauro Monti Nov 03 '10 at 16:54
  • @Mauro My point is that nowhere in your question you wrote that you tried `entity.get("id")`, readers have to guess what you tried, which is not good. Anyway, I'll give your mapping a try with another implementation. – Pascal Thivent Nov 03 '10 at 17:16
  • @Pascal sorry for the misunderstanding. I've edited the question, so i hope this time be more clear on what I've tried to do. I will try with the recent version of Hibernate (3.6) or Eclipse Link and i will back with the results, btw... i think that is a basic query (Navigate over compound property - in this case Embeeded Class) so it's rare that hibernate don't support this type of queries. Thanks!. – Mauro Monti Nov 03 '10 at 17:55
  • @Mauro No problem. It's just that things that might be obvious for you aren't necessarily obvious for readers and avoiding any possible ambiguity is a good thing when writing a question :) I've updated my answer, the query works with Hibernate (at least with the version I used). – Pascal Thivent Nov 03 '10 at 18:27
  • @Pascal it's working right now. I've updated the hibernate entity manager to version 3.6.0.Final and run the same code and just work. Thanks 4 all!. Mauro. – Mauro Monti Nov 03 '10 at 19:01
  • @Pascal, thank you very much for your answers, they are always very helpful! – Oleg Apr 15 '14 at 10:58
0

It is an old question, but anyway...

Another extremely simple solution is

InterfaseId id = new InterfaseId();
id.setClase("Clase");
Interfase found = em.find(id);

Except if you trying to do something else besides what you asked, this is the "sane" way to do it. A query on the id will return maximum one result.

Theofanis
  • 523
  • 5
  • 15
0

Try to copy and paste the metamodel classes into the same folder where your entities are saved (in NetBeans 8.2 they are automatically generated and have the same name of your entity but with an underscore at the end. Should be something like Interfase_ and InterfaseId_).

Force the import of the metamodel classes Interfase_ and InterfaseId_ and refer to the desired field.

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(Interfase_.id).get(InterfaseId_.clase),"Referencia 111"));
List<Interfase> interfases = em.createQuery(criteria).getResultList();
Milo
  • 3,365
  • 9
  • 30
  • 44