【发布时间】:2012-06-17 09:40:27
【问题描述】:
我有以下实体; Ticket 包含一组 0,N 个 WorkOrder:
@Entity
public class Ticket {
...
@OneToMany(mappedBy="ticket", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<WorkOrder> workOrders = null;
...
}
@Entity
public class WorkOrder {
...
@ManyToOne
@JoinColumn(nullable = false)
private Ticket ticket;
}
我正在加载票证并获取属性。所有 0,1 属性都没有问题。对于workOrders,我使用this answer获取以下代码。
CriteriaBuilder criteriaBuilder = this.entityManager.getCriteriaBuilder();
CriteriaQuery<Ticket> criteriaQuery = criteriaBuilder
.createQuery(Ticket.class);
Root<Ticket> rootTicket = criteriaQuery.from(Ticket.class);
ListAttribute<? super Ticket, WorkOrder> workOrders =
rootTicket.getModel().getList("workOrders", WorkOrder.class);
rootTicket.fetch(workOrders, JoinType.LEFT);
// WHERE logic
...
criteriaQuery.select(rootTicket);
TypedQuery<Ticket> query = this.entityManager.createQuery(criteriaQuery);
return query.getResultList();
结果是,在一个应该返回我 1 个工单和 5 个工作订单的查询中,我检索了同一个工单 5 次。
如果我只是将 workOrders 设为 Eager Fetch 并删除 fetch 代码,它会正常工作。
谁能帮帮我?提前致谢。
更新:
关于为什么我对 JB Nizet 的回答不满意的一个解释(即使最终它有效)。
当我只是使关系急切时,JPA 正在检查与我使它变得懒惰并将 fetch 子句添加到 Criteria / JPQL 时完全相同的数据。各种元素之间的关系也很清楚,因为我为 Criteria 查询定义了ListAttribute。
对于JPA在两种情况下没有返回相同数据的原因有一些合理的解释吗?
更新赏金:虽然 JB Nizet 的回答确实解决了这个问题,但我仍然认为这毫无意义,因为两个操作具有相同的含义(“获取 Ticket 并在 ticket.workOrders 中获取所有 WorkOrder”),做它们通过预先加载不需要进一步更改,而指定 fetch 需要 DISTINCT 命令
【问题讨论】:
-
如果您查看Left Join,它就是这样工作的。为什么需要leftjoin取结果?
-
在条件 API 中可用的三个选项中,它是更明智的。我们在这里讨论的是 JPA,所以我希望 API 能够以更恰当的方式组织实体中的 SQL。
标签: jpa jpa-2.0 criteria-api