Spring 按条件动态搜索
我正在使用Spring 按条件动态搜索,spring,hibernate,jpa,spring-data,querydsl,Spring,Hibernate,Jpa,Spring Data,Querydsl,我正在使用QueryDSL和Spring数据Jpa进行动态搜索 我遵循这一点,它与BooleanBuilder没有关系,但在我的情况下,我必须进行连接 那么,如果我在player、player\u team、team上有3个连接,并且我在player的名称和他的团队的名称上有可选参数,我怎么能做到呢 ________ ___________________ _______ | player | | player_team | | team
QueryDSL
和Spring数据Jpa
进行动态搜索
我遵循这一点,它与BooleanBuilder
没有关系,但在我的情况下,我必须进行连接
那么,如果我在player
、player\u team
、team
上有3个连接,并且我在player的名称和他的团队的名称上有可选参数,我怎么能做到呢
________ ___________________ _______
| player | | player_team | | team |
|------ | |---------------- | |-------|
| id | | player_team_id (pk) | | id |
| name | | player_id (fk) | | name |
------ | team_id (fk) | -------
-----------
player.java
@Entity
@Table(...)
public class Player implements java.io.Serializable {
private Integer idPlayer ;
private String namePlayer;
private Set<PlayerTeam> player_teams = new HashSet<PlayerTeam>(0);
...
}
对于每个庄园,我都有这样的回答:
public interface PlayerRespository extends JpaRepository<Player, Integer>, QueryDslPredicateExecutor<Player> {
}
公共接口PlayerRespository扩展了JpaRepository、QueryDSL谓词执行器{
}
您是否尝试过使用规范
?Spring的JPA存储库使用以下方法使用规范查找结果:
清单findAll(规范规范)代码>
构建规范有不同的方法,我的方法是为接受来自REST服务的请求而定制的,因此我基本上创建了一个给定类型的空白实体(本例中为Foo)并设置请求中提供的任何搜索条件(例如名称),然后从每个字段构建谓词(如果指定了名称字段,则添加“name等于”bob“谓词)
以下是规范生成器的示例:
import static org.springframework.data.jpa.domain.Specifications.where;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;
import com.acme.model.security.Principal;
public class FooSpecification {
private final Foo criteria;
private String query;
public FooSpecification(String query, Foo criteria) {
this.query = query;
this.criteria = criteria;
}
public Specification<Foo> trainerEquals() {
if (criteria.getTrainer() == null) {
return null;
}
return new Specification<Foo>() {
@Override
public Predicate toPredicate(Root<Foo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.<Principal>get("trainer").<Long>get("id"), criteria.getTrainer().getId());
}
};
}
public <T> Specification<Foo> valueEquals(final T value, final String field) {
if (value == null) {
return null;
}
return new Specification<Foo>() {
@Override
public Predicate toPredicate(Root<Foo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.<T> get(field), value);
}
};
}
/**
* Convert input string to lower case, appends '%' around it and does SQL LIKE comparison with the field value, also lower cased.
* If value is null, no comparison is done. Example:
*
* value = "John";
* field = "firstName";
*
* resulting specification = "name like '%john%'"
*
* @param value string or null
* @param field field name
* @return SQL LIKE specification for the given value or null if value is null
*/
public Specification<Foo> stringLike(final String value, final String field) {
if (StringUtils.isBlank(value)) {
return null;
}
return new Specification<Foo>() {
@Override
public Predicate toPredicate(Root<Foo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(cb.lower(root.<String> get(field)), getLikePattern(value));
}
};
}
private String getLikePattern(String searchTerm) {
return new StringBuilder("%")
.append(searchTerm.toLowerCase().replaceAll("\\*", "%"))
.append("%")
.toString();
}
public Specification<Foo> fullSearch() {
return where(trainerEquals())
.and(valueEquals(criteria.getName(), "name"))
.and(valueEquals(criteria.getInstructions(), "description"))
.and(valueEquals(criteria.isAwesome(), "isAwesome"))
.and(
where(
stringLike(query, "name"))
.or(stringLike(query, "instructions")
)
);
}
}
导入静态org.springframework.data.jpa.domain.Specifications.where;
导入javax.persistence.criteria.CriteriaBuilder;
导入javax.persistence.criteria.CriteriaQuery;
导入javax.persistence.criteria.Predicate;
导入javax.persistence.criteria.Root;
导入org.apache.commons.lang3.StringUtils;
导入org.springframework.data.jpa.domain.Specification;
导入com.acme.model.security.Principal;
公共类规范{
私人最终食品标准;
私有字符串查询;
公共Foo规范(字符串查询、Foo条件){
this.query=query;
本标准=标准;
}
公共规范培训资格(){
if(criteria.getTrainer()==null){
返回null;
}
返回新规范(){
@凌驾
公共谓词toPredicate(根根、CriteriaQuery查询、CriteriaBuilder cb){
返回cb.equal(root.get(“trainer”).get(“id”)、criteria.getTrainer().getId());
}
};
}
公共规范值等于(最终T值,最终字符串字段){
如果(值==null){
返回null;
}
返回新规范(){
@凌驾
公共谓词toPredicate(根根、CriteriaQuery查询、CriteriaBuilder cb){
返回cb.equal(root.get(字段),value);
}
};
}
/**
*将输入字符串转换为小写,在其周围附加“%”,并与字段值(也是小写)进行类似SQL的比较。
*如果值为null,则不进行比较。示例:
*
*value=“约翰”;
*field=“firstName”;
*
*结果规范=“名称类似于“%john%””
*
*@param值字符串或null
*@param字段名
*@返回给定值的类似SQL的规范,如果值为null,则返回null
*/
公共规范stringLike(最终字符串值、最终字符串字段){
if(StringUtils.isBlank(值)){
返回null;
}
返回新规范(){
@凌驾
公共谓词toPredicate(根根、CriteriaQuery查询、CriteriaBuilder cb){
返回cb.like(cb.lower(root.get(field)),getLikePattern(value));
}
};
}
私有字符串getLikePattern(字符串搜索术语){
返回新的StringBuilder(“%”)
.append(searchTerm.toLowerCase().replaceAll(“\\*”,“%”)
.附加(“%”)
.toString();
}
公共规范fullSearch(){
返回位置(trainerEquals())
.和(valueEquals(criteria.getName(),“name”))
和(valueEquals(criteria.getInstructions(),“description”))
.和(valueEquals(criteria.isAwesome(),“isAwesome”))
.及(
在哪里(
stringLike(查询,“名称”))
.或(stringLike(查询,“说明”)
)
);
}
}
如果不在PlayerTeam中添加额外属性,则不应将其建模为实体
player.namePlayer.eq(...)
及
域模型是什么样子的?我已经更新了我的问题,给出了域模型的代码。什么搜索?什么连接?问题是关于QueryDSL
notSpecifications
,但我只想选择玩家,我的PlayerTeam中有额外的字段。为什么你使用JPASubQuery()而不是playerResposition,这是findall()方法?给定的两个表达式是findAll方法的参数,您可以通过first.和(second)组合它们
import static org.springframework.data.jpa.domain.Specifications.where;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;
import com.acme.model.security.Principal;
public class FooSpecification {
private final Foo criteria;
private String query;
public FooSpecification(String query, Foo criteria) {
this.query = query;
this.criteria = criteria;
}
public Specification<Foo> trainerEquals() {
if (criteria.getTrainer() == null) {
return null;
}
return new Specification<Foo>() {
@Override
public Predicate toPredicate(Root<Foo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.<Principal>get("trainer").<Long>get("id"), criteria.getTrainer().getId());
}
};
}
public <T> Specification<Foo> valueEquals(final T value, final String field) {
if (value == null) {
return null;
}
return new Specification<Foo>() {
@Override
public Predicate toPredicate(Root<Foo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(root.<T> get(field), value);
}
};
}
/**
* Convert input string to lower case, appends '%' around it and does SQL LIKE comparison with the field value, also lower cased.
* If value is null, no comparison is done. Example:
*
* value = "John";
* field = "firstName";
*
* resulting specification = "name like '%john%'"
*
* @param value string or null
* @param field field name
* @return SQL LIKE specification for the given value or null if value is null
*/
public Specification<Foo> stringLike(final String value, final String field) {
if (StringUtils.isBlank(value)) {
return null;
}
return new Specification<Foo>() {
@Override
public Predicate toPredicate(Root<Foo> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(cb.lower(root.<String> get(field)), getLikePattern(value));
}
};
}
private String getLikePattern(String searchTerm) {
return new StringBuilder("%")
.append(searchTerm.toLowerCase().replaceAll("\\*", "%"))
.append("%")
.toString();
}
public Specification<Foo> fullSearch() {
return where(trainerEquals())
.and(valueEquals(criteria.getName(), "name"))
.and(valueEquals(criteria.getInstructions(), "description"))
.and(valueEquals(criteria.isAwesome(), "isAwesome"))
.and(
where(
stringLike(query, "name"))
.or(stringLike(query, "instructions")
)
);
}
}
player.namePlayer.eq(...)
new JPASubQuery().from(playerTeam)
.where(playerTeam.player.eq(player), palyerTeam.team.name.eq(...))
.exists()