吹,如果 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;
}
}
B 注意你不需要 mappedBy属性,因为@PrimaryKeyJoinColumn
@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;
}
}
让我们测试(你可以测试,如果你想)
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());
请注意,我使用 MutableInt 字段(由 Integer 属性封装)而不是 Integer,因为 Integer是不可变类型,因此 A 和 B 共享相同的分配 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;
}
}
和乙
@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;
}
}
去测试
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);
通过使用所有者方B,您将获得两个选择语句它发生是因为B表不包含任何指向表A的外键列但是通过使用
“从 A 左连接获取 a.id = :id 的 ab”
您将只得到一个 select 语句,因为 A 知道如何使用其 B_ID 外键列检索其连接的 B