14

次のモデルを検討します。

@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: 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 を選択)。

ただし、完全な User Entity (「from User」) が必要なため、hibernate は最初の結果行ごとに 1 つの選択を生成します。

デフォルトのフェッチ戦略はEAGERではなくLAZYであるべきなので、私はそれを理解していません。LAZY に強制しても問題は解決しませんでした。

4

3 に答える 3

12

ここで遅延読み込みを防ぐには2つの問題があります。

  1. のデフォルトのフェッチ戦略はOneToOneです(これは永続性プロバイダーへの単なるヒントであるEAGERことに注意してください)。LAZY
  2. LAZYアソシエーションがnull許容でない場合にのみ、OneToOneアソシエーションで機能します(少なくともバイトコードインストルメンテーションを使用しない場合)。

9.1.23OneToOneアノテーション

OneToOne注釈は、1対1の多重度を持つ別のエンティティへの単一値の関連付けを定義します。通常、参照されているオブジェクトのタイプから推測できるため、関連するターゲットエンティティを明示的に指定する必要はありません。

表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:
    選択する
        user0_.USER_ID as USER1_0_、
        user0_.FIRST_NAME as FIRST2_0_、
        user0_.LAST_NAME as LAST3_0_
    から
        USER user0_

また、N個の追加クエリを実行せず、UserExt遅延ロードされます。

したがって、関連付けが必須の場合は、適切なマッピングを使用してください:)また、必須でない場合は、次のいずれかを行う必要があります。

  • バイトコードインストルメンテーションとプロキシなしフェッチを使用します(以下の関連する質問を参照)
  • 代わりに偽のManyToOneを使用してください(共有主キーを使用してこのマッピングをテストしませんでした)
  • を使用してUserExtを熱心にロードし、join fetch後続のN個の選択を回避します(もちろん、これは別のテーブルのポイントを何らかの形で無効にします)

クエリインターフェイスを使用する場合、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();

関連する質問

参照

  • JPA1.0仕様
    • セクション9.1.23「OneToOneアノテーション」
于 2010-08-21T19:00:15.380 に答える
3

@ManyToOne や @OneToOne などの -ToOne を使用する場合のデフォルトのフェッチ戦略は、fetch=FetchType.EAGER NOT fetch=FetchType.LAZY です。

しかし、Hibernate HQL はデフォルトのフェッチ戦略をオーバーライドします。1 つのクエリのみを使用して完全に初期化されたオブジェクトを取得する場合は、呼び出す必要があります。

from 
    User u
 left join fetch 
    u.userExt
于 2010-08-21T12:18:22.013 に答える