JPA Criteria API-填充关联

时间:2018-07-17 07:09:14

标签: jpa eclipselink criteria-api

我正在尝试使用JPA Criteria 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
}

我们在“地址”实体中定义了ManyToOne关联,在“人”实体中定义了OneToMany关联。由于性能问题,两者都被定义为懒惰。

然后,例如,我想查询居住在某个邮政编码中的人。我想让人们知道他们的地址。

因为我们将关联定义为惰性,并且因为“地址”是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'属性。

如何获取填充了“ addreses”属性的“ person”实体?

谢谢

我找到的解决方案:

    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提供程序。我不知道它是否可以与其他提供商一起使用。

1 个答案:

答案 0 :(得分:2)

您可以在“ Root”类上使用“ 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'方法的简单示例。你可以退房 从下面的链接。

https://github.com/sonerokur/stackoverflow-51375238/

编辑2:

您可以提取联接,这样只能导致一个联接,如下所示:

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

编辑3:

如果您不想使用强制转换,则可以使用实体图。但是,此解决方案自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);
...