blo*_*low 9 java hibernate jpa one-to-one bidirectional-relation
我有实体A有一个B实体,而B有一个带有@OneToOne双向关联的A.
现在,当我找到所有A记录时,hibernate在B上执行左外连接的两个查询,如下所示:
select a.id, a.id_b, a.field1, b.id, b.field1 from A as a, B as b left outer join b ON b.id=a.id_b;
select a.id, a.id_b, a.field1, b.id, b.field1 from A as a, B as b left outer join b ON b.id=a.id_b WHERE b.id=?
Run Code Online (Sandbox Code Playgroud)
首先查询加载A和B字段,这没关系,但为什么要执行第二次查询来重新加载A?我认为这个查询加载了B中的A内容,但是这个A显然是包含B的A ......所以它已经加载了第一个查询,是不是真的?
- 编辑 -
实体A:
@Entity
public class A implements Serializable{
// id and other ecc ecc
@OneToOne
@JoinColumn(name="id_b")
B b;
}
Run Code Online (Sandbox Code Playgroud)
实体B:
@Entity
public class B implements Serializable{
// id and other ecc ecc
@OneToOne(mappedBy="b")
A a;
}
Run Code Online (Sandbox Code Playgroud)
这就是情况,A上的findAll需要两个查询......为什么?
Blow,如果A和B 共享使用主键连接两个实体的同一主键列,则应使用@PrimaryKeyJoinColumn
@Entity
public class A implements Serializable {
private MutableInt id = new MutableInt();
private B b;
public void setIdAsMutableInt(MutableInt id) {
this.id = id;
}
@Id
@GeneratedValue
public Integer getId() {
return id.intValue();
}
public void setId(Integer id) {
this.id.setValue(id);
}
/**
* Any ToOne annotation, such as @OneToOne and @ManyToOne, is EARGELY loaded, by default
*/
@OneToOne(fetch=FetchType.LAZY)
@PrimaryKeyJoinColumn
@Cascade(CascadeType.SAVE_UPDATE)
public B getB() {
return b;
}
public void setB(B b) {
b.setIdAsMutableInt(id);
this.b = b;
}
}
Run Code Online (Sandbox Code Playgroud)
并且B请注意,由于@PrimaryKeyJoinColumn,您不需要mappedBy属性
@Entity
public class B implements Serializable {
private MutableInt id = new MutableInt();
private A a;
public void setIdAsMutableInt(MutableInt id) {
this.id = id;
}
@Id
public Integer getId() {
return id.intValue();
}
public void setId(Integer id) {
this.id.setValue(id);
}
@OneToOne(fetch=FetchType.LAZY)
@PrimaryKeyJoinColumn
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
}
Run Code Online (Sandbox Code Playgroud)
让我们测试(你可以测试你想要的)
A a = new A();
B b = new B();
a.setB(b);
/**
* b property will be saved because Cascade.SAVE_UPDATE
*/
Serializable id = session.save(a);
b = (B) session
.createQuery("from B b left join fetch b.a where b.id = :id")
.setParameter("id", id)
.list()
.get(0);
Assert.assertEquals(b.getId(), b.getA().getId());
Run Code Online (Sandbox Code Playgroud)
注意我使用MutableInt字段(由Integer属性封装)而不是Integer,因为Integer 是一个不可变类型,A和B共享SAME分配的id
但是如果A和B 通过使用其他主键而加入,则应使用@JoinColumn和mappedBy(双向关系,右),如下所示
@Entity
public class A implements Serializable {
private Integer id;
private B b;
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
/**
* mappedBy="a" means: Look at "a" field / property at B Entity. If it has any assigned value, join us Through B_ID foreign key column
*/
@OneToOne(fetch=FetchType.LAZY, mappedBy="a")
/**
* Table A has a foreign key column called "B_ID"
*/
@JoinColumn(name="B_ID")
@Cascade(CascadeType.SAVE_UPDATE)
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
Run Code Online (Sandbox Code Playgroud)
而B
@Entity
public class B implements Serializable {
private Integer id;
private A a;
public void setIdAsMutableInt(MutableInt id) {
this.id = id;
}
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@OneToOne(fetch=FetchType.LAZY)
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
}
Run Code Online (Sandbox Code Playgroud)
去测试
A a = new A();
B b = new B();
/**
* Set up both sides
* Or use some kind of add convenience method
*/
a.setB(b);
b.setA(a);
/**
* b property will be saved because Cascade.SAVE_UPDATE
*/
Serializable id = session.save(a);
b = (B) session
.createQuery("from B b left join fetch b.a where b.id = :id")
.setParameter("id", id)
.list()
.get(0);
Run Code Online (Sandbox Code Playgroud)
通过使用所有者B,您将获得两个select语句它是因为B Table 不包含指向表A的任何外键列但是通过使用
"来自A左连接获取ab,其中a.id =:id"
您将只获得一个select语句,因为A知道如何使用其B_ID外键列检索其连接的B.
归档时间: |
|
查看次数: |
6181 次 |
最近记录: |