次のエンティティがあるとします。
@Entity
@Table(name = "subscription")
public class Subscription implements Serializable {
private static final long serialVersionUID = 1L;
@ElementCollection
@CollectionTable(joinColumns= @JoinColumn(name="subscription"))
private Set<Code> mainCodes = new HashSet<>();
@ElementCollection
@CollectionTable(joinColumns= @JoinColumn(name="subscription"))
private Set<Code> otherCodes = new HashSet<>();
}
そのため、Subscription は、関心のある 0 個以上の mainCode または otherCode を持つことができます。通過する特定のオブジェクトの mainCode および otherCode を取得できます。コード自体は、単一の String フィールドのみを持つ埋め込み可能です。
「OR」メカニズムを使用してこれらのコレクションを検索する JPA クエリ (または CriteriaBuilder) を作成するにはどうすればよいですか?
基本的に、次のようなクエリを探しています。
select s from subscription s where :myMainCode IN s.mainCodes OR :otherCode IN s.otherCodes
このようなことは CriteriaBuilder で実行できますか、それともより明示的なクエリを使用する必要がありますか? もしそうなら、クエリはどのように見えますか?
編集: CriteriaBuilderでこれを試しました:
final CriteriaBuilder cb = this.entityManager.getCriteriaBuilder();
final CriteriaQuery<Subscription> cq = cb.createQuery(Subscription.class);
final Root<Subscription> root = cq.from(Subscription.class);
final Expression<Collection<Code>> mainCodes = root.get("mainCodes");
final Predicate containsMainCode = cb.isMember(obj.getClassCode(), mainCodes);
final Expression<Collection<Code>> otherCodes = root.get("otherCodes");
final Predicate containsOtherCode = cb.isMember(obj.getOtherCode(), otherCodes);
final Predicate searchPredicate = cb.or(containsMainCode, containsOtherCode);
cq.select(root).where(searchPredicate);
ただし、これにより、関連する両方のコレクションの内部結合が作成されます。つまり、データベースに mainCode の行があり、otherCode の行がない場合、結果は返されないため、次のクエリが生成されます。
SELECT t0.ID
FROM Subscription_OTHERCODES t2, Subscription_MAINCODES t1, subscription t0
WHERE ((t1.CODESYSTEM = ?) AND (t1.CODE = ?)) OR ((t2.CODESYSTEM = ?) AND (t2.CODE = ?))) AND ((t1.subscription = t0.ID) AND (t2.subscription = t0.ID))
そのため、一致する mainCode が見つかったとしても、otherCode がない場合は失敗します。