С учетом следующей модели:
@Entity
public class User {
@Id
@Column(name = "USER_ID")
private Long userId;
@Column(name = "FIRST_NAME")
private String firstName;
@Column(name = "LAST_NAME")
private String lastName;
@OneToOne
@PrimaryKeyJoinColumn
private UserExt userExt;
... //getters and setters
}
@Entity
public class UserExt {
@Id
@Column(name="USER_ID")
private Long id;
private String cdpId;
private Date lastChanged;
... //getters and setters
}
при выполнении:
Query query = session.createQuery("from User");
List<User> list = query.list();
Hibernate выполняет
Hibernate: select user0_.USER_ID as USER1_0_, user0_.FIRST_NAME as FIRST2_0_, user0_.LAST_NAME as LAST3_0_, user0_.EXT_USERNAME as EXT4_0_ from USER user0_
Hibernate: select userext0_.USER_ID as USER1_1_0_, userext0_.cdpId as cdpId1_0_, userext0_.lastChanged as lastChan3_1_0_ from USER_EXT userext0_ where userext0_.USER_ID=?
Hibernate: select userext0_.USER_ID as USER1_1_0_, userext0_.cdpId as cdpId1_0_, userext0_.lastChanged as lastChan3_1_0_ from USER_EXT userext0_ where userext0_.USER_ID=?
...
...
Использование запроса с конкретными свойствами работает (выберите u.firstName, u.userExt.cdpId).
Однако так как я хочу получить полную сущность пользователя («от пользователя»), hibernate генерирует один выбор для каждой строки результата в первой.
Я не получаю его, так как стратегия выборки по умолчанию должна быть LAZY, а не EAGER. Принуждение к LAZY не решило проблему.
Здесь есть две проблемы, предотвращающие отложенную загрузку:
OneToOne
- EAGER
(и имейте в виду, что LAZY
просто подсказка поставщику постоянства). LAZY
может работать только с ассоциацией OneToOne
, если ассоциация не допускает обнуления (по крайней мере, без использования инструментария байт-кода). 9.1.23 Аннотация OneToOne
Аннотация
OneToOne
определяет однозначная ассоциация с другим сущность, которая имеет индивидуальный множественность. Это не нормально необходимо указать связанный целевой объект явно, поскольку он может обычно выводится из типа объект, на который ссылаются.В таблице 16 перечислены элементы аннотации. который может быть указан для
OneToOne
аннотации и их значения по умолчанию.@Target ({METHOD, FIELD}) @Retention (RUNTIME) public @interface OneToOne { Класс targetEntity () по умолчанию void.class; CascadeType [] cascade () по умолчанию {}; FetchType fetch () по умолчанию EAGER; логическое значение optional () по умолчанию true; String mappedBy () по умолчанию ""; }
Я проверил следующее:
@OneToOne(optional = false, fetch = FetchType.LAZY)
@PrimaryKeyJoinColumn
private UserExt userExt;
И подтвердите, что простой от пользователя
загружает только всех пользователей
Hibernate: select user0_.USER_ID as USER1_0_, user0_.FIRST_NAME as FIRST2_0_, user0_.LAST_NAME as LAST3_0_ from USER user0_
и не выполняет N дополнительных запросов, UserExt
являются загружается лениво.
Итак, если ассоциация является обязательной, используйте соответствующее сопоставление :) А если она не является обязательной, вам придется либо:
объединенную выборку
, чтобы избежать N последующих выборок ( конечно, это каким-то образом лишает смысла отдельную таблицу) Обратите внимание, что Hibernate> = 3.x игнорирует аннотацию Fetch, когда вы используете интерфейс Query. В этом случае вам нужно написать это явно. это пример:
EntityManager em = [...]
[...]
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<User> criteria = builder.createQuery(User.class);
Root<User> usersRoot = criteria.from(User.class);
usersRoot.fetch("Address", JoinType.LEFT);
List<User> users = em.createQuery(criteria).getResultList();
Стратегия выборки по умолчанию при использовании -ToOne, например @ManyToOne и @OneToOne, - fetch = FetchType.EAGER НЕ fetch = FetchType.LAZY
Но Hibernate HQL переопределяет стратегию выборки по умолчанию. Если вы хотите получить полностью инициализированный объект с помощью всего одного запроса, вы должны вызвать
from
User u
left join fetch
u.userExt