我有两个实体:父和儿童。并且它们之间存在 @OneToOne 关系。
我有以下查询:来自Parent p left join fetch p.child 。
如果Parent中有一行存在不存在的子键(例如-1),则hibernate会为每种情况发出附加查询。
Hibernate:
select
parent0_.PARENT_ID as PARENT1_2_0_,
child1_.CHILD_ID as CHILD1_3_1_,
parent0_.CHILD_ID as CHILD2_2_0_,
child1_.NAME as NAME3_1_
from
PARENT parent0_
left outer join
CHILD child1_
on parent0_.CHILD_ID=child1_.CHILD_ID
Hibernate:
select
child0_.CHILD_ID as CHILD1_3_0_,
child0_.NAME as NAME3_0_
from
CHILD child0_
where
child0_.CHILD_ID=?
以下是代码:
@Entity
@Table(name = "PARENT")
public class Parent {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "PARENT_ID", nullable = false)
private int id;
@OneToOne(optional = true)
@JoinColumn(name = "CHILD_ID")
@NotFound(action = NotFoundAction.IGNORE)
private Child child;
}
@Entity
@Table(name="CHILD")
public class Child {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "CHILD_ID", nullable = false)
private int id;
@Column(name = "NAME")
private String name;
}
为什么会这样?如何防止这个额外的sql?
以下是数据库生成的代码:
create table PARENT(
PARENT_ID INTEGER GENERATED ALWAYS AS IDENTITY,
CHILD_ID INTEGER,
PRIMARY KEY (PARENT_ID)
);
create table CHILD(
CHILD_ID INTEGER GENERATED ALWAYS AS IDENTITY,
NAME VARCHAR(100) NOT NULL,
PRIMARY KEY (CHILD_ID)
);
insert into PARENT(CHILD_ID) values(-1);
答案 0 :(得分:0)
正确设计数据库,不要在PARENT.CHILD_ID
列中存储不存在的子ID。如果父级没有子级,则在此列中存储NULL,并为该列创建外键约束以确保该列始终保留NULL或有效的子ID。
这将允许您从映射中删除@NotFound
注释,并将删除其他查询。实际上,当Hibernate执行第一个查询时,它将获得-1作为子ID。但是由于无法知道-1是否是有效的子ID,它必须执行附加查询以确定子项是否存在(因此应该在父项中初始化),或者不是(因此应该如此)在父母中设置为null。
答案 1 :(得分:0)
你可能会尝试不同的fetchtype;
@OneToOne(optional = true, fetch = FetchType.EAGER)
private Child child;
但是,正如JB Nizet已经解释的那样,潜在的问题是存储在CHILD_ID字段中的虚构标识符。
另一种策略是通过在父类中的@OneToOne注释中添加mappedBy属性,并在子类中添加对父项的引用,或者仅在子项中设置父项来反转关系类。