【问题标题】:Dynamic search by criteria按条件动态搜索
【发布时间】:2014-09-07 16:32:56
【问题描述】:

我正在使用QueryDSLSpring Data Jpa,我想执行一些动态搜索。

我关注这个AnswerBooleanBuilder 没关系,但就我而言,我必须加入。

那么,如果我在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> {

}

【问题讨论】:

  • 领域模型是什么样子的?
  • 我已经更新了我的问题
  • 给出领域模型的代码。什么搜索?什么加入?

标签: spring hibernate jpa spring-data querydsl


【解决方案1】:

如果您不将额外属性放入 PlayerTeam,则不应将其建模为实体。关于它的条件

player.namePlayer.eq(...)

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

【讨论】:

  • 但我只想选择球员,而且我的 PlayerTeam 中确实有额外的场地。为什么你使用 JPASubQuery() 而不是 PlayerRespository 和它的 findall() 方法?
  • 给定的两个表达式是 findAll 方法的参数,您可以通过 first.and(second) 组合它们
【解决方案2】:

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

List&lt;T&gt; findAll(Specification&lt;T&gt; spec);

构建规范有不同的方法,我的方法是为接受来自我的 REST 服务的请求而量身定制的,所以我基本上创建了一个给定类型的空白实体(在本例中为 Foo)并设置在请求(例如名称),然后我从每个字段构建谓词(如果指定了名称字段,则添加 '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")
                    )
                );
    }
}

【讨论】:

  • 问题是关于QueryDSL 而不是Specifications
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-04
  • 2015-03-11
  • 2012-03-31
  • 1970-01-01
相关资源
最近更新 更多