【问题标题】:JPA Criteria API - Accessing fields of One-to-Many collection associationJPA Criteria API - 访问一对多集合关联的字段
【发布时间】:2020-11-16 18:27:35
【问题描述】:

如何使用 Criteria API 编写以下 JPQL 查询?

" select a from A a left join fetch a.bs b where b.i like 'X%' "

A-to-B 是一对多的关系,其中 A 和 B 如下所示:

@Entity
public class A {

    @OneToMany(cascade={CascadeType.PERSIST})
    private Set<B> bs = new HashSet<B>();   

    //...
}

@Entity
public class B {

    private String i;
    
    //...
}

我试过了:

CriteriaBuilder cb = em.getCriteriaBuilder();           
CriteriaQuery<A> cq = cb.createQuery( A.class );
Root<A> aRoot = cq.from( A.class );
Fetch<A, B> bs = aRoot.fetch(A_.bs, JoinType.LEFT);
cq.where(cb.like(what_do_i_do_here, "X%"));
cq.select(aRoot);

我需要获取所有这些As 及其关联的Bs,其中关联Bs 的i 值以"X" 开头。

编辑

如果我尝试How to properly express JPQL "join fetch" with "where" clause as JPA 2 CriteriaQuery? 给出的方法,我不正确得到 2 As 结果而我应该只得到 1 A 其关联的 B_.i 具有以开头的值“X”。

我使用以下代码解决了这个问题:

CriteriaBuilder cb = em.getCriteriaBuilder();           
CriteriaQuery<A> cq = builder.createQuery( A.class );
Root<A> root = cq.from( A.class );
Join<A, B> bs = (Join<A, B>) root.fetch(Guide_.students, JoinType.LEFT);
cq.where(builder.like(bs.get(B_.i), builder.parameter(String.class, "i")));
cq.select(root);
            
TypedQuery<A> query = em.createQuery(criteria).setParameter("i", "X%");         
List<A> as= query.getResultList();          
for (A a: as) {
  System.out.println(a);
}

【问题讨论】:

  • 以下划线结尾的类就是所谓的元模型。它用于在进行连接(或获取)时访问实体的属性以及比较或使用它们。在 Eclipse 中,如果您二次单击项目/属性/JPA 并在“Canonical Metamodel 2.0”部分中选择要生成它们的目录,它们会自动生成。
  • @crizzis 谢谢 crizzis,它有帮助。我得到它与以下工作。不过应该有更好的方法来完成它。 CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery&lt;A&gt; cq = cb.createQuery( A.class ); Root&lt;A&gt; aRoot = cq.from( A.class ); Join&lt;A, B&gt; bs = (Join&lt;A, B&gt;) aRoot.fetch(A_.bs, JoinType.LEFT); cq.where(cb.like(bs.get(B_.i), builder.parameter(String.class, "i"))); cq.select(aRoot); TypedQuery&lt;A&gt; query = em.createQuery(cq).setParameter("i", "X%");
  • @gaetanTEMATE 谢谢门。它有帮助,但我无法帮助我解决给定问题。

标签: jpa left-join jpql eager-loading criteria-api


【解决方案1】:

您可以使用 Join 来获取和过滤子实体。试试下面的代码

CriteriaBuilder cb = em.getCriteriaBuilder();           
CriteriaQuery<A> cq = cb.createQuery( A.class );
Root<A> aRoot = cq.from( A.class );
Join<A, B> bs = root.join(A_.B);
cq.where(cb.like(bs.get(B_.i), "X%"));
cq.select(aRoot);

注意 - 我没有机会测试这段代码。你可以参考我为类似问题实现的工作代码https://github.com/bsridharpatnaik/SpecificationTest

编辑 - 提供详细答案

我已经对回购进行了新的推动。请采取最新的拉动。

我创建了与您提到的完全相同的示例。

实体类

public class A 
{
    
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long aid;

    @OneToMany(cascade={CascadeType.PERSIST})
    private Set<B> bs = new HashSet<B>();
// get & set
}

public class B 
{

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long bid;
    
    String i;
//get & set
}

现在,根据您的查询,您想要过滤所有来自 A 类的记录,其中对应的 B.i 以 x 开头。

下面是服务等级。为了便于理解,我在单独的类中编写了 criteroa 查询逻辑

@Service
public class Service1 
{
    @Autowired
    aRepo repo;
    
    @Autowired
    ModelSpecification modelSpecification;

    @Autowired
    EntityManager entityManager;
    public List<?> getResults() throws ParseException 
    {
        //ModelSpecification modelSpecification = new ModelSpecification();
        CriteriaQuery<A> query = modelSpecification.getSpecQuery();
        TypedQuery<A> typedQuery = entityManager.createQuery(query);
        List<A> resultList = typedQuery.getResultList();
        return resultList;
    }
}

下面是条件查询逻辑

@Component
public class ModelSpecification 
{
    @Autowired
    EntityManager entityManager;
    
    public CriteriaQuery<A> getSpecQuery() throws ParseException
    {
        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        CriteriaQuery<A> query = builder.createQuery(A.class);
        Root<A> root = query.from(A.class);
        Join<A,B>   ab = root.join(A_.BS);
        query.where(builder.like(ab.get(B_.I),"x"+"%"));
        return query;
    }
}

我正在过滤所有 B_.I 以 x 开头的 A 记录。

输出 A 类有以下援助条目 - 1,2 B类有以下条目

加入表 a_bs 有以下条目

现在,如果我点击 API,我应该只得到 A 记录,并且辅助 =1,因为它只与从 x 开始的 B.i 相关联。

【讨论】:

  • 谢谢斯里达尔。给定的代码不起作用。提到的链接也无济于事。我不知道在哪里可以找到给定链接中的相关代码。
  • @skip 我修改了代码以匹配您提到的确切示例。请看一看。
  • 感谢 Sridhar,但在您的查询中没有获取。我需要一个left join fetch,它会急切地加载Bs 数据以及As 数据,其中B_.i 以“X”开头。我已经编辑了我的问题,显示了我是如何解决问题的。
  • @skip 欢迎。很高兴听到问题得到解决。请在此处添加它作为答案,以便它可以帮助其他人。
猜你喜欢
  • 1970-01-01
  • 2018-12-24
  • 2016-06-23
  • 1970-01-01
  • 2015-05-12
  • 2022-12-21
  • 2013-12-02
  • 2020-02-18
  • 1970-01-01
相关资源
最近更新 更多