为什么hibernate执行两个查询以急切加载@OneToOne双向关联?

我有实体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=?
首先查询加载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;
}
实体B:
@Entity
public class B implements Serializable{
    // id and other ecc ecc
    @OneToOne(mappedBy="b")
    A a;
}
这就是情况,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;
    }

}
并且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;
    }

}
让我们测试(你可以测试你想要的)
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共享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;
    }

}   
而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,您将获得两个select语句它是因为B Table不包含指向表A的任何外键列但是通过使用   “来自A左连接获取a.b,其中a.id =:id” 您将只获得一个select语句,因为A知道如何使用其B_ID外键列检索其连接的B.     
你的映射到底是什么样的? 你的
A
B
类是否正确实现了
hashCode()
equals()
,这样Hibernate可以告诉
B
指向的
A
实例与第一个
A
的实例相同? 听起来您正在尝试建模双向一对一映射 - 请查看本手册中的部分,以查看完成它的推荐方法。     

要回复问题请先登录注册