考虑遵循简单的实体模型
class Order{
int id;
String description;
//one to one eager load with join column specified
Detail details;
//one to many lazy load with mapped by specified
Collection<Item> items;
}
class Detail{
}
class Item{
String name;
//reference to order
}
现在,假设要求是通过某些标准(例如,匹配某些内容的描述)加载所有具有项目详细信息的订单。很简单,我写了一个像“来自订单说明......”的hql。例如,这会加载1000个实体,并且项目集合是延迟加载的。我通过调用size强制在会话中加载它们。
这当然会导致N + 1问题,所以我决定使用批量抓取项目。只需在项目集合上添加批量大小注释,并按预期添加更少的查询。
但是,我根本不对'detail'感兴趣,但由于它是一对一的热切加载,每个Order有一个查询总是加载它。我只想废除这些问题。
要解决此问题,我尝试在没有详细信息的情况下进行选择,但我不确定如何在查询中包含项目(集合),以便它的加载方式与我选择所有内容的方式相同(即,延迟加载,然后可以在以后的调用中使用批量大小)。一些建议是在where子句中使用join,但是使用空数组列表初始化我的集合(而不是像Lazy加载那样使用PersistentBag)。
寻找解决方案。
答案 0 :(得分:0)
一种可能的解决方案如下:
创建一个包含查询结果的POJO。例如:
public class OrderResult {
private String description;
private String itemName;
// ... more fields, if any
public OrderResult(String desc, String itemName) {
this.description = desc;
this.itemName = itemName;
}
// getters & setters
}
使用构造函数表达式创建JPQL查询:
List<OrderResult> resultList = entityManager.createQuery("SELECT NEW OrderResult(o.description, i.name) FROM Order o JOIN o.items i where <condition>", OrderResult.class).getResultList();
因此,您将获得OrderResult
的实例列表,其中仅包含您感兴趣的信息。
注意1:您说的是HQL,但HQL是Hibernate特定的遗留查询语言。由于Hibernate是JPA的一个实现,并且您使用JPA标记了您的问题,因此该解决方案也适用于您的环境。
注2:在解决方案中,我使用了所谓的JPQL构造函数表达式,它是在select子句中使用NEW
定义的。 NEW
运算符的参数必须是完全限定的类名,例如,如果将OrderResult
类放在包com.mycompany.myproject.order
中,则表达式应如下所示:
SELECT NEW com.mycompany.myproject.order.OrderResult(...) FROM ...
注3:这只是为了提示如何实施解决方案,应该被视为pseodo代码。