web-dev-qa-db-ja.com

Spring-Data-QueryDslPredicateExecutorを使用したJPAとコレクションへの参加

私がこのようなデータモデル(擬似コード)を持っているとしましょう:

_@Entity
Person {
    @OneToMany
    List<PersonAttribute> attributes;
}

@Entity
PersonAttribute {
    @ManyToOne
    AttributeName attributeName;

    String attributeValue;
}

@Entity
AttributeName {
    String name;
}
_

次のように定義されたSpring-Data-JPAリポジトリがあります。

_public interface PersonRepository extends PagingAndSortingRepository<Person, Long>, QueryDslPredicateExecutor<Person>{}
_

QueryDSLのドキュメントで、PersonからPersonAttributeに結合するメカニズムがあることがわかりましたが、リポジトリのクライアントにはないQueryDslQueryオブジェクトにアクセスする必要があるようです。

私の述語でやりたいのは、値が「blue」のAttributeValue(1つの結合がある)と「eyecolor」という名前のAttributeName(別の結合がある)を持つすべてのPersonを見つけることです。 any()を使用してこれを行う方法がわかりません。また、eye_color = blueの場合のみ取得し、shoe_color = blueの場合は取得しないように強制します。

私はこのようなことができることを望んでいました:

_QPerson person = QPerson.person;
QPersonAttribute attribute = person.attributes.any();

Predicate predicate = person.name.toLowerCase().startsWith("jo")
    .and(attribute.attributeName().name.toLowerCase().eq("eye color")
          .and(attribute.attributeValue.toLowerCase().eq("blue")));
_

ただし、そこにany()があると、色に関係なく、属性値が「青」のすべてのものと「目の色」属性のすべてのものに一致します。 これらの条件をセット内の同じ属性に適用するにはどうすればよいですか?

12
digitaljoel

述語の列を直接結合することはできませんが、次のようなany()式を作成することはできます。

_QPerson.person.attributes.any().attributeValue.eq("X")
_

このアプローチには、結合式QPerson.person.attributes.any()を1つのフィルターでのみ使用できるという制限があります。ただし、この式が内部的にページングと競合しないサブクエリに変換されるという利点があります。

複数の制限がある場合は、次のように明示的にサブクエリ式を作成する必要があります

_QPersonAttribute attribute = QPersonAttribute.personAttribute;
new JPASubQuery().from(attribute)
    .where(attribute.in(person.attributes),
           attribute.attributeName().name.toLowerCase().eq("eye color"),
           attribute.attributeValue.toLowerCase().eq("blue"))
     .exists()
_

QueryDslPredicateExecutorに加えて、次のようにSpringDataを介してQuerydslクエリを使用することもできます。

_public class CustomerRepositoryImpl
 extends QueryDslRepositorySupport
 implements CustomerRepositoryCustom {

    public Iterable<Customer> findAllLongtermCustomersWithBirthday() {
        QCustomer customer = QCustomer.customer;
        return from(customer)
           .where(hasBirthday().and(isLongTermCustomer()))
           .list(customer);
    }
}
_

ここからの例 https://blog.42.nl/articles/spring-data-jpa-with-querydsl-repositories-made-easy/

18