2010-10-22 21 views
10

En mi proyecto Wicket + JPA/Hibernate + Spring, gran parte de la funcionalidad se basa en la página Bandeja de entrada donde, utilizando muchas opciones de filtrado (no todas deben usarse), los usuarios pueden restringir el conjunto de objetos con los que quieren trabajar Me preguntaba cuál es la mejor estrategia para implementar este filtrado. En la versión anterior de esta aplicación, la consulta de búsqueda se construyó concatenando cadenas que contenían condiciones de SQL. Hace poco leí acerca de la nueva API de Criteria que proporciona JPA. ¿Lo recomendaría antes que trabajar con la cadena de búsqueda? ¿Y cómo se combina esto con la capa DAO? ¿No está construyendo la consulta de búsqueda utilizando Criteria API en la capa empresarial una brecha en la separación de capas?Consultas de búsqueda compleja JPA

Respuesta

4

Para filtrar consultas como las que describes, definitivamente recomiendo usar la API de criterios de Hibernate o JPA debido al soporte para consultas condicionales. Usualmente coloco el código de construcción de criterios en mi DAO y paso todos los argumentos requeridos (posiblemente nulos).

He aquí un método DAO ejemplo de una aplicación de alquiler de coches ejemplo utilizando el API de Hibernate criterios:

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 llamada createAlias ​​se puede utilizar cuando se necesitaría una combinación en SQL.

+0

+1 por concepto básico. Aunque uno podría discutir sobre el uso del parámetro customerNameOrID. Parece anidar un "o" en los parámetros de lo contrario "y" relacionados ". Esto puede volverse arbitrariamente complejo si surge un caso cuando los tipos de datos son iguales. Para estos casos, probablemente sea mejor crear sobrecargas con diferentes conjuntos de parámetros. –

+0

@Adriaan Koster Su lista de argumentos puede ser reemplazada por una clase que dibuje su búsqueda, como ** VehicleRentalContractCriteria ** –

+0

@Martin 'customerNameOrID' proviene de un campo de entrada de texto en el que el usuario puede ingresar una parte del cliente nombre, o una identificación de cliente. No veo cómo sugieres que simplifiques el OR anidado, muéstranoslo. –

1

incluso prefiero usar Criteria sobre HQL y SQL, para mí la modularidad y también el rendimiento, porque cuando el proyecto entra en producción, el principal problema al que nos enfrentamos es el rendimiento, ni HQL ni SQL pueden competir con Criteria actuación.

Añadiendo a la anterior La capa DAO se crea para acceder a los datos, y esta capa debe ser tan clara como el vidrio sin codificación compleja o lógica comercial, pero en caso de criterios, uno tiene que escribir una lógica (crear criterios) para llegar a una forma mejor y sintonizada de acceder al objeto, entonces, en mi opinión, no hay infracción al poner tanta lógica en la capa DAO.

+0

No creo que una API de alto nivel pueda superar a SQL, ya que todo termina como consultas SQL después de todo. –

1

dos enfoques:

1 .. Dependiendo de qué tipo de filtrado que necesitan que usted puede ser capaz de lograr esto mediante la búsqueda, por ejemplo, indexe todos los objetos con Lucene y luego use consultas de búsqueda para realizar el filtrado. por ejemplo, construir una consulta como:

título: "La manera correcta" & mod_date: [20020101 A 20030101]

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


2 .. O usando criterios ...

que haría uso de un nuevo tipo de fallos criterios API de hibernación:

http://relation.to/12805.lace

En lugar de un método que se acumula unas muy grandes criterios, que iba a tratar de separar toda la lógica utilizando criterios Independiente -

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

Con una combinación de estos dos sería capaz de construir subir los criterios fácilmente

Otro lugar para buscar inspiración son los buscadores dinámicos de grilles. Esto es esencialmente lo que estás tratando de lograr de una manera estática.

http://www.grails.org/doc/1.0.x/guide/single.html#5.4.1 dinámicos buscadores

Si realmente desea la completa separación de las capas se podía aplicar una gramática sencilla. Luego, analiza esto para crear los criterios relevantes. Esto permitiría cambiar las implementaciones de criterios subyacentes. Si esto es apropiado depende de cuán crucial es para usted esta abstracción.

Cuestiones relacionadas