我正在使用QueryDSL
Spring Data Jpa
,我希望执行一些动态搜索。
我跟着这个Answer和它BooleanBuilder
,但在我的情况下我必须加入。
那么,如果我在player
,player_team
,team
上有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> {
}
答案 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")
)
);
}
}