次のモデルを考えます
@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
の埋め込み要素コレクションがあります。要素コレクションのfetch
はFetchType.LAZY
に設定されます。ここで、熱心に初期化されたアドレスを持つすべての従業員を取得する@NamedQuery
を作成したいと思います。 JPA 2.1に基づいてJOIN FETCH
エンティティコレクションでのみ機能します@OneToMany
または@ManyToMany
で注釈されていることを知って、有効なJPQL
を作成するにはどうすればよいですか埋め込まれた要素のコレクションを熱心に取得できるクエリですか?
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クエリは問題を解決するようです。
ちなみに、より効果的な方法は、結合を使用するnotですが、副選択です。
@Fetch(FetchMode.SUBSELECT)
@BatchSize(size=500)
1つではなく2つの選択を行いますが、それほどあいまいさは生じません。