2017-08-11 55 views
0

考虑下面这个简单的实体模型如何有选择地加载休眠实体,同时还初始化(不加载)延迟集合

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,比如“从Order where description ...”。例如,这加载了1000个实体,并且项目集合被延迟加载。我强制通过调用大小来加载它们。

当然这导致了一个N + 1个问题,所以我决定使用批量抓取物品。只需在项目集合中添加批量大小注释,并按预期方式添加更少的查询。

但是,我一点都不感兴趣,“细节”,但因为它是一个一对一的渴望负荷时,有每笔订单总是加载这个查询。我只是想解决这些问题。

为了解决这个问题,我尝试做一个没有细节的选择,但我不知道如何在查询中包含项目(集合),以便它以完全相同的方式加载,就像我选择所有,然后可以在稍后的调用中使用批量大小的懒加载)。一些建议是在where子句中使用join,但是它使用空的数组列表(而不是使用PersistentBag来初始化我的集合,就像Lazy加载一样)。

寻找解决方案。

+0

为什么赚不到'Detail'延迟加载的? – ujulu

+0

该应用程序的其他部分依赖于默认(急切)加载。而且,所有的解决方案都是非常简单的(字节码检测等),我不想冒险打破现有的代码。 – smi

回答

0

一个可能的解决方案是:

  • 创建一个POJO其中将包含查询结果。例如:

    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实例列表:

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查询。

    注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代码。

  • +0

    但是您的解决方案不考虑物品集合。我希望项目中的顺序细节,据我所知,我不能在构造函数参数中包含集合。或者我错过了什么? – smi