у меня есть объект, который имеет - объект B, и B имеет - с @OneToOne двунаправленной ассоциацией.
Теперь, когда я findall записи, будьте в спящем режиме, выполняют два запроса с левым внешним объединением на 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, очевидно, который уже содержит B... так его загруженный первым запросом, не верно?
- РЕДАКТИРОВАНИЕ-
Объект 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;
}
Это - ситуация и findAll на потребности два запроса... почему?
Удар, если 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;
}
}
And B Notice вам не нужен атрибут 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 совместно используют ОДИНАКОВЫЙ присвоенный идентификатор
Но если 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, вы получите Два оператора выбора Это происходит из-за того, что таблица B не содержит столбца внешнего ключа, который указывает на таблицу A , но при использовании
"из A выборка левого соединения ab, где a.id =: id "
Вы получите только один оператор выбора , потому что A знает, как получить свой присоединенный B, используя свой столбец внешнего ключа B_ID
Как именно выглядит ваше отображение?
Правильно ли ваши классы A
и B
реализуют hashCode()
и equals()
, чтобы Hibernate мог сказать, что экземпляр A
, на который указывает B
, является тем же самым экземпляром первого A
?
Похоже, что вы пытаетесь смоделировать двунаправленное отображение один-к-одному - посмотрите раздел в руководстве об этом, чтобы увидеть рекомендуемые методы для достижения этого.