我正在使用Hibernate JPA 1.0。
我有以下类型的模型,我认为manyToOne和oneToOne关系“急切地”获取并且oneToMany“懒洋洋地”获取。
我想获取实体A及其所有关联,其中a.id =?
是否可以在单个查询中加载此实体? 或者在一系列查询中记住“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();
}
显然必须有更好的方法来做到这一点。
答案 0 :(得分:6)
答案 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%'
)