2011-02-17 13 views
10

He visto y trabajado con muchos códigos DAO antiguos basados ​​en JDBC que generalmente comienzan con métodos CRUD. Mi pregunta se refiere específicamente a los métodos de recuperación, o 'buscadores'. Normalmente lo que encuentro es que los DAOs comienzan con dos métodos:Patrón DAO y el principio de abierto abierto

  • hallazgo y devolver todos los
  • recuperar una instancia específica en base a un identificador único

Más a menudo que no, los dos buscadores son insuficientes Por lo general terminan viendo una clase DAO modificado varias veces para añadir métodos de búsqueda como la siguiente:

  • hallazgo y devolver todos donde {condición}

Lo que sucede es que se añaden más métodos cuando una nueva { condiciones} debe ser compatible o los métodos existentes se modifican para agregar nuevos parámetros como indicadores para modificar la consulta SQL dentro del método para soportar las condiciones adicionales.

Es un enfoque feo y viola el principio de Open-Closed. Siempre ha sido una pena ver las clases de DAO continuamente modificadas cada vez que se necesita soportar alguna nueva condición de recuperación. La investigación sobre esta cuestión a menudo me señala el patrón de repositorio y las condiciones de encapsulado para la recuperación como Specifications o los objetos de consulta y luego los pasa a un método de búsqueda. Pero esto solo parece factible si tiene una colección en la memoria de todo el conjunto de datos o si está utilizando algún tipo de ORM (estoy trabajando con código JDBC anterior)

Considero una solución que las cargas perezosas todo el conjunto de datos que DAO administra como una colección en la memoria y luego usando el patrón de especificación como consultas para la recuperación. Luego implemento algún tipo de observador en la colección que solo actualiza la base de datos cuando se invocan los métodos de creación, actualización o eliminación. Pero obviamente el rendimiento y la escalabilidad sufren significativamente.

¿Alguna idea de esto?


Gracias por las respuestas hasta el momento. Tengo una idea: ¿cuáles son sus opiniones sobre el uso del patrón Comando/Política para encapsular las solicitudes de acceso a datos? Cada comando concreto concreto puede representar un tipo específico de acceso y se puede pasar a un invocador. Terminaría con numerosas clases de Comando Concreto, pero cada una se enfocará en un solo tipo de acceso y debería ser muy comprobable y estar aislada.

public abstract class Command<R>{ 
     public <R> execute(); 
     public void setArguments(CommandArguments args){ 
      //store arguments 
     } 
    } 

    //map based structure for storing and returning arguments 
    public class CommandArguments{ 
     public String getAsString(String key); 
     public String getAsInt(String key); 
     //... others 
    } 

    //In some business class... 
    Command command = CommandFactory.create("SearchByName"); 
    CommandArguments args = new CommandArguments(); 
    args.setValue("name", name); 
    // others 
    command.setArguments(args); 
    List<Customer> list = command.execute(); 

Respuesta

4

Hemos utilizado iBatis para nuestra capa de datos ORM y hemos podido implementar lo que usted propone en una consulta al pasar un objeto de parámetro con los diversos campos que podría desear utilizar como parámetros.

Luego, en su cláusula WHERE puede especificar cada campo como una cláusula de condición, pero solo si se rellena en el objeto de parámetro. Si solo un campo en el param obj no es nulo, entonces es el único que se usará para filtrar los resultados.

Por lo tanto, si necesita agregar campos a sus parámetros, simplemente cambie el SQL y el paramObj. Luego puede tener 2 métodos que devuelven TODO o un subconjunto basado en el conjunto de parámetros pasados, o al menos este enfoque reduciría la cantidad de consultas requeridas.

p. Ej. algo parecido a ...

SELECT * FROM MY_TABLE 
WHERE FIELD_ZERO = paramObj.field0 
<isNotNull property="paramObj.field1">AND FIELD_ONE = paramObj.field1</isNotNull> 
<isNotNull property="paramObj.field2">AND FIELD_TWO = paramObj.field2</isNotNull> 
<isNotNull property="paramObj.field3">AND FIELD_THREE = paramObj.field3</isNotNull> 
+1

+1 He hecho lo mismo en iBatis, admitiendo rangos de fechas opcionales, predicados LIKE opcionales, y así sucesivamente. Funciona bien. (Por cierto, no desea la condición de clave principal en su ejemplo.) –

+0

Supongo que esto podría funcionar en cláusulas where relativamente más simples. Pero sería difícil escalar si las condiciones se volvieran más complejas o si algunas recuperaciones dependieran de las uniones de otra mesa. Por ejemplo, puedo tener un CustomerDAO que solo recupere Clientes según un nombre. Pero, ¿qué sucede si también quiero recuperar un cliente en función de saldos pendientes que necesitarán información de otra mesa? Terminaría teniendo un generador de consultas complejo dentro de mis DAO solo para anticipar los diferentes parámetros que se pueden pasar. –

+0

@eplozada cierto, entonces necesitaría más opciones, su pregunta comienza haciendo referencia a CRUD simple y cómo se expande. Puede tener un método de buscador separado para su ejemplo de tabla de unión y luego tener parámetros sobre eso también. Si está buscando una llamada a un método que satisfaga todos los escenarios posibles que podría prever para consultar su tabla de clientes junto con las tablas vinculadas, creo que podría ser tremendamente complicado. Los métodos separados en su DAO son preferibles a los que en mi humilde opinión. Para condiciones más complejas, el nombre del método indicaría el tipo de consulta al consumidor – MadMurf

0

En lugar de crear un método de búsqueda específico para cada condición posible cuando aparezcan, ¿por qué no crear una API de buscador genérico? Esto podría tomar la forma de un DAO que tenga un Enum interno para representar campos, y un método que tome una lista de instancias de una clase interna del DAO con campos que representen qué campo del DAO filtrar, qué filtro aplicar en él y qué condición (Y, O, etc.).

Es un poco difícil de configurar, y para proyectos pequeños puede ser exagerado, pero es ciertamente factible. Los marcos ORM suelen tener algo similar ya incorporado, por lo que es posible que desee considerar la adopción de uno de ellos (o al menos mirar cómo lo han implementado al diseñar su propia solución para la retroadaptación en su aplicación heredada).

+0

Un buscador genérico o más bien un buscador extensible era lo que intentaba lograr cuando implementé el patrón de especificación. Estaba cerca de lo que estaba buscando ya que los objetos SearchCriteria pasados ​​en el método del buscador único también se implementaron desde la perspectiva del dominio. No quería que los objetos de SearchCrietria se vincularan a una implementación específica, ya que, en primer lugar, vencería el objetivo de los DAO. –

+0

con genéricos, puede crear una infraestructura de tipo SearchCriteria donde tiene una clase de criterios separada vinculada a cada DAO sin que el DAO se vincule nuevamente a la clase de criterios. – jwenting

Cuestiones relacionadas