Reputation: 6266
I am using QueryDSL
with Spring Data Jpa
and i want execute some dynamic search.
I follow this Answer and it's okey with BooleanBuilder
But in my case I have to make joins.
So how can i make it if i have 3 joins on player
, player_team
, team
and i have optional parameters on the name of player and name of his team ?
________ ___________________ _______
| 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;
...
}
and for each domaine i have respository like that :
public interface PlayerRespository extends JpaRepository<Player, Integer>, QueryDslPredicateExecutor<Player> {
}
Upvotes: 2
Views: 3359
Reputation: 22200
If you don't put extra properties into PlayerTeam it shouldn't be modeled as an entity. Concerning the conditions it would be
player.namePlayer.eq(...)
and
new JPASubQuery().from(playerTeam)
.where(playerTeam.player.eq(player), palyerTeam.team.name.eq(...))
.exists()
Upvotes: 1
Reputation: 9868
Have you tried using Specification
? Spring's JPA Repositories has this method for finding results using Specifications:
List<T> findAll(Specification<T> spec);
There are different approaches for building a specification, my approach is tailored for accepting request from my REST service, so I essentially make a blank entity of a given type (Foo in this case) and set whatever search criteria was provided in the request (name for example), then I build predicates from each field (if name field is specified then add 'name equals "bob"' predicate).
Here is an example of a Specification builder:
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")
)
);
}
}
Upvotes: 0