2015-05-25 25 views
12

Attualmente sto usando primavera successiva JPA repository di query di base personalizzato e funziona benissimo,Primavera JPA Repository query dinamica

@Query("SELECT usr FROM User usr WHERE usr.configurable = TRUE " 
       + "AND (" + 
         "lower(usr.name) like lower(:filterText) OR lower(usr.userType.classType.displayName) like lower(:filterText) OR lower(usr.userType.model) like lower(:filterText)" 
       +  ")" 
       + "") 
    public List<User> findByFilterText(@Param("filterText") String filterText, Sort sort); 

ho bisogno di modificare la query quando il testo del filtro sarà un valore separati da virgola. Ma come segue sarà una query dinamica e come posso eseguirla.

query dinamica Ho bisogno di costruire,

String sql = "SELECT usr FROM User usr WHERE usr.configurable = TRUE"; 

for(String word : filterText.split(",")) { 
       sql += " AND (lower(usr.name) like lower(:" + word + ") OR lower(usr.userType.classType.displayName) like lower(:" + word + ") OR lower(usr.userType.model) like lower(:" + word + "))"; 
} 
+1

guarda in 'JpaSpecificationExecutor' –

+1

Fornire un'implementazione per il proprio DAO ed eseguire questa query dinamica dall'implementazione. http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.single-repository-behaviour. Il DAO non dovrebbe dividersi. Dovrebbe richiedere un elenco o un Set come argomento. Il chiamante dovrebbe occuparsi della divisione. –

risposta

8

Per JB Nizet e la spring-data documentation, è necessario utilizzare un'interfaccia personalizzata + implementazione repository.

Creare un'interfaccia con il metodo:

public interface MyEntityRepositoryCustom { 
    List<User> findByFilterText(Set<String> words); 
} 

Creare un'implementazione:

@Repository 
public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom { 
    @PersistenceContext 
    private EntityManager entityManager; 

    public List<User> findByFilterText(Set<String> words) { 
     // implementation below 
    } 
} 

Estendere la nuova interfaccia nell'interfaccia Repository esistente:

public interface MyEntityRepository extends JpaRepository<MyEntity, Long>, MyEntityRepositoryCustom { 
    // other query methods 
} 

Infine, chiamare il metodo da qualche altra parte:

dao.findByFilterText(new HashSet<String>(Arrays.asList(filterText.split(",")))); 

esecuzione di query

tuo metodo di produzione variabile sql, vale a dire concatenando alcune stringhe nella query è male. Non farlo.

Il word cui si concatenato deve essere un valid JPQL identifier, vale a dire una : seguito da un java identifier start, eventualmente seguita da un java identifier part. Ciò significa che se il tuo CSV contiene foo bar,baz, tenterai di utilizzare foo bar come identificatore e otterrai un'eccezione.

È invece possibile utilizzare CriteriaBuilder per costruire la query in modo sicuro:

public List<User> findByFilterText(Set<String> words) { 
    CriteriaBuilder cb = entityManager.getCriteriaBuilder(); 
    CriteriaQuery<User> q = cb.createQuery(User.class); 
    Root<User> user = q.from(User.class); 

    Path<String> namePath = user.get("name"); 
    Path<String> userTypeClassTypeDisplayName = 
        user.get("userType").get("classType").get("displayName"); 
    Path<String> userTypeModel = user.get("userType").get("model"); 
    List<Predicate> predicates = new ArrayList<>(); 
    for(String word : words) { 
     Expression<String> wordLiteral = cb.literal(word); 
     predicates.add(
       cb.or(
        cb.like(cb.lower(namePath), cb.lower(wordLiteral)), 
        cb.like(cb.lower(userTypeClassTypeDisplayName), 
          cb.lower(wordLiteral)), 
        cb.like(cb.lower(userTypeModel), cb.lower(wordLiteral)) 
       ) 
     ); 
    } 
    q.select(doc).where(
      cb.and(predicates.toArray(new Predicate[predicates.size()])) 
    ); 

    return entityManager.createQuery(q).getResultList(); 
} 
+1

Mille grazie per la tua completa risposta. causa di fallimento compilatore devo applicare seguenti correzioni, cb.lower (word) -> cb.lower (wordLiteral) q.select (doc) -> q.select (utente) Ma con quelle correzioni quando implemento questa soluzione otterrò il seguente errore sul tempo di implementazione dell'applicazione: - Causato da: org.springframework.data.mapping.PropertyReferenceException: Nessun filtro di proprietà trovato per tipo com.ord.model.User – Channa

+0

@Channa Fixed. Sembra che i dati di primavera stiano cercando di interpretare il nome della funzione 'findByFilterText', che non dovrebbe essere eseguito. Hai fatto estendere il repository alla classe del repository personalizzato? – beerbajay

+0

Sì, ho fatto le cose come dici tu. Ciò significa che ho creato l'interfaccia "MyEntityRepositoryCustom" e successivamente la estenderò all'interfaccia repository esistente come "interfaccia pubblica MyEntityRepository estende JpaRepository , MyEntityRepositoryCustom" – Channa

2

ho cercato per la soluzione me: La denominazione dell'interfaccia "Custom" repository e implentation è molto severa (come ha detto che ci How to add custom method to Spring Data JPA)

Quindi, per essere chiari, l'intero codice: (Ma @beerbajay aveva ragione)

il metodo personalizzato di interfaccia

public interface MyEntityRepositoryCustom { 
    List<MyEntity> findSpecial(); 
} 

L'implementazione del metodo personalizzato

public class MyEntityRepositoryImpl implements MyEntityRepositoryCustom { 
    @PersistenceContext 
    private EntityManager em; 

    //custom method implementation 
    public List<Object> findSpecial() { 
     List<Object> list = em.createNativeQuery("select name, value from T_MY_ENTITY").getResultList(); 
     return list; 
    } 
} 

Il repository "originale"

@Repository 
public interface MyEntityRepository extends JpaRepository<MyEntity,Long>, MyEntityRepositoryCustom { 
    //original methods here... do not redefine findSpecial()... 
} 

è ora possibile utilizzare il repository "originale" con i nuovi metodi personalizzati

@Service 
public class MyService { 
    @Autowired 
    private DataRepository r; 

    public void doStuff() { 
     List<Object> list = r.findSpecial(); 
    } 
} 
Problemi correlati