2016-08-19 3 views
3

Я работаю над компонентом динамического фильтра на основе QueryDSL с использованием SpringData для выполнения запроса. Таким образом, я создаю Predicate экземпляров из полученного объявления данных, передавая его QueryDslPredicateExecutor. Для динамического доступа к атрибутам сущности я использую общий PathBuilder, введенный в класс сущности.Коллекция фильтров по нескольким атрибутам его элементов - QueryDSL

Рассмотрим следующий (упрощенный) код:

class Offer { 
    List<LanguageToName> names; 
} 
class LanguageToName { 
    String name; 
    String language; 
} 

При попытке запросить Offer entites, которые имеют в своей коллекции name элемента с атрибутом «ABC», я просто создать предикат следующим образом:

pathBuilder.getCollection("names", LanguageToName.class).any().getString("name") 
    .like("%" + fieldData.getFieldValue() + "%"); 

Однако мне не удалось найти решение для фильтрации коллекции по нескольким атрибутам содержащихся объектов с использованием PathBuilder. Когда я добавляю код выше с .and() и снова получаю доступ к коллекции через переменную pathBuilder, я, естественно, получаю результат, эквивалентный добавлению SQL-запроса с AND EXISTS..., что не является желаемым результатом. Я также пытался использовать getCollection().contains(), но мне не удалось создать Expression<LanguageToName>, который описывал бы такой случай.

Есть ли способ создать Predicate, который будет фильтровать объекты по нескольким атрибутам элементов из коллекции, то есть поле запрашиваемого объекта?

ответ

0

Я столкнулся с той же проблемой в своем проекте. Мое обходное решение - создать подзапрос существует вручную.

Если предположить, что ваши оба класса отображаются как объекты:

@Entity 
@Table(name = "Offer") 
public class Offer { 

    @Id 
    String id; 

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "offer") 
    List<LanguageToName> names; 
} 

@Entity 
@Table(schema = "dcsdba", name = "Language_To_Name") 
public class LanguageToName { 

    @Id 
    String id; 

    @ManyToOne(fetch= FetchType.LAZY) 
    @JoinColumn(name="Offer_id") 
    private Offer offer; 

    String name; 
    String language; 
} 

Простой запрос с любым():

BooleanExpression namesFilter = QOffer.offer.names.any().name.eq("Esperanto"); 

карты для

select 
    offer0_.id as id1_7_ 
from 
    offer offer0_ 
where 
    exists (
     select 
      1 
     from 
      dcsdba.language_to_name names1_ 
     where 
      offer0_.id=names1_.offer_id 
      and names1_.name=? 
    ) 

подзапрос:

BooleanExpression namesFilter = JPAExpressions.selectOne() 
      .from(languageToName) 
      .where(languageToName.offer.eq(QOffer.offer) 
        .and(languageToName.name.eq("Esperanto"))) 
      .exists(); 

Карты для:

select 
    offer0_.id as id1_7_ 
from 
    offer offer0_ 
where 
    exists (
     select 
      1 
     from 
      dcsdba.language_to_name languageto1_ 
     where 
      languageto1_.offer_id=offer0_.id 
      and languageto1_.name=? 
    ) 

, который отлично сочетается предыдущий SQL. Вы можете добавить дополнительные условия, такие как:

BooleanExpression namesFilter = JPAExpressions.selectOne() 
      .from(languageToName) 
      .where(languageToName.offer.eq(QOffer.offer) 
        .and(languageToName.name.eq("Esperanto")) 
        .and(languageToName.language.like("E%"))) 
      .exists(); 
Смежные вопросы