2014-07-16 102 views
2

我正在使用QueryDSLSpring Data Jpa,我想執行一些動態搜索。按標準動態搜索

我按照這個Answer和它的okey BooleanBuilder但在我的情況下,我必須加入。

所以我如何讓它,如果我有3個連接player,player_team,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; 
    ... 
} 

並且對於每個酒莊我有程序存儲庫這樣的:

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

} 
+0

怎樣域模型是什麼樣子? –

+0

我已更新我的問題 – Youssef

+0

爲他的域模型提供*代碼*。什麼搜索?什麼加入? – philipxy

回答

0

您是否嘗試過使用Specification? Spring的JPA庫具有使用規格查詢結果這個方法:

List<T> findAll(Specification<T> 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") 
        ) 
       ); 
    } 
} 
+0

問題是關於'QueryDSL'而不是'規格' –

1

如果你不把額外的屬性到PlayerTeam它不應該被建模爲一個實體。關於條件下,它會

player.namePlayer.eq(...) 

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

但我想選擇只是玩家,我在我的PlayerTeam中有額外的領域。以及爲什麼你使用JPASubQuery()而不是PlayerRespository,它是findall()方法? – Youssef

+0

給定的兩個表達式是findAll方法的參數,可以通過first.and(second) –