JPA - Критерии API и EmbeddedId - PullRequest
25 голосов
/ 03 ноября 2010

Я хочу использовать критерии, чтобы сделать следующий запрос.У меня есть Entity с EmbeddedId , определенным:

 @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;
 }

И запрос критерия, который я пытаюсь сделать:

 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"),
 );

Но это вызывает исключение IllegalArgumentException:

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

Я пробовал и с этими запросами:

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

и с этим тоже ...

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

без удачиПоэтому мой вопрос заключается в том, как сделать запрос с критериями, когда мои классы используют аннотации Embedded и EmbeddedId?

Спасибо !.Mauro.

Ответы [ 3 ]

57 голосов
/ 03 ноября 2010

Вам необходимо использовать навигацию по пути для доступа к атрибуту (ам) Embeddable. Вот пример из спецификации JPA 2.0 (с использованием статической метамодели):

6.5.5 Навигация по маршруту

...

В следующем примере ContactInfo это встраиваемый класс состоящий из адреса и набора телефоны. Phone является сущностью.

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));

Следующий запрос Java Persistence языковой запрос эквивалентен:

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

Так что в вашем случае, я думаю, вам понадобится что-то вроде этого:

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

Ссылки

  • JPA 2.0 Спецификация
    • Раздел 6.5.5 «Навигация по маршруту»

Обновление: Я проверил предоставленные сущности с помощью Hibernate EntityManager 3.5.6 и следующего запроса:

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();

работает нормально и генерирует следующий 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

Работает как положено.

0 голосов
/ 07 декабря 2017

Попробуйте скопировать и вставить классы metamodel в ту же папку, где сохраняются ваши сущности (в NetBeans 8.2 они создаются автоматически и имеют то же имя вашей сущности, но с подчеркиванием в конце. Должно быть что-то вродеInterfase_ и InterfaseId_).

Принудительно импортировать metamodel классов Interfase_ и InterfaseId_ и обращаться к нужному полю.

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();
0 голосов
/ 18 октября 2016

Это старый вопрос, но все равно ...

Другое чрезвычайно простое решение -

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

За исключением случаев, когда вы пытаетесь сделать что-то еще, кроме того, что вы просили, это "нормальный" способ сделать это. Запрос по идентификатору вернет максимум один результат.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...