(1 + N) выбирает с ассоциациями OnetoOne

С учетом следующей модели:

@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 не решило проблему.

13
задан Pascal Thivent 21 August 2010 в 19:03
поделиться

2 ответа

Здесь есть две проблемы, предотвращающие отложенную загрузку:

  1. Стратегия выборки по умолчанию для OneToOne - EAGER (и имейте в виду, что LAZY просто подсказка поставщику постоянства).
  2. 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 являются загружается лениво.

Итак, если ассоциация является обязательной, используйте соответствующее сопоставление :) А если она не является обязательной, вам придется либо:

  • использовать инструментарий байт-кода и no-proxy fetch ( см. соответствующий вопрос ниже)
  • вместо этого используйте поддельный ManyToOne (не тестировал это сопоставление с общим первичным ключом)
  • нетерпеливо загружает 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();

Связанные вопросы

Ссылка

  • Спецификация JPA 1.0
    • Раздел 9.1.23 «Аннотация OneToOne»
11
ответ дан 2 December 2019 в 00:30
поделиться

Стратегия выборки по умолчанию при использовании -ToOne, например @ManyToOne и @OneToOne, - fetch = FetchType.EAGER НЕ fetch = FetchType.LAZY

Но Hibernate HQL переопределяет стратегию выборки по умолчанию. Если вы хотите получить полностью инициализированный объект с помощью всего одного запроса, вы должны вызвать

from 
    User u
 left join fetch 
    u.userExt
3
ответ дан 2 December 2019 в 00:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: