2014-02-07 1 views
10

Скажем, у меня есть модель данных, как это (псевдокод):весна-данных JPA с QueryDslPredicateExecutor и присоединение в коллекцию

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

@Entity 
PersonAttribute { 
    @ManyToOne 
    AttributeName attributeName; 

    String attributeValue; 
} 

@Entity 
AttributeName { 
    String name; 
} 

У меня есть хранилище Spring-данных JPA определено, такие как:

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

Я вижу в документации QueryDSL, что существует механизм присоединения от Person к PersonAttribute, но похоже, что вам нужен доступ к объекту QueryDsl Query, который не был бы у клиента репозитория.

То, что я хотел бы сделать с моим предикатом, - это найти всех лиц, у которых есть атрибут AttributeValue (есть одно соединение) со значением «blue» и AttributeName (есть еще одно соединение) с именем «eyecolor» , Я не уверен, как бы это сделать с any() и обеспечить, чтобы я получал только те, у которых eye_color = синий, а не те, у которых shoe_color = синий.

Я надеялся, что я мог бы сделать что-то вроде этого:

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

Вы не можете напрямую присоединиться столбец в предикате, но вы можете создать любой() выражения типа этого

QPerson.person.attributes.any().attributeValue.eq("X") 

Этот подход имеет ограничение, что присоединиться выражение QPerson.person.attributes.any() может быть использован только в одном фильтр. Несмотря на то, что это выражение внутренне преобразуется в подзапрос, который не конфликтует с поисковым вызовом.

Для нескольких ограничений вам нужно будет построить подзапросы выражения в явном виде, как этого

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 вы также можете использовать Querydsl запросы с помощью Spring Data как этого

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/

+0

Да, я это понимаю. Я пытаюсь понять, есть ли способ сделать это с QueryDslPredicateExecutor, что означало бы, что мне не нужно было бы предоставлять какую-либо реализацию, а вызывающий объект репозитория мог бы создавать более интересные запросы без необходимости открывать новый метод через апи. В любом случае, спасибо за ответ и ссылку. – digitaljoel

+0

Я обновил свой ответ. –

+0

Отличное обновление, спасибо, заодно. Я знал о любом, но не вижу, как присоединиться через AttributeValue в AttributeName и сопоставить их. Я обновил свой вопрос, чтобы отразить это. – digitaljoel

 Смежные вопросы

  • Нет связанных вопросов^_^