32

我想使用条件进行以下查询。我有一个定义了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 注释时,如何使用标准进行查询?

谢谢!。毛罗。

4

3 回答 3

65

您需要使用路径导航来访问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 [主]调试 org.hibernate.SQL -
    选择
        interfase0_.CLASE 为 CLASE31_
    从
        TB_INTERFASES interfase0_
    在哪里
        interfase0_.CLASE=?
17:20:26.895 [main] TRACE org.hibernate.type.StringType - 将“Referencia 111”绑定到参数:1

按预期工作。

于 2010-11-03T06:19:25.440 回答
0

这是一个老问题,但无论如何......

另一个非常简单的解决方案是

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

除非您尝试做除您所要求的以外的其他事情,否则这是“理智”的做法。对 id 的查询将返回最多一个结果。

于 2016-10-17T21:27:51.450 回答
0

尝试将metamodel类复制并粘贴到保存实体的同一文件夹中(在 NetBeans 8.2 中,它们是自动生成的,并且与您的实体具有相同的名称,但末尾带有下划线。应该类似于Interfase_and InterfaseId_)。

强制导入metamodelInterfase_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();
于 2017-12-07T18:13:21.573 回答