我正在使用Hibernate 4.3.8.Final和Oracle 11g数据库。 我在两个实体之间定义了一个非常简单的双向关系,名为Parent和Child,如下所示(省略了getter和setter):
@Entity
public class Parent {
@Id
private Long id;
@OneToOne(mappedBy="parent",fetch=FetchType.LAZY)
private Child child;
}
@Entity
public class Child {
@Id
private Long id;
@OneToOne(fetch=FetchType.EAGER)
@JoinColumn(name="PARENT_ID")
private Parent parent;
}
生成相应表的SQL代码是:
CREATE TABLE PARENT
(
ID NUMBER(10)
);
CREATE UNIQUE INDEX PARENT_PK ON PARENT(ID);
ALTER TABLE PARENT ADD (
CONSTRAINT PARENT_PK
PRIMARY KEY
(ID)
USING INDEX PARENT_PK
ENABLE VALIDATE);
--------------
CREATE TABLE CHILD
(
ID NUMBER(10),
PARENT_ID NUMBER(10) NOT NULL
);
CREATE UNIQUE INDEX CHILD_PK ON CHILD (ID);
CREATE UNIQUE INDEX CHILD_U01 ON CHILD (PARENT_ID);
ALTER TABLE CHILD ADD (
CONSTRAINT CHILD_PK
PRIMARY KEY
(ID)
USING INDEX CHILD_PK
ENABLE VALIDATE,
CONSTRAINT CHILD_U01
UNIQUE (PARENT_ID)
USING INDEX CHILD_U01
ENABLE VALIDATE);
ALTER TABLE CHILD ADD (
CONSTRAINT CHILD_R01
FOREIGN KEY (PARENT_ID)
REFERENCES PARENT (ID)
ENABLE VALIDATE);
结构非常简单:子项通过外键( PARENT_ID )链接到父项,该外键也是唯一的。 使用以下代码从数据库中检索子实例:
entityManager.find(Child.class,1l);
Hibernate执行两个查询。似乎第一个用于加载关系的第一个方向(从子级到父级),第二个用于加载另一个关系(从父级到子级):
SELECT child0_.id AS id1_0_0_,
child0_.PARENT_ID AS PARENT_ID2_0_0_,
parent1_.id AS id1_1_1_
FROM Child child0_
LEFT OUTER JOIN
Parent parent1_
ON child0_.PARENT_ID = parent1_.id
WHERE child0_.id = ?;
SELECT child0_.id AS id1_0_1_,
child0_.PARENT_ID AS PARENT_ID2_0_1_,
parent1_.id AS id1_1_0_
FROM Child child0_
LEFT OUTER JOIN
Parent parent1_
ON child0_.PARENT_ID = parent1_.id
WHERE child0_.PARENT_ID = ?;
Child配置为急切加载Parent,因此第一个查询是正确的:Child和Parent表被连接和获取。我试图将Parent的“child”属性的获取策略设置为LAZY以防止第二个查询,但它没有效果。
如何使用单个查询急切加载双向关系? 实际上,如果检索到N个子实例,则执行N + 1个查询。
答案 0 :(得分:0)
正如here所指出的,解决方案是使用非拥有方。如果您修改映射,将拥有方移动到Parent(字段包以保护简洁):( / p>)
@Entity
public class Parent {
@Id Long id;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="CHILD_ID")
Child child;
}
和
@Entity
public class Child {
@Id Long id;
@OneToOne(mappedBy="child",fetch=FetchType.EAGER)
Parent parent;
}
然后您可以查询生成单个选择的Child,因为有一个FK列:
@Test
public void shouldQueryTheDatabaseOnlyOnce() {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("stackoverflow");
EntityManager entityManager = emf.createEntityManager();
Child child = entityManager.find(Child.class, 2l);
assertEquals((Long)1l, child.parent.id);
}
结果是:
Hibernate:选择parent0_.id为id1_1_0_,child1_.id为id1_0_1_,child1_.PARENT_ID为PARENT_I2_0_1_来自Parent parent0_ left outer join Child child__ on parent0_.id = child1_.PARENT_ID where parent0_.id =?