考虑以下简单实体关联: (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 ...
}
如果进行了简单的查询:
EntityManager em = ...;
TypedQuery<EntityA> tq = em.createQuery("from EntityA a", EntityA.class);
tq.getResultList();
我在Hibernate的SQL调试输出中看到,对EntityA的每一行都进行了EntityB查询:
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=?
即使默认提取策略是EAGER(似乎是这种情况),也应该通过implizit join获取EntityB,不应该吗? 有什么问题?
但它变得更加奇怪 - 如果只加载了一个EntityA对象:
EntityA a = em.find(EntityA.class, new Long(1));
然后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=?
上述测试是使用Hibernate 3.5和JPA 2.0进行的。
答案 0 :(得分:5)
即使默认提取策略是EAGER(似乎是这种情况),也应该通过隐式连接获取EntityB,不应该吗?有什么问题?
实际上,FetchType
的默认ManyToOne
为EAGER
。但这只是表示One
方应该加载加载Many
方,而不是如何。如何由持久性提供程序决定(并且JPA不允许调整策略)。
Hibernate有一个特定的Fetch
注释,允许调整获取模式。来自文档:
2.4.5.1. Lazy options and fetching modes
JPA附带了fetch选项 定义延迟加载和获取 模式,但Hibernate有很多 此区域设置了更多选项。罚款 调整延迟加载和获取 策略,一些额外的 注释已经引入:
[...]
@Fetch
:定义用于加载关联的提取策略。FetchMode
可以是SELECT
(选择是 在关联需要时触发 待加载),SUBSELECT
(仅限 可用于收藏,使用 子选择策略 - 请参考 Hibernate参考文档 有关更多信息)或JOIN
(使用a SQLJOIN
加载关联时 加载所有者实体)。JOIN
覆盖任何惰性属性(an 通过JOIN加载的关联 战略不能懒惰。)
您可能希望尝试以下操作(如果您不介意使用提供程序特定的注释):
@ManyToOne(optional=false)
@Fetch(FetchMode.JOIN)
private EntityB entityB;
答案 1 :(得分:4)
适用于当前用例的解决方案是在语句中包含一个获取连接:
select a from entityA left join fetch a.entityB
这将获取所有关联的EntityB(并覆盖FetchType.LAZY)。
答案 2 :(得分:0)
首先,你为什么担心这个?使用ORM库的关键是你不必处理这样的细节。如果您发现某些操作运行缓慢,那么然后就会开始考虑优化查询。
我认为Hibernate的策略是有道理的,因为这种关系是ManyToOne。这意味着查询中返回的EntityB数量永远不会大于EntityAs的数量,通常会更少。因此,尝试通过连接从EntityB获取数据可能意味着发送相同数据的冗余副本。