(1 + N)选择OnetoOne关联

Dav*_*vid 13 java performance orm hibernate one-to-one

考虑以下型号:

@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
}
Run Code Online (Sandbox Code Playgroud)

执行时:

Query query = session.createQuery("from User");
List<User> list = query.list();
Run Code Online (Sandbox Code Playgroud)

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=?
...
...
Run Code Online (Sandbox Code Playgroud)

使用具有特定属性的查询(选择u.firstName,u.userExt.cdpId).

但是,由于我想要完整的用户实体("来自用户"),因此hibernate会为第一个中的每个结果行生成一个选择.

我没有得到它,因为默认的提取策略应该是LAZY而不是EAGER.强迫它到LAZY并没有解决问题.

Pas*_*ent 11

这里有两个阻止延迟加载的问题:

  1. 默认的提取策略OneToOneEAGER(并记住这LAZY只是对持久性提供程序的提示).
  2. LAZYOneToOne如果关联是非可空的(至少不使用字节码检测),则只能在关联上工作.

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 "";
}
Run Code Online (Sandbox Code Playgroud)

我测试了以下内容:

@OneToOne(optional = false, fetch = FetchType.LAZY)
@PrimaryKeyJoinColumn
private UserExt userExt;
Run Code Online (Sandbox Code Playgroud)

并确认简单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(没有使用共享主键测试此映射)
  • 急切地使用a加载UserExt join fetch以避免N个后续选择(当然,这会以某种方式击败单独的表)

请注意,使用Query接口时,Hibernate> = 3.x会忽略Fetch批注.在这种情况下,您需要明确地编写它.这是一个例子:

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();
Run Code Online (Sandbox Code Playgroud)

相关问题

参考

  • JPA 1.0规范
    • 第9.1.23节"OneToOne注释"