2010-10-22 17 views
10

Nel mio progetto Wicket + JPA/Hibernate + Spring, gran parte delle funzionalità si basa sulla pagina della posta in arrivo dove, utilizzando molte opzioni di filtro (non tutte devono essere utilizzate), gli utenti possono limitare il set di oggetti con cui vogliono lavorare. Mi stavo chiedendo quale sia la migliore strategia per implementare questo filtro? Nella vecchia versione di questa applicazione, la query di ricerca è stata creata concatenando stringhe contenenti condizioni SQL. Recentemente ho letto della nuova API Criteria fornita da JPA: consiglieresti di utilizzare questa funzione con la stringa di ricerca? E come si combina con il livello DAO? Non sta creando la query di ricerca utilizzando l'API Criteria nel livello aziendale una violazione della separazione dei livelli?Query di ricerca complesse JPA

risposta

4

Per il filtraggio di query come la descrizione, si consiglia di utilizzare l'API di criteri Hibernate o JPA a causa del supporto per le query condizionali. Di solito inserisco il codice di costruzione dei criteri nei DAO e trasmetto tutti gli argomenti necessari (eventualmente null).

Ecco un metodo DAO esempio da un'applicazione di autonoleggio esempio usando il criterio Hibernate API:

public List<VehicleRentalContract> list(Long contractID, 
      String customerNameOrID, Date date, 
      String vehicleDescriptionOrRegistration) { 
     Criteria criteria = getSession().createCriteria(
       VehicleRentalContract.class); 
     // contractID filter 
     if (contractID != null && contractID != 0) { 
      criteria.add(Restrictions.eq("id", contractID)); 
     } 
     // customerNameOrID filter 
     if (customerNameOrID != null && customerNameOrID.length() > 0) { 
      try { 
       Long customerID = Long.parseLong(customerNameOrID); 
       criteria.add(Restrictions.eq("customer.id", customerID)); 
      } catch (NumberFormatException e) { 
       // assume we have a customer name 
       String customerNameQuery = "%" + customerNameOrID.trim() + "%"; 
       criteria.createAlias("customer", "customer").add(
         Restrictions.or(Restrictions.like("customer.firstName", 
           customerNameQuery), Restrictions.like(
           "customer.lastName", customerNameQuery))); 
      } 
     } 
     // date filter 
     if (date != null) { 
      criteria.add(Restrictions.and(
        Restrictions.le("rentalPeriod.startDate", date), 
        Restrictions.ge("rentalPeriod.endDate", date))); 
     } 

     // vehicleDescriptionOrRegistration filter 
     if (vehicleDescriptionOrRegistration != null 
       && vehicleDescriptionOrRegistration.length() > 0) { 
      String registrationQuery = "%" 
        + Vehicle 
          .normalizeRegistration(vehicleDescriptionOrRegistration) 
        + "%"; 
      String descriptionQuery = "%" 
        + vehicleDescriptionOrRegistration.trim() + "%"; 

      criteria.createAlias("vehicle", "vehicle").add(
        Restrictions.or(Restrictions.like("vehicle.registration", 
          registrationQuery), Restrictions.like(
          "vehicle.description", descriptionQuery))); 
     } 

     List<VehicleRentalContract> contracts = criteria.list(); 
     return contracts; 
} 

La chiamata CREATEALIAS può essere utilizzata in cui si avrebbe bisogno di un join in SQL.

+0

+1 per il concetto di base. Sebbene si possa discutere sull'utilizzo del parametro customerNameOrID. Sembra annidare un "o" nei parametri altrimenti "e" -related. Questo può diventare arbitrariamente complesso se si verifica un caso in cui i tipi di dati sono uguali. In questi casi è probabilmente meglio creare sovraccarichi con set di parametri diversi. –

+0

@Adriaan Koster L'elenco degli argomenti può essere sostituito da una classe che disegna la ricerca, ad esempio ** VehicleRentalContractCriteria ** –

+0

@Martin 'customerNameOrID' viene da un campo di input di testo in cui l'utente può immettere una parte del cliente nome o un ID cliente. Non vedo come suggerisci di semplificare l'OR annidato, per favore mostraci. –

1

anche io preferisco utilizzare Criteri su HQL e SQL, per me la ragione sarà la modularità e anche le prestazioni, perché quando il progetto entra in produzione, il problema principale che dobbiamo affrontare sono le prestazioni, né HQL né SQL possono competere con Criteria su prestazione.

Aggiunta a sopra Il livello DAO viene creato per accedere ai dati e questo livello deve essere chiaro come il vetro senza alcuna codifica complessa o logica aziendale, ma in caso di criteri, si deve scrivere una logica (creare criteri) per arrivare a un modo migliore e sintonizzato per accedere all'oggetto, quindi, a mio modo di vedere, non c'è alcuna violazione nel mettere molta logica nel livello DAO.

+0

Non penso che nessuna API di alto livello possa sovraperformare SQL, perché tutto finisce come query SQL dopo tutto. –

1

due approcci:

1 .. a seconda del tipo di filtraggio è necessario si può essere in grado di raggiungere questo obiettivo con la ricerca per esempio indicizzare tutti gli oggetti con Lucene e quindi utilizzare le query di ricerca per eseguire il filtraggio. ad esempio, costruire una query come:

titolo: "Il modo giusto" & mod_date: [20.020.101 20.030.101 TO]

See: http://lucene.apache.org/java/2_4_0/queryparsersyntax.html


2 .. O utilizzando criteri ...

userei il nuovo type-safe criteri api da hibernate:

http://relation.to/12805.lace

Invece di un metodo che si accumula molto grandi criterio, mi piacerebbe provare a separare fuori tutta la logica utilizzando criteri indipendenti -

http://docs.jboss.org/hibernate/core/3.5/reference/en/html/querycriteria.html#querycriteria-detachedqueries

Con una combinazione di questi due si sarebbe in grado di costruire criteri facilmente.

Un altro luogo dove cercare ispirazione sono i cercatori dinamici dei graal. Questo è essenzialmente ciò che stai cercando di ottenere in modo statico.

http://www.grails.org/doc/1.0.x/guide/single.html#5.4.1 dinamici Finders

se si vuole veramente completa separazione degli strati si potrebbe implementare una semplice grammatica. Quindi analizzarlo per creare i criteri pertinenti. Ciò consentirebbe la modifica delle implementazioni dei criteri sottostanti. Se questo è appropriato dipende da quanto sia importante per te questa astrazione.