我有以下实体:事件和属性。一个事件可以有很多属性。
我遇到的问题是,我似乎找不到在单个 SQL 查询中返回事件及其属性的查询。我可能有数百万个需要迭代的事件,出于明显的性能原因,我不想延迟加载它们。
我尝试在查询中使用 fetch,但它为每个属性返回一个事件。即,如果一个事件有 2 个属性,它将返回 2 个事件,每个事件都有一个属性。
我想要的是一个具有 2 个属性的事件。
SELECT e FROM Event e LEFT JOIN FETCH e.attributes
如果我添加 DISTINCT 它可以工作,但是它会创建一个独特的 SQL 查询,这在大型数据集上非常慢。
public class Event {
@OneToMany(mappedBy = "event", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
public Set<Attribute> getAttributes(){}
}
public class Attribute {
@ManyToOne(cascade=CascadeType.ALL)
@JoinColumn(name = "event_id", nullable = false)
public Event getEvent() {
return event;
}
}
解决方案
我找不到 JPA 解决方案。相反,我将 EntityManager 解包到 Hibernate 会话,并按照@milkplusvellocet 的建议使用标准的结果转换器。这将检索不同的根实体,而无需创建不同的 SQL 查询。
Session session = em.unwrap(Session.class);
Criteria criteria = session.createCriteria(Event.class);
criteria.setFetchMode("attributes", FetchMode.JOIN);
criteria.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
需要注意的一件事是,我尝试从展开的会话中使用 HQL。我将 DISTINCT 添加到查询中,并将结果转换器设置为 DISTINCT_ROOT_ENTITY,类似于上面的标准解决方案。这样做仍然会创建一个独特的 SQL 查询。