【问题标题】:JPA - Criteria API and EmbeddedIdJPA - 标准 API 和 EmbeddedId
【发布时间】:2011-05-04 07:43:26
【问题描述】:

我想使用条件进行以下查询。我有一个定义了 EmbeddedId 的 Entity:

 @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 注释时,如何使用条件进行查询?

谢谢! 毛罗。

【问题讨论】:

    标签: jpa jpa-2.0 criteria-api composite-id


    【解决方案1】:

    您需要使用路径导航来访问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 持久性查询 语言查询等价:

    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

    按预期工作。

    【讨论】:

    • 嗨帕斯卡,我试过了,没有运气。正如我在帖子中所说,当我执行 entity.get("id") 时,我得到一个 IllegalArgumentException。有什么建议吗?
    • @Mauro 不,你没有在你的问题中这么说。您使用的是什么 JPA 实现?
    • @Pascal,再次感谢您的回复...我使用的是 Hibernate 版本 3.5.0-Beta2。异常说 InterfaseId 它是一个非托管实体。特别是 IllegalArgumentException: Not an managed type: class InterfaseId
    • @Mauro 我的意思是,在您的问题中,您没有写到您尝试过entity.get("id"),读者必须猜测您尝试了什么,这不好。不管怎样,我会用另一个实现来试试你的映射。
    • @Pascal 很抱歉造成误解。我已经编辑了这个问题,所以我希望这次能更清楚地说明我试图做什么。我将尝试使用最新版本的 Hibernate (3.6) 或 Eclipse Link,我将返回结果,顺便说一句...我认为这是一个基本查询(导航复合属性 - 在本例中为嵌入类)所以很少见hibernate 不支持这种类型的查询。谢谢!。
    【解决方案2】:

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

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

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

    除非你试图做你所要求的以外的其他事情,这是做这件事的“理智”方式。对 id 的查询将返回最多一个结果。

    【讨论】:

      【解决方案3】:

      尝试将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();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-04-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-06
        • 2018-08-22
        • 1970-01-01
        • 2012-03-31
        相关资源
        最近更新 更多