通过其元素的多个属性过滤集合-QueryDSL

Ond*_* K. 5 java hibernate querydsl

我正在使用SpringData对查询执行使用基于QueryDSL的动态过滤器组件。因此,我Predicate将从接收到的数据广告创建实例,并将其传递给QueryDslPredicateExecutor。为了动态访问实体属性,我使用泛型PathBuilder类型输入实体类。

考虑以下(简化)代码:

class Offer {
    List<LanguageToName> names;
}
class LanguageToName {
    String name;
    String language;
}
Run Code Online (Sandbox Code Playgroud)

当我尝试查询Offer其集合name元素中具有属性“ abc”的实体时,我仅按如下方式创建谓词:

pathBuilder.getCollection("names", LanguageToName.class).any().getString("name")
    .like("%" + fieldData.getFieldValue() + "%");
Run Code Online (Sandbox Code Playgroud)

但是,我无法提出一种使用来通过包含对象的多个属性过滤集合的解决方案PathBuilder。当我将上面的代码附加到.and()并通过pathBuilder变量再次访问集合时,我自然得到的结果等同于将sql query添加到AND EXISTS...,这不是期望的结果。我也尝试使用getCollection().contains(),但无法创建Expression<LanguageToName>描述这种情况的。

有没有一种方法可以创建一个Predicate将通过集合中元素的多个属性(即所查询实体的字段)过滤实体的实体?

Les*_*iak 1

我在我的项目中遇到了同样的问题。我的解决方法是手动构建存在子查询。

假设您的两个类都映射为实体:

@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;
}
Run Code Online (Sandbox Code Playgroud)

使用any() 进行简单查询:

BooleanExpression namesFilter = QOffer.offer.names.any().name.eq("Esperanto");
Run Code Online (Sandbox Code Playgroud)

映射到

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=?
    )
Run Code Online (Sandbox Code Playgroud)

子查询:

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

映射到:

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=?
    )
Run Code Online (Sandbox Code Playgroud)

这与之前的 SQL 完全匹配。您可以添加其他条件,例如:

BooleanExpression namesFilter = JPAExpressions.selectOne()
            .from(languageToName)
            .where(languageToName.offer.eq(QOffer.offer)
                    .and(languageToName.name.eq("Esperanto"))
                    .and(languageToName.language.like("E%")))
            .exists();
Run Code Online (Sandbox Code Playgroud)