JPA 条件 API - 填充关联

JPA Criteria API - Populate associations

我正在尝试使用 JPA 条件 API 进行非常简单的查询。

我有两个实体:

@Entity
@Table(name = "PERSONS")
public class Person implements Serializable
{
   @Id
   @Column(name = "COD_PERSON") 
   private String personCode;

   @Column(name = "NAME")   
   private String name;

   @OneToMany(mappedBy="person")
   List<Address > addresses;

   ... other attributes, getters and setters
}

@Entity
@Table(name = "ADDRESS")
public class Address implements Serializable
{
   private static final long serialVersionUID = 1L;

   @Id
   @Column(name = "COD_ADDRESS")
   private String addressCode;

   @ManyToOne(fetch=FetchType.LAZY, optional=false)
   @JoinColumn(name = "COD_PERSON")
   private Person person;

   @Column(name = "street") 
   private String street;

   @Column(name = "zipCode")    
   private String zipCode;

   ... other attributes, getters and setters
}

我们在 'Address' 实体中定义了 ManyToOne 关联,在 'Person' 实体中定义了 OneToMany 关联。由于性能问题,两者都被定义为懒惰。

然后我想查询居住在某个邮政编码的人。我想让人们填充他们的地址。

因为我们已经将关联定义为惰性关联,并且因为 'addresses' 是 OneToMany 关联,所以我认为我应该使用 "eclipselink.batch" 提示。

我试过:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Person> query = cb.createQuery(Person.class);
Root<Person> from = query.from(Person.class);
Join<Person, Address> join =  from.join("addresses");
query.select(from);
Predicate predicate = cb.equal(join .get("zipCode"), "28020");
query.where(predicate);
List results = em.createQuery(query).setHint(org.eclipse.persistence.config.QueryHints.BATCH, "p.addresses").getResultList();       

我得到了所有居住在某个邮政编码的人,没关系,但是 'addreses' 属性没有被填充。

如何让 'person' 个实体填充 'addreses' 属性?

谢谢

我找到的解决方案:

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Person> query = cb.createQuery(Person.class);
    Root<Person> from = query.from(Person.class);
    Join<Person, Address> join =  (Join<Person, Address>) from.fetch("addresses", JoinType.LEFT);
    query.select(from);
    Predicate predicate = cb.equal(join.get("zipCode"), "28020");       
    query.where(predicate);
    List results = em.createQuery(query).getResultList();

我非常不喜欢的是我必须做的选角。我已经尝试过使用 EclipseLink 提供程序。我不知道它是否适用于其他提供商。

您可以在 "Root" class 上使用 "fetch" 方法。

例如,

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery q = cb.createQuery(Order.class);
Root o = q.from(Order.class);
o.fetch("items", JoinType.INNER);
q.select(o);
q.where(cb.equal(o.get("id"), orderId));

Order order = (Order)this.em.createQuery(q).getSingleResult();

此外,您可以从此处查看其他选项

https://www.thoughts-on-java.org/5-ways-to-initialize-lazy-relations-and-when-to-use-them/

编辑 1:

您可以执行 fetch join,结果只有一个 join,如下所示

...
Join<Order, OrderItem> join = (Join<Order,OrderItem>)root.<Order,OrderItem>fetch("items");
...

编辑 2:

如果你不想使用转换,你可以使用实体图。但此解决方案自 JPA 2.1

起可用
...
EntityGraph<Order> fetchGraph = entityManager.createEntityGraph(Order.class);
fetchGraph.addSubgraph("items");
TypedQuery<Order> orderQuery = entityManager.createQuery(query);
orderQuery.setHint("javax.persistence.loadgraph", fetchGraph);
...