web-dev-qa-db-ja.com

JPA Criteria API:オプションの関係の場合はLEFT JOIN

基本的に初めてCriteriaAPIを使用しています。これは、ジェネリックビルダーのクエリを抽象化することです。

_public TypedQuery<T> newQuery( Manager<?,T> manager )
{
    CriteriaBuilder builder = this.entityManager.getCriteriaBuilder();

    Class<T> genericClass = ( Class<T> ) ( ( ParameterizedType ) manager.getClass().getGenericSuperclass() ).getActualTypeArguments()[1];

    CriteriaQuery<T> criteriaQuery = builder.createQuery( genericClass );
    Root<T> root = criteriaQuery.from( genericClass );

    ...
}
_

criteriaQuery.from( genericClass );を呼び出すと、デフォルトでエンティティで見つかったすべての関係に対してSQL _INNER JOIN_が生成されます。これは問題です。すべての関係がnull(DB NULLまたは外部キーを使用せず無効な参照を持つDB)であるため、これらのエンティティは結果リストに表示されず、誤った検索結果が効果的に生成されます。

例はここにあります: JPA Criteria query Path.get left join is it possibile

このクラス/メソッドによってインスタンス化されたクエリで発生したいのは、エンティティ(ここではgenericClass)のすべての関係が_optional = true_としてマップされていることです。

_@ManyToOne( FetchType.EAGER, optional = true )
@JoinColumn( name = "CLOSE_USER_ID", referencedColumnName = "USER_ID" )
private User              closer;
_

_INNER JOIN_の代わりにSQL LEFT (OUTER) JOINを生成します。

質問

これを行うための標準的なJPQの方法はありますか?もしそうなら、どのように?

PS:通常、具体的なタイプを事前に知る方法はないので、必要なことを達成できる唯一の方法は、ある種のメタモデルを使用して、手動で結合を生成することです(これは避けたいです)。


EclipseLink2.3を使用しています

12
Kawu

.from(class)は、すべての関係にINNER結合を使用するのではなく、クラスにクエリを実行するだけです。

関係は、join()またはfetch()APIを使用する場合にのみ照会され、外部結合を使用するには、JoinType.LEFTでjoin()を使用します。

https://en.wikibooks.org/wiki/Java_Persistence/Criteria#Join

Join()を呼び出さないのに、なぜ結合が表示されるのかわかりません。一部のJPAプロバイダーは、すべてのEAGER関係のフェッチに自動的に参加します。これは、表示されているものである可能性があります。私はいつもこの奇妙なことをしていますが、おそらくあなたのJPAプロバイダーはこれを行わないように構成する必要があります。そうでなければ、関係をLAZYにすることができます。

8
James

私は同じ問題を抱えていました...調査後、結論は、jpqlの左結合でこれを処理する必要があるということです。次を参照してください。 http://www.objectdb.com/Java/jpa/query/jpql/ path#Navigation_through_a_NULL_value _

2
Steph