Arquitectura del Proveedor de Datos

En este post describo como se va a estructurar mi Proveedor de Datos Servidor Cliente.
De manera general cuento cómo voy a obtener los datos del SQL server, la manera de tratarlos antes de enviarlos al cliente, y la inteligencia que debería programar en el explorador para hacer mas fácil el consumo de estos.
Allí vamos…

 

Voy a pensar en voz alta como debería funcionar este control:

El primer paso : el acceso a los datos del SQL Server.

No voy a lidiar con la automatización de la configuración de un SqlDataAdapter, eso lo dejo para otro tipo de control como ser algún generador de regla de negocios o el diseñador de Datasets que puede funcionar bastante bien.

Para hacerme con los datos del SQL Server voy a pedir como parámetro un objeto SqlDataAdapter ya configurado, de tal forma que este sea totalmente independiente.

Estoy pensando en generar algún tipo de paginado para tablas muy grandes. Mi asesor en todo lo que sea SQL Server, Horacio Gonzalez me ha recomendado un nuevo comando que viene en SQL server 2012 y que describe en su blog con el título de Nuevas funcionalidades TSQL en SQL Server 2012.

Esta opción esta muy buena pero he decidido descartarla por ahora por ser muy nueva. No todo el mundo tiene instalado un SQL Server 2012.

Así que vamos a pensar otra manera. ¿ Qué pasaría si antes que nada creo algún tipo de índice para llevarme al cliente y desde allí pedir lo que necesito de una manera mas acotada ?

En ese caso debería ordenar la tabla de SQL por alguna columna que me interese buscar, dividirla en paginas de X cantidad de registros y quedarme con el primer valor de cada pagina, armar una tabla con todos esos valores y enviarla al cliente.

¿ Cómo hago eso en TSQL sin mucho esfuerzo ? …. voilá !!!  ROW_NUMBER() es la solución.

Que tal si tomo, por ejemplo, todos las valores del campo Nombre en una tabla de Afiliados cuyo ROW_NUMBER() sea divisible por 500 exactamente. Esto me devolvería una tabla con el Nombre de lo Afiliados en la posición 0, 500 , 1000, 1500 … etc. Entonces si quisiera buscar a “Perez Juan” primero buscaría en mi índice del lado del cliente, tomaría el valor anterior y posterior al dato que estoy buscando,en este caso “Perez Amelia” y “Perez Martitn”, y  luego llamaría al servidor con una búsqueda acotada entre estos dos valores, lo que me va a devolver alrededor de 500 registros entre los que se encuentra “Perez Juan”. Por último, y ya del lado del cliente, busco a “Perez Juan” entre esos 500 registros.

Se podría usar una sentencia TSQL como la siguiente para obtener el índice:

Select * from (Select ROW_NUMBER() OVER (ORDER BY Nombre) -1 AS FilaNumero,Nombre from Afiliados)  as Indice where (cast(FilaNumero as decimal)/500) – (FilaNumero/500) = 0

La única condición para que esto funcione rápidamente es que exista un índice en la tabla SQL por el campo que se esta buscando.

Luego para obtener la página se podría usar la sentencia Select común y corriente con la única condición que la clausula Where incluya una restricción para el campo Nombre entre dos valores.

Usar esta solución para paginar la tabla me va a traer mas de un dolor de cabeza, pero si lo resuelvo creo que va a funcionar muy bien. Ademas estoy pensando que teniendo ese índice del lado del cliente podría estar presentando sus valores al usuario final, y mejorar la experiencia de búsqueda. Estaría mostrando un verdadero índice, como el de un libro y  me desharía del tipo de paginación 1,2,3,4…..etc. en el que nunca se sabe si la pagina 4 corresponde a la letra A o la letra R.

El segundo paso : Inteligencia del lado del cliente.

La Filosofía AJAXciana, si es que existe la palabra, nos dice: “Todo lo que puedas hacer del lado del cliente… !! HAZLO !!”

Vamos a intentar respetarla en todo lo posible generando un ScriptControl con todas la funciones necesaria para lograr la siguientes acciones:

  • Ir al primer registro de la tabla/ página
  • Ir al último registro de la tabla/página
  • Ir a un registro previamente memorizado
  • Avanzar uno o mas registros
  • Retroceder uno o mas registro
  • Buscar un dato en la tabla (según orden establecido)
  • Agregar un registro
  • Eliminar un registro
  • Modificar un registro
  • Actualizar varios registro de un sola vez.
  • Clonar un registro
  • Limpiar la tabla.

Eventos:

  • Registro Encontrado (búsqueda, avanzar, retroceder, primero o ultimo)
  • Registro Modificado
  • Registro Agregado
  • Registro Eliminado
  • Tabla Actualizada
  • Principio de Tabla
  • Fin de Tabla

En todo momento accediendo a la propiedad “Registro” deberíamos poder leer los campos del registro en el cual estamos posicionados.

Los métodos de posicionamiento (ir al próximo, anterior, primero ultimo …etc) deberían seguir los mismos lineamientos:


Notemos que usando este tipo de rutina llevamos al cliente los datos a medida que este los va pidiendo y luego los guardamos en memoria. Si repite la búsqueda traemos los registros directamente de memoria, evitando llamadas innecesarias al servidor.

Luego para consumir los registros, el programador deberá suscribirse al evento “Encontrado” ya que todo este proceso se realiza de manera asincrónica.

Guardaríamos los registros obtenidos de la siguiente manera:

Aquí tendríamos un objeto “Indices” conteniendo un objeto por cada ordenamiento posible. Cada indice contiene una lista de valores que corresponden al primer registro de cada página. A su vez cada pagina contiene el conjunto de registros comprendidos entre el valor de esta página y la siguiente.

Por último realizaría una búsqueda binaria dentro de este árbol binario, lo que debería resolverse de manera mas que eficiente.

Del último deseo del post Proveedor de datos Servidor Cliente donde ruego que estos datos puedan ser consumidos por varios controles al mismo tiempo sin duplicar los datos, sale la idea de poner esta estructura a nivel documento. De esta manera todos los Proveedor de Datos que invoquen el mismo WebMethod compartirían los datos sin necesidad de duplicarlos.

El tercer y ultimo paso : Comunicación entre Servidor y Cliente.

Teniendo definido los pasos anteriores lo último que queda es saber cómo y con qué formato viajaran los datos.

En primer lugar usaría el la función InvocarWebMethod definida en el post Invocando un WebMethod en Javascript de forma asincrónica.

En segundo lugar definiría una estructura de datos lo suficientemente amplia para poder transportar cualquier pedido.

Voy a tirar un primer bosquejo:

Campo Servidor-Cliente Descripción
Indice Ida primeros registros de cada página.
Página Ida registros de una página en particular.
Desde vuelta-ida Valor con el cual comienza la página a buscar
Hasta vuelta-ida Valor con el cual comienza la página siguiente a la que se busca
Método vuelta-ida Método en JavaScrip que desencadenó la llamada, con sus parametros
Clave vuelta Valor que se esta buscando (en caso de no haber paginas en cliente)
Operación vuelta Alta, baja, modificación o consulta, con sus parámetros

Bueno… creo que acabamos de definir como debería funcionar este control, es hora de ponerse a trabajar sobre el código y ver si todo funciona como esperamos.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s