通过其元素的多个属性过滤器集合 - QueryDSL
问题描述:
我正在研究基于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
变量再次访问集合时,我自然会得到相当于将AND EXISTS...
附加到sql查询的结果,这不是所需的结果。我也尝试使用getCollection().contains()
,但我无法创建描述这种情况的Expression<LanguageToName>
。
有没有办法创建一个Predicate
可以通过集合中元素的多个属性过滤实体,即查询实体的字段?
答
我在我的项目中遇到了同样的问题。 我的解决方法是手动构建存在的子查询。
假设你的两个类被映射为实体:
@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();