【问题标题】:Search by nested property of collection field with criteria api使用条件 api 按集合字段的嵌套属性搜索
【发布时间】:2017-03-20 13:55:55
【问题描述】:

我正在尝试查找所有具有一些嵌套元素的实体,并且嵌套元素具有元素集合,我需要通过这些集合的属性找到它。

应该是这样的

class A{
    private B b;
}

class B{
   private Collection<C> cCol;
}

class C{
   private String name;
}

所以我想获取所有具有 B 元素的 A 元素,这些元素的 C 名称与给定参数匹配。

不确定如何使用 JPA Critieria API 进行操作。我知道 JPQL 中有谓词或 MEMEBER OF,但我需要按集合中元素的属性而不是集合成员进行搜索。

尝试过 root.get(a.b.c.name) 以及 root.fetch(a.b)root.fetch(b.c) 之类的方法,但总是以非法 api 使用的一些例外情况告终

【问题讨论】:

    标签: jpa criteria criteria-api


    【解决方案1】:

    以下应该可以工作

    root.get("a").get("b").get("name")
    

    How to create specification using JpaSpecificationExecutor by combining tables?

    【讨论】:

    • 从使用的字段名称来看,它应该是root.get("b").get("cCol").get("name")(假设rootRoot&lt;A&gt;)。
    • 不幸的是,这失败了 IllegalStateException:非法尝试取消引用基本类型的路径源 [null.b.cCol]
    • @Nadir - 您可能应该发布更多关于如何尝试创建查询的代码
    • 我一直试图为此编写一个测试但没有成功,因为 get("cCol") 实际上是一个集合。
    【解决方案2】:

    我想获取所有具有 B 元素的 A 元素,这些元素的 C 名称与给定参数匹配。

    在尝试浏览标准 API 时,我发现先编写 JPQL 查询非常有帮助。这里是:

    SELECT a
    FROM A a
    WHERE EXISTS(
        SELECT c FROM a.b b JOIN b.cCol c WHERE c.name = 'condition'
    )
    

    现在标准 API 变得更加清晰(如果可能的话):

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<A> aQuery = cb.createQuery(A.class);
    Root<A> a = aQuery.from(A.class);
    
    Subquery<C> cSubquery = aQuery.subquery(C.class);
    Root<A> aSubroot = cSubquery.correlate(a);
    Join<A, B> b = aSubroot.join("b");  // "b" is the name of the property of A that points to B
    Join<B, C> c = b.join("cCol"); // "cCol" is the name of the property of C that holds the related C objects
    
    cSubquery.select(c);
    cSubquery.where(cb.equal(c.get("name"), "XXXXXXX"));
    
    aQuery.where(cb.exists(cSubquery));
    
    TypedQuery<A> aTypedQuery = em.createQuery(aQuery);
    aTypedQuery.getResultList();
    

    Java 变量的名称与 JPQL 中的名称相同,例如Join&lt;A, B&gt; b 对应于 JPQL FROM a.b b

    【讨论】:

    • aQuery.distinct(true).where(cb.equal(root.get("b").get("cCol").get("name"), searchString)) 也应该在不需要子查询的情况下给出相同的结果 - 等效的 JPQL 查询将是 SELECT DISTINCT a from A a JOIN a.b b JOIN b.cCol c WHERE c.name = :searchString
    • 我更喜欢子查询而不是 DISTINCT JOIN 的原因是性能。虽然我不是这方面的专家,但这里有一些支持它的资源:@​​987654321@、(2)(3)(4)。实际结果和性能提升当然取决于具体的用例。
    【解决方案3】:

    我成功了

    root.**join**("a").get("b").get("name"):
    

    因为它是一个集合。

    【讨论】:

      【解决方案4】:

      我通过使用这样的连接来做到这一点:

      builder = entityManager.getCriteriaBuilder();
      CriteriaQuery<A> query = builder.createQuery(A.class);
      Root<A> root = query.from(A.class);
      root.join("b").join("c").get("name");
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-11-23
        • 1970-01-01
        • 1970-01-01
        • 2020-04-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多