JPA - Критерии API и EmbeddedId
Я хочу использовать критерии, чтобы сделать следующий запрос. У меня есть сущность с определенным 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 ответа
Вам нужно использовать навигацию по пути для доступа к атрибуту (ам) 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 - Выбрать interfase0_.CLASE as CLASE31_ от TB_INTERFASES interfase0_ где interfase0_.CLASE=? 17:20:26.895 [main] TRACE org.hibernate.type.StringType - привязка 'Referencia 111' к параметру: 1
Работает как положено.
Попробуйте скопировать и вставить 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();
Это старый вопрос, но все равно...
Другое чрезвычайно простое решение
InterfaseId id = new InterfaseId();
id.setClase("Clase");
Interfase found = em.find(id);
За исключением случаев, когда вы пытаетесь сделать что-то еще, кроме того, что вы просили, это "нормальный" способ сделать это. Запрос по идентификатору вернет максимум один результат.