Cla*_*sso 5 hibernate hibernate-mapping
我正在使用 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;
}
Run Code Online (Sandbox Code Playgroud)
生成对应表的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);
Run Code Online (Sandbox Code Playgroud)
结构非常简单:子项通过外键 ( PARENT_ID )链接到父项,该外键也是唯一的。使用以下代码从数据库中检索子实例:
entityManager.find(Child.class,1l);
Run Code Online (Sandbox Code Playgroud)
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 = ?;
Run Code Online (Sandbox Code Playgroud)
Child 被配置为急切地加载 Parent,所以第一个查询是正确的:Child 和 Parent 表被连接和获取。我试图将 Parent 的“child”属性的 fetch 策略设置为 LAZY 以防止第二次查询,但它没有效果。
如何使用单个查询急切加载双向关系?事实上,如果检索到 N 个子实例,则执行 N+1 个查询。
小智 0
正如此处指出的,解决方案是使用非拥有方。如果您通过以下方式修改映射,将拥有方移动到父级(为简洁起见,受保护的字段包):
@Entity
public class Parent {
@Id Long id;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="CHILD_ID")
Child child;
}
Run Code Online (Sandbox Code Playgroud)
和
@Entity
public class Child {
@Id Long id;
@OneToOne(mappedBy="child",fetch=FetchType.EAGER)
Parent parent;
}
Run Code Online (Sandbox Code Playgroud)
然后您可以查询生成单个选择的子项,因为有一个 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);
}
Run Code Online (Sandbox Code Playgroud)
结果是:
休眠:选择parent0_.id作为id1_1_0_,child1_.id作为id1_0_1_,child1_.PARENT_ID作为PARENT_I2_0_1_从父parent0_左外连接子child1_在parent0_.id=child1_.PARENT_ID,其中parent0_.id=?
| 归档时间: |
|
| 查看次数: |
1648 次 |
| 最近记录: |