按标准动态搜索

时间:2014-07-16 23:58:12

标签: spring hibernate jpa spring-data querydsl

我正在使用QueryDSL Spring Data Jpa,我希望执行一些动态搜索。

我跟着这个Answer和它BooleanBuilder,但在我的情况下我必须加入。

那么,如果我在playerplayer_teamteam上有3个联接,并且我在玩家名称和团队名称上有可选参数,我怎么能成功?

 ________       ___________________       _______
| 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);  
    ...
}

team.java

@Entity
@Table(...)
public class Team implements java.io.Serializable {

    private Integer idTeam ;
    private String nameTeam;
    private Set<PlayerTeam> player_teams = new HashSet<PlayerTeam>(0);  
    ...
}  

player_team.java

@Entity
@Table(...)
public class PlayerTeam implements java.io.Serializable {

    private Integer idPlayerTeam ;
    private Team team;
    private Player paleyr;
    ...
} 

对于每个酒庄,我都有这样的存储库:

public interface PlayerRespository extends JpaRepository<Player, Integer>, QueryDslPredicateExecutor<Player> {

}

2 个答案:

答案 0 :(得分:1)

如果您没有将额外的属性添加到PlayerTeam中,则不应将其建模为实体。关于它的条件

player.namePlayer.eq(...)

new JPASubQuery().from(playerTeam)
    .where(playerTeam.player.eq(player), palyerTeam.team.name.eq(...))
    .exists()

答案 1 :(得分:0)

您是否尝试过使用Specification? Spring的JPA Repositories有这种使用规范查找结果的方法:

List<T> findAll(Specification<T> spec);

有不同的方法来构建规范,我的方法是为接受来自我的REST服务的请求而定制的,所以我基本上创建了一个给定类型的空白实体(在这种情况下为Foo)并设置了提供的任何搜索条件。请求(例如名称),然后我从每个字段构建谓词(如果指定了name字段,则添加'name equals“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")
                    )
                );
    }
}