考虑以下简单实体关联:(EntityA)*-1(EntityB)在数据库中使用EntityA中的外键(entityB_id).
JPA实体正在单向映射此关系:
@Entity
EntityA {
@Id
@GeneratedValue
private long id;
@Column(nullable=false,length=250)
private String name;
@ManyToOne(optional=false)
private EntityB entityB;
... getter/setter ...
}
@Entity
EntityB {
@Id
@GeneratedValue
private long id;
@Column(nullable=false,length=250)
private String name;
... getter/setter ...
}
Run Code Online (Sandbox Code Playgroud)
如果进行简单查询:
EntityManager em = ...;
TypedQuery<EntityA> tq = em.createQuery("from EntityA a", EntityA.class);
tq.getResultList();
Run Code Online (Sandbox Code Playgroud)
我在Hibernate的SQL调试输出中看到EntityB查询是针对EntityA的每一行完成的:
Hibernate:
select
entitya0_.id as id8_,
entitya0_.entityB_id as entityB3_8_,
entitya0_.name as name8_
from
EntityA entitya0_
Hibernate:
select
entityb0_.id as id4_0_,
entityb0_.name as name4_0_
from
EntityB entityb0_
where
entityb0_.id=?
Run Code Online (Sandbox Code Playgroud)
即使默认的提取策略是EAGER(似乎是这种情况),也应该通过implizit join获取EntityB,不应该吗?怎么了?
但它变得更加奇怪 - 如果只加载了一个EntityA对象:
EntityA a = em.find(EntityA.class, new Long(1));
Run Code Online (Sandbox Code Playgroud)
那么Hibernate似乎理解这项工作:
Hibernate:
select
entitya0_.id as id1_1_,
entitya0_.entityB_id as entityB3_1_1_,
entitya0_.name as name1_1_,
entityb1_.id as id12_0_,
entityb1_.name as name12_0_
from
EntityA entitya0_
inner join
EntityB entityb1_
on entitya0_.entityB_id=entityb1_.id
where
entitya0_.id=?
Run Code Online (Sandbox Code Playgroud)
上面的测试是使用Hibernate 3.5和JPA 2.0完成的.
即使默认提取策略是EAGER(似乎是这种情况),也应该通过隐式连接获取EntityB,不应该吗?怎么了?
事实上,默认FetchType
的ManyToOne
是EAGER
.但是,这只是说,One
方应得到加载时的Many
侧加载,而不是如何.如何由持久性提供程序决定(并且JPA不允许调整策略).
Hibernate有一个特定的Fetch
注释,允许调整获取模式.从文档:
2.4.5.1.懒惰选项和提取模式
JPA附带了fetch选项来定义延迟加载和获取模式,但Hibernate在此区域中设置了更多选项.为了微调延迟加载和获取策略,引入了一些额外的注释:
[...]
@Fetch
:定义用于加载关联的提取策略.FetchMode
可以是SELECT
(当需要加载关联时触发选择),SUBSELECT
(仅适用于集合,使用子选择策略 - 请参阅Hibernate参考文档以获取更多信息)或JOIN
(使用SQLJOIN
在加载时加载关联)所有者实体).JOIN
覆盖任何延迟属性(通过JOIN策略加载的关联不能是惰性的).
您可能希望尝试以下操作(如果您不介意使用提供程序特定的注释):
@ManyToOne(optional=false)
@Fetch(FetchMode.JOIN)
private EntityB entityB;
Run Code Online (Sandbox Code Playgroud)
适用于当前用例的解决方案是在语句中包含一个 fetch join:
select a from entityA left join fetch a.entityB
Run Code Online (Sandbox Code Playgroud)
这将获取所有关联的 EntityB(并覆盖 FetchType.LAZY)。
归档时间: |
|
查看次数: |
3777 次 |
最近记录: |