web-dev-qa-db-ja.com

JPA:埋め込まれた要素のコレクションを熱心にフェッチする方法

次のモデルを考えます

@Entity
// JPA and JAXB annotations here
public class Employee implements Serializable {
     // other fields, annotations, stuffs
     ...
     @ElementCollection(fetch = FetchType.LAZY,
        targetClass = Address.class)
     @CollectionTable(name = "employee_address",
        schema = "hris",
        joinColumns = @JoinColumn(name = "employee_id",
                nullable = false,
                referencedColumnName = "employee_id",
                foreignKey = @ForeignKey(ConstraintMode.CONSTRAINT)))
     protected Set<Address> addresses;
     // setters, getters
     ...
 }

 @Embeddable
 // JAXB annotations here
 public class Address implements Serializable {
      // fields, setters, getters
 }

Addressクラスには@Embeddableアノテーションが付けられており、Employeeクラスにはaddressesの埋め込み要素コレクションがあります。要素コレクションのfetchFetchType.LAZYに設定されます。ここで、熱心に初期化されたアドレスを持つすべての従業員を取得する@NamedQueryを作成したいと思います。 JPA 2.1に基づいてJOIN FETCHエンティティコレクションでのみ機能します@OneToManyまたは@ManyToManyで注釈されていることを知って、有効なJPQLを作成するにはどうすればよいですか埋め込まれた要素のコレクションを熱心に取得できるクエリですか?

11
Warren M. Nocos

JPA 2.1仕様(JSR 338)では、フェッチ結合がエンティティ関係でのみ機能する(ただし、埋め込み可能ではない)というヒントはありません。 JSR 338、セクション4.4.5.3でも、次のように述べています。

FETCH JOINは、クエリの実行の副作用として、関連付けまたは要素コレクションのフェッチを有効にします。

別のヒントとして、JPAプロバイダーとしてHibernate 4.3.11で実行された次の最小限の例(本質的にはあなたのものに似ています)は単一のクエリになります。

埋め込み可能なアドレス:

@Embeddable public class Address { private String city; }

従業員エンティティ:

@Entity public class Employee {

    @Id private Long id;

    @ElementCollection(fetch = FetchType.LAZY)
    @CollectionTable(name = "address", 
           joinColumns = @JoinColumn(name="employee_id"))
    private Set<Address> addresses;

}

JPQLクエリ:

em.createQuery("select e from Employee e join fetch e.addresses").getResultList();

結果のSQLクエリ:

select
    employee0_.id as id1_1_,
    addresses1_.employee_id as employee1_1_0__,
    addresses1_.city as city2_5_0__ 
from
    Employee employee0_ 
inner join
    address addresses1_ on employee0_.id=addresses1_.employee_id

したがって、上記のJPQLクエリは問題を解決するようです。

6
8hZWKA

ちなみに、より効果的な方法は、結合を使用するnotですが、副選択です。

@Fetch(FetchMode.SUBSELECT)
@BatchSize(size=500)

1つではなく2つの選択を行いますが、それほどあいまいさは生じません。

3
Oleg Gritsak