(1 + N) выбирает с ассоциациями OnetoOne - PullRequest
13 голосов
/ 21 августа 2010

Учитывая следующую модель:

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

Ответы [ 2 ]

11 голосов
/ 21 августа 2010

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

  1. Стратегия выборки по умолчанию OneToOne - EAGER (и имейте в виду, что LAZY - это просто подсказка поставщику постоянства).
  2. LAZY может работать только на OneToOne ассоциации, если ассоциация не обнуляется (по крайней мере, без использования инструментов байт-кода).

9.1.23 OneToOne Аннотация

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

В таблице 16 перечислены элементы аннотации. это может быть указано для OneToOne аннотации и их значения по умолчанию.

@Target({METHOD, FIELD}) @Retention(RUNTIME)
public @interface OneToOne {
    Class targetEntity() default void.class;
    CascadeType[] cascade() default {};
    FetchType fetch() default EAGER;
    boolean optional() default true;
    String mappedBy() default "";
}

Я проверял следующее:

@OneToOne(optional = false, fetch = FetchType.LAZY)
@PrimaryKeyJoinColumn
private UserExt userExt;

И подтвердите, что простой from User загружает только всех пользователей

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 загружаются лениво.

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

  • использовать инструментарий байт-кода и без прокси выборка (см. Соответствующий вопрос ниже)
  • вместо этого используйте поддельный ManyToOne (не проверял это сопоставление с общим первичным ключом)
  • Стремится загрузить UserExt, используя join fetch, чтобы избежать 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»
3 голосов
/ 21 августа 2010

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

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

from 
    User u
 left join fetch 
    u.userExt
...