获取多个onetoMany关系Hibernate JPA

时间:2010-07-13 14:20:08

标签: java hibernate orm jpa

我正在使用Hibernate JPA 1.0。

我有以下类型的模型,我认为manyToOne和oneToOne关系“急切地”获取并且oneToMany“懒洋洋地”获取。

我想获取实体A及其所有关联,其中a.id =?

  • OneToMany B
    • B oneToOne C
      • C oneToMany D
    • B oneToOne E
      • E oneToMany D
    • B oneToOne F.
      • F oneToMany D

是否可以在单个查询中加载此实体? 或者在一系列查询中记住“n + 1选择问题”!

到目前为止,我加载所有A关联的解决方案是执行以下操作:

“从一个JOIN FETCH中选择DISTINCT a a.bs WHERE a.id =:aID”

然后使用代码进行迭代以获取所有其他关联。

收集B bs = A.getBs();

         for (final B b : bs) {
         b.getCs().getDs().size();
         b.getEs().getDs().size();
         b.getFs().getDs().size();
         }

显然必须有更好的方法来做到这一点。

3 个答案:

答案 0 :(得分:6)

您可能有兴趣阅读this文章。我测试了两个

@Fetch(FetchMode.SUBSELECT)

和  还使用Set而不是List,结合fetch = FetchType.EAGER,它可以工作。

答案 1 :(得分:2)

使用FETCH JOIN。从JPA 1.0规范:

  

4.4.5.3获取联接

     

FETCH JOIN启用提取关联   作为执行a的副作用   查询。指定FETCH JOIN   实体及其相关实体。

     

获取连接的语法是

fetch_join ::= [ LEFT [OUTER] | INNER ] JOIN FETCH join_association_path_expression
     

由...引用的关联   FETCH JOIN子句的右侧   必须是属于的协会   作为结果返回的实体   的查询。不允许这样做   指定一个标识变量   右边引用的实体   FETCH JOIN子句的一侧,和   因此隐含地引用了   获取的实体无法显示   在查询的其他地方。

     

以下查询返回一组   部门。作为副作用,   相关员工   部门也被检索,甚至   虽然他们不是   显式查询结果。执着   员工的领域或财产   热切的提取是完全的   初始化。初始化了   关系属性   检索到的员工是   由元数据确定   员工实体类。

SELECT d
FROM Department d LEFT JOIN FETCH d.employees
WHERE d.deptno = 1
     

获取联接具有相同的联接   语义作为相应的内在   或外部联接,但相关的   右侧指定的对象   加入操作的一面不是   在查询结果中返回或   否则在查询中引用。   因此,例如,如果部门1   有五名员工,以上查询   返回五个引用   第1部门实体。

当然,明智地使用它,不要加入太多牌桌,否则你会杀死表演。

答案 2 :(得分:0)

  

寻找可靠和/或官方来源的答案。

JBoss ORM文档怎么样?

https://docs.jboss.org/hibernate/orm/current/userguide/html_single/chapters/fetching/Fetching.html

  
    

定义抓取的范围有很多:

  
     

static

获取策略的静态定义在   映射。静态定义的提取策略用于   没有任何动态定义的策略

     

SELECT 执行单独的SQL select以加载数据。这个可以   要么是EAGER(第二个选择是立即发行),要么是LAZY(   第二个选择被延迟,直到需要数据)。这是   策略一般称为N + 1。

     

加入本质上是EAGER的抓取方式。要获取的数据是   通过使用SQL外连接获得。

     

BATCH 执行单独的SQL选择以加载大量相关数据   使用IN-restriction作为SQL WHERE子句的一部分的项目   批量大小。同样,这可以是EAGER(第二个选择是   立即发出)或LAZY(第二个选择被推迟到   需要数据。)

     

SUBSELECT 执行单独的SQL select以加载相关数据   关于用于加载所有者的SQL限制。再次,这可以   是EAGER(第二个选择是立即发布)或LAZY(第二个   选择被延迟,直到需要数据。)

           

动态(有时称为运行时)

动态定义实际上是以用例为中心的。有多种方法可以定义动态   取:

     

获取配置文件在映射中定义,但可以启用/禁用   会话。

     

HQL / JPQL ,Hibernate和JPA Criteria查询都具备此功能   指定提取,特定于所述查询。

     

实体图从Hibernate 4.2(JPA 2.1)开始,这也是一个   选项。

为了证明上面的答案,这是一个例子:

  

FetchMode.SUBSELECT 为了演示FetchMode.SUBSELECT的工作原理,我们   将要修改要使用的FetchMode.SELECT映射示例   FetchMode.SUBSELECT:

     

示例17. FetchMode.SUBSELECT映射示例:

@OneToMany(mappedBy = "department", fetch = FetchType.LAZY)
@Fetch(FetchMode.SUBSELECT)
private List<Employee> employees = new ArrayList<>();
  

现在,我们将获取与给定
匹配的所有Department实体   过滤标准,然后导航他们的员工集合。

     

Hibernate将通过生成单个来避免N + 1查询问题   用于初始化所有员工集合的SQL语句   先前获取的部门实体。而不是使用   传递所有实体标识符,Hibernate只是重新运行前一个   获取部门实体的查询。

     

示例18. FetchMode.SUBSELECT映射示例:

List<Department> departments = entityManager.createQuery(
    "select d " +
    "from Department d " +
    "where d.name like :token", Department.class)
    .setParameter( "token", "Department%" )
    .getResultList();

log.infof( "Fetched %d Departments", departments.size());

for (Department department : departments ) {
    assertEquals(3, department.getEmployees().size());
}
  

- 获取2个部门

SELECT
    d.id as id1_0_
FROM
    Department d
where
    d.name like 'Department%'

-- Fetched 2 Departments

SELECT
    e.department_id as departme3_1_1_,
    e.id as id1_1_1_,
    e.id as id1_1_0_,
    e.department_id as departme3_1_0_,
    e.username as username2_1_0_
FROM
    Employee e
WHERE
    e.department_id in (
        SELECT
            fetchmodes0_.id
        FROM
            Department fetchmodes0_
        WHERE
            d.name like 'Department%'
    )