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);
...
我正在尝试使用 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);
...