如何在初始化(不加载)延迟集合

时间:2017-08-11 09:38:06

标签: java hibernate jpa lazy-loading

考虑遵循简单的实体模型

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)。

寻找解决方案。

1 个答案:

答案 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代码。