automatización de procesos software para la empresa · automatización de procesos software para...
TRANSCRIPT
Íñigo Astráin Rodríguez
Automatización de procesos software para la empresa
Julio Rubio García
Facultad de Ciencias, Estudios Agroalimentarios e Informática
Proyecto Fin de Carrera
Matemáticas y Computación
2012-2013
Título
Autor/es
Director/es
Facultad
Titulación
Departamento
PROYECTO FIN DE CARRERA
Curso Académico
© El autor© Universidad de La Rioja, Servicio de Publicaciones, 2013
publicaciones.unirioja.esE-mail: [email protected]
Automatización de procesos software para la empresa, proyecto fin de carrerade Íñigo Astráin Rodríguez, dirigido por Julio Rubio García (publicado por la Universidad
de La Rioja), se difunde bajo una LicenciaCreative Commons Reconocimiento-NoComercial-SinObraDerivada 3.0 Unported.
Permisos que vayan más allá de lo cubierto por esta licencia pueden solicitarse a lostitulares del copyright.
2
Resumen
Este documento contiene la memoria de mi proyecto de fin de carrera, en el cual he buscado
la manera de automatizar la generación del código fuente de aplicaciones que desarrollo en
una empresa.
Para lograr este objetivo, he analizado el código fuente de varias aplicaciones identificando
aquellas partes que son comunes, para después crear una serie de herramientas que son
capaces de generar el código fuente, que más tarde formará parte de las aplicaciones. Al
utilizar estas herramientas se consigue un ahorro de tiempo del desarrollo en futuras
aplicaciones, lo que permite reducir el precio final del producto y en consecuencia hacer que la
empresa sea más competitiva.
3
Índice
1. DOP (Documento de Objetivos del Proyecto) ..... 9
1.1 Aproximaciones iniciales..................................................................................... 9 1.1.1 Descripción del proyecto .......................................................................................... 9
1.1.2. Justificación del Proyecto......................................................................................... 9
1.2. Alcance del Proyecto ........................................................................................ 10 1.2.1. Informe del Alcance ............................................................................................... 10
1.2.2 Actividades de apoyo al Alcance del Proyecto ......................................................... 11
1.2.3 Plan de dirección del alcance .................................................................................. 11
1.3. Recursos Humanos y Personal .......................................................................... 11 1.3.1 Conexiones del Proyecto......................................................................................... 11
1.3.2 Organigrama........................................................................................................... 12
1.4. Plan de Comunicaciones ................................................................................... 12 1.4.1 Tecnología para la comunicación ............................................................................ 12
1.5. Dirección de Riesgos ........................................................................................ 13 1.5.1 Fuentes de Riesgo ................................................................................................... 13
1.5.2 Síntomas de Riesgo ................................................................................................. 14
1.5.3 Cuantificación de Riesgos ....................................................................................... 14
1.5.4 Plan de Dirección de Riesgos (Plan de Contingencia) ............................................... 15
1.6. Planificación del Proyecto ................................................................................ 15 1.6.2 Listado de Actividades ............................................................................................ 17
1.6.3 Orden de Actividades.............................................................................................. 24
1.6.4 Calendario de trabajo ............................................................................................. 27
1.6.5 Diagrama de Gantt ................................................................................................. 31
2. Replanificación ...................................... 32
3. Análisis. Identificación de partes repetitivas .... 33
3.1. Ámbito del análisis. .......................................................................................... 33 3.2. Bases de datos .................................................................................................. 34
3.2.1 Tablas ..................................................................................................................... 34
3.2.2 Procedimientos almacenados ................................................................................ 35
3.2.3 Funciones ............................................................................................................... 37
3.2.4 Usuario ................................................................................................................... 37
3.3. Servicio web..................................................................................................... 37 3.3.1 Carpeta Modelo ...................................................................................................... 39
3.3.2 Carpeta DAL (Data Access Layer) ............................................................................. 41
3.3.3 Métodos web (fichero asmx) .................................................................................. 49
4
3.4. Aplicaciones web ............................................................................................. 49 3.4.1 Aplicaciones internas o de gestión .......................................................................... 51
3.4.2 Aplicaciones públicas .............................................................................................. 54
3.5. Conclusiones .................................................................................................... 55
4. Brainstorm ............................................ 56
5. Análisis. Librerías Utilidades y Controles Web Personalizados. ......................................... 58
5.1 Librería Utilidades. ............................................................................................ 58 5.1.1 Clases Útiles según tipos de datos........................................................................... 58
5.1.2 Clases Útiles según funcionalidad ........................................................................... 61
5.2 Librería de Controles Web personalizados. ........................................................ 63 5.2.1 Controles y validaciones más comunes ................................................................... 63
5.2.2 TextBox .................................................................................................................. 64
5.2.3 DropDownList ......................................................................................................... 67
5.2.4 ListBox .................................................................................................................... 68
5.2.5 CheckBoxList .......................................................................................................... 68
5.2.6 RadioButtonList ...................................................................................................... 68
5.2.7 Validación de los controles ..................................................................................... 69
6. Fase I .................................................. 70
6.1 Aplicación ......................................................................................................... 71 6.1.1 Menú ...................................................................................................................... 71
6.2 Opción Proyecto ................................................................................................ 72 6.2.1 Nuevo proyecto ...................................................................................................... 72
6.2.2 Modificar proyecto ................................................................................................. 73
6.2.3 Seleccionar proyecto .............................................................................................. 74
6.3 Opción Crear .................................................................................................... 75 6.3.1 Base de datos ......................................................................................................... 75
7. Fase II ................................................. 84
7.1 Mejoras respecto a la fase primera ..................................................................... 85 7.1.1 Modificación del menú de aplicación . .................................................................... 85
7.1.2 Separación en varios ficheros XML la información relativa a los proyectos. ............. 85
7.1.3 Mejoras en el generador de procedimientos almacenados. .................................... 86
7.1.4 Nuevos campos en el alta y modificación de proyectos ........................................... 87
7.2 Nuevas funcionalidades ..................................................................................... 88 7.2.1 Abrir el último proyecto con el cual se estaba trabajando ....................................... 88
7.2.2 Detección de tablas y campos agregados, modificados y eliminados. ...................... 88
7.2.3 Generador de modelos de datos ............................................................................. 89
5
7.2.4 Creación de clases y métodos para automatizar la lectura de datos provenientes de
los procedimientos almacenados .................................................................................... 96
7.2.5 Generador de métodos de acceso a datos (Data Access Layer) ............................. 100
8. Fase III .............................................. 102
8.1 Mejoras respecto a la segunda fase .................................................................. 103 8.1.1 Modificación de la herramienta de generación de procedimientos almacenados .. 103
8.1.2 Mejora de la herramienta de generación de métodos de acceso. .......................... 103
8.2 Novedades. Librería de validación de controles. .............................................. 108 8.2.1 Clase TextBoxV ..................................................................................................... 110
8.2.2 Clase DropDownListV............................................................................................ 111
8.2.3 Clase CheckBoxListV ............................................................................................. 111
8.2.4 Uso de la librería ................................................................................................... 111
8.2.5 Configuración de los proyectos para poder utilizar la librería. ............................... 112
9. Pruebas ............................................. 114
9.1 Herramienta de generación de procedimientos y código .................................. 114
9.2 Controles de validación ................................................................................... 118
10. Conclusiones ...................................... 122
10.1 Librería Utilidades ......................................................................................... 122
10.2 Generador de procedimientos almacenados ................................................... 122 10.3 Agregar funciones SQL a base de datos ......................................................... 123
10.4 Generadores del modelo de datos y métodos de acceso a datos. ..................... 124 10.5 Librería validación del contenido de controles web. ....................................... 124
10.6 Conclusión final ............................................................................................ 125
6
Índice de Figuras Figura 1: Organigrama............................................................................................................. 12
Figura 2: Planificación del Proyecto ......................................................................................... 16
Figura 3: Orden de paquetes generales ................................................................................... 25
Figura 4: Orden de paquetes secundarios ............................................................................... 26
Figura 5: Calendario proyecto. Septiembre - Octubre .............................................................. 28
Figura 6: Calendario proyecto. Noviembre - Diciembre ........................................................... 29
Figura 7: Calendario proyecto. Enero - Febrero ....................................................................... 30
Figura 8: Diagrama de Gantt ................................................................................................... 31
Figura 9: Ejemplo de tablas maestras ...................................................................................... 35
Figura 10: Ejemplo estructura proyecto................................................................................... 38
Figura 11: Ejemplo tablas para modelo de datos. .................................................................... 39
Figura 12: Ejemplo clases de modelo de datos. ....................................................................... 39
Figura 13: Ejemplo de estructura de carpetas para modelo de datos ....................................... 40
Figura 14: Ejemplo organización proyecto ............................................................................... 51
Figura 15: Ejemplo mantenimiento sencillo. ............................................................................ 52
Figura 16: Ejemplo mantenimiento intermedio. ...................................................................... 53
Figura 17: TextBox .................................................................................................................. 64
Figura 18: DropDownList ......................................................................................................... 67
Figura 19: ListBox .................................................................................................................... 68
Figura 20: CheckBoxList ........................................................................................................... 68
Figura 21: RadioButtonList ...................................................................................................... 68
Figura 22: Diseño inicial aplicación .......................................................................................... 71
Figura 23. Menú proyecto de la aplicación .............................................................................. 71
Figura 24: Menú crear de la aplicación .................................................................................... 71
Figura 25: Formulario para crear un nuevo proyecto ............................................................... 72
Figura 26: Formulario para modificar un proyecto. .................................................................. 73
Figura 27: Formulario para seleccionar un proyecto. ............................................................... 74
Figura 28: Formulario para crear procedimientos almacenados .............................................. 75
Figura 29: Pestaña de configuración de campos ...................................................................... 77
Figura 30: Pestaña de configuración de filtros ......................................................................... 78
Figura 31: Pestaña de configuración del orden de los campos ................................................. 79
Figura 32: Pestaña configuración campo activo y código grabado ........................................... 80
Figura 33: Pestaña vista previa script procedimiento almacenado ........................................... 81
Figura 34: Aviso detectada existencia de procedimiento almacenado ..................................... 82
Figura 35: Aviso procedimiento almacenado creado ............................................................... 82
Figura 36: Formulario para agregar funciones de SQL .............................................................. 83
Figura 37: Nueva configuración del menú de la aplicación ....................................................... 85
Figura 38: Mejoras en la configuración de campo activo ......................................................... 86
Figura 40: Check para utilizar el modelo de datos .................................................................... 86
Figura 39: Vista previa procedimiento almacenado ................................................................. 86
Figura 41: Formulario modificar proyecto ............................................................................... 87
Figura 42: Cambios detectados al abrir proyecto. Tablas ......................................................... 88
7
Figura 43: Cambios detectados al abrir un proyecto. Campos .................................................. 89
Figura 44: Configuración general en la creación del modelo de datos ...................................... 90
Figura 45: Configuración de clases .......................................................................................... 92
Figura 46: Listado de propiedades de una clase ....................................................................... 93
Figura 47: Configuración procedimientos almacenados. Usar modelo de datos ....................... 93
Figura 48: Modificación del nombre de una propiedad que es clave foránea. Paso 1 ............... 94
Figura 49: Modificación del nombre de una propiedad que es clave foránea. Paso 2 ............... 94
Figura 50: Modificación del nombre de una propiedad que es clave foránea. Paso 3 ............... 94
Figura 51: Vista previa generación de clases ............................................................................ 95
Figura 52: Aviso generación de clases...................................................................................... 95
Figura 53. Casilla utilizar modelo de datos en generación de procedimientos almacenados .... 98
Figura 54: Vista previa generación procedimientos utilizando el modelo de datos .................. 99
Figura 55. Configuración del método de acceso a datos ........................................................ 100
Figura 56: Botón DAL en generación de procedimientos almacenados .................................. 103
Figura 57. Nuevas opciones en la configuración general para la generación de clases de acceso
a datos .................................................................................................................................. 104
Figura 58: Nuevas opciones en la pestaña de configuración del método de acceso a datos ... 104
Figura 60: Nuevas opciones en la pestaña de configuración de método de acceso a datos. ... 106
Figura 59: Escoger ruta en la generación de clases de acceso a datos .................................... 106
Figura 61: Vista previa de clase de acceso a datos ................................................................. 108
Figura 62. Ejemplo elemento por defecto en controles DropDownList .................................. 111
Figura 63: Referencia a librería de validación de controles .................................................... 112
Figura 64: Ejemplo de configuración de la librería validación de controles............................. 113
Figura 65: Ejemplo control web disponible en diseño de pantalla .......................................... 113
Figura 66: Modelo de datos para pruebas ............................................................................. 114
Figura 67: Configuración del proyecto para probar la herramienta ........................................ 115
Figura 68: Configuración del nuevo proyecto. ....................................................................... 115
Figura 69: Clases generadas e incluidas en el proyecto. ......................................................... 116
Figura 70: Ejemplo de clase generada. Empleado .................................................................. 116
Figura 71: Clases DAL generadas ........................................................................................... 117
Figura 72: Métodos web para probar las operaciones creadas. ............................................. 117
Figura 73: Resultado de invocación de un método web de pruebas ....................................... 118
Figura 74: Ejemplo de página web para probar los controles de validación. ........................... 118
Figura 75: Primera prueba de validación de controles. .......................................................... 120
Figura 76: Segunda prueba de validación de controles. ......................................................... 121
8
Índice de Tablas Tabla 1: Recuento de tablas por proyecto ............................................................................... 34
Tabla 2: Recuento de campos por tablas por proyecto. ........................................................... 34
Tabla 3: Recuento de tablas maestras por proyecto ................................................................ 35
Tabla 4: Número de procedimientos almacenados por operación y proyecto. ......................... 36
Tabla 5: Comparativa número procedimientos almacenados y tablas ...................................... 37
Tabla 6: Recuento de clases y número de líneas de código por proyecto. ................................ 48
Tabla 7: Recuento de mantenimientos sencillos. ..................................................................... 52
Tabla 8: Recuento de pantallas con mantenimientos intermedios. .......................................... 53
Tabla 9: Tipos de operación y opciones activas en generación de métodos de acceso a datos
............................................................................................................................................. 101
Tabla 10: Relación entre operaciones básicas y opciones activadas en la configuración de los
parámetros de entrada ......................................................................................................... 107
Tabla 11: Número de procedimientos almacenados por operación y proyecto. ..................... 122
Tabla 12: Relación del número de tablas principales ............................................................. 123
Tabla 13: Procedimientos almacenados sin búsquedas.......................................................... 123
Tabla 14: Recuento del número de líneas de código .............................................................. 124
9
1. DOP (Documento de Objetivos del Proyecto) En este capítulo se describe de forma general los objetivos del proyecto.
1.1 Aproximaciones iniciales En este punto se explicarán las definiciones iniciales de este Proyecto. Se detallará qué se
quiere hacer y por qué se va a hacer.
1.1.1 Descripción del proyecto
Los objetivos del proyecto son:
1. Analizar cómo se estructuran los proyectos que se vienen desarrollando en una
empresa concreta.
2. Búsqueda de una posible mejora en la organización de los mismos.
3. Construcción de una serie de herramientas que faciliten el desarrollo de los proyectos,
así como una mejora (reducción) en los tiempos de desarrollo de los proyectos.
1.1.2. Justificación del Proyecto
Cuando se trabaja en proyectos de desarrollo, uno se va dando cuenta de que muchas de las
operaciones que se realizan en esencia son repetitivas, pese a ser proyectos diferentes. Hay
muchas operaciones que son comunes. Si los proyectos los organizáramos de una determinada
manera, seríamos capaces de generar código de una manera semiautomática mediante el uso
de herramientas creadas a tal efecto.
Por tanto este proyecto va a tratar de buscar la manera más eficiente de organizar los
proyectos y una vez conseguido esto, diseñar y crear herramientas que permitan una
generación semiautomática de código, con el fin de ahorrar tiempo de desarrollo y en
consecuencia ahorrar costes.
VENTAJAS PARA LA EMPRESA
- Reducción de costes. Con menos horas se realiza el mismo trabajo.
- Aumento de la productividad y competitividad
VENTAJAS PARA EL USUARIO (DESARROLLADOR)
- Las tareas repetitivas se reducen.
- Al estar los proyectos organizados de la misma manera, se reduce el tiempo en la localización
de posibles errores, así como el tiempo de solución de los mismos.
10
1.2. Alcance del Proyecto El alcance del proyecto define y detalla lo que se realizará en un proyecto.
1.2.1. Informe del Alcance
En este proyecto se llevarán a cabo las siguientes tareas.
1. Recopilación de proyectos ya finalizados.
2. Análisis de los proyectos para identificar qué partes son repetitivas y por tanto
susceptibles de ser generadas de manera semiautomática. Identificar operaciones
comunes en los proyectos.
3. Estudiar qué herramientas serían más productivas para la generación de código.
4. Diseñar las herramientas, identificando sus principales objetivos.
5. Decidir qué herramientas se llevan a cabo, puesto que probablemente no haya tiempo
para poder desarrollar todas ellas, o su desarrollo sea muy complicado.
6. Probar las herramientas desarrolladas en proyectos ya terminados y comparar los
tiempos y resultados, entre el desarrollo sin uso de herramientas y el desarrollo con
uso de herramientas.
7. De las pruebas anteriores, comprobar si realmente merece la pena invertir tiempo en
el desarrollo de estas herramientas.
8. Buscar puntos de mejora con los resultados obtenidos en los puntos 6 y 7. Volver al
punto 5 si es necesario para crear nuevas herramientas o mejorar las ya existentes.
9. Informe final, con las conclusiones obtenidas respecto al tiempo de desarrollo de las
herramientas y el tiempo ganado al hacer uso de ellas.
Una vez que el proyecto esté acabado se tendrá hecho los siguientes entregables:
Herramientas para la generación de código (librerías y ejecutables)
Documentos con las conclusiones que analizan los resultados del uso de estas
herramientas, ventajas e inconvenientes.
Los objetivos del proyecto son:
Acabar todos los entregables antes de la entrega de la memoria.
Acabar y entregar la memoria antes de la defensa.
Realizar la defensa del proyecto en Febrero - Marzo de 2013
11
1.2.2 Actividades de apoyo al Alcance del Proyecto
Buscar herramientas ya existentes que generen código.
Estudiar las funcionalidades de las herramientas encontradas.
Se irá dando parte del estado del proyecto periódicamente a Julio Rubio.
Se realizarán reuniones periódicas para valorar el estado del proyecto y/o para tomar
decisiones sobre el proyecto.
1.2.3 Plan de dirección del alcance
Al ser esto un Proyecto de Fin de Carrera, el alcance del proyecto puede cambiar por varios
motivos:
Yo realizo un cambio en el alcance del proyecto o Por propia iniciativa. o Para mejorar en algún aspecto el proyecto. o Por algún motivo de “fuerza mayor”, como acortar alguna tarea por falta de
tiempo.
El director del proyecto recomienda un cambio en el alcance del proyecto
Una vez asumido el cambio, yo seré el encargado de realizarlo. Se modificará todo aquello que
sea necesario, aquellas partes que se vean afectadas.
1.3. Recursos Humanos y Personal En este apartado, se explicará la gestión de los recursos humanos de este proyecto. Cada
persona implicada tiene un papel que jugar en este proyecto, unas obligaciones que cumplir y
unas decisiones que tomar.
1.3.1 Conexiones del Proyecto
Estas son las personas que formarán parte del proyecto:
Julio Rubio: Director del Proyecto o Decisiones a tomar: Cualquiera que considere oportuno. o Dedicación: Esporádica.
Iñigo Astráin: Estudiante que realizará el proyecto o Decisiones a tomar: La gran mayoría. o Dedicación:
Los días de trabajo: parcial. Fin de semana y vacaciones: completa.
Otros profesores: Grupo de profesores a los cuales preguntaré alguna duda puntual. o Decisiones a tomar: Únicamente aportarán su solución a la duda. o Dedicación: El tiempo que consideren oportuno para resolver la cuestión.
Miembros del tribunal: Grupo de profesores que evaluarán el proyecto. o Decisiones a tomar: La nota final del proyecto. o Dedicación: Únicamente los días necesarios para leer la memoria y el día de la
defensa.
12
1.3.2 Organigrama
Este sería el organigrama de personal en mi proyecto, asumiendo yo
cualquier decisión, siendo las aportaciones de Julio y profesores
consideradas siempre como buenas y aceptadas como tal.
Figura 1: Organigrama
1.4. Plan de Comunicaciones
El plan de comunicaciones de un proyecto detalla para las entidades involucradas en el
proyecto, quién necesita qué tipo de información, cuándo la va a necesitar y cómo le será
enviada.
1.4.1 Tecnología para la comunicación
Estas son las herramientas que se utilizarán en la comunicación dentro del proyecto:
Correo – electrónico: A través del correo de la universidad, se enviarán partes del proyecto para su posterior evaluación y/o optimización en el casa necesario u oportuno.
Reuniones: Las reuniones jugarán un papel muy importante dentro del proyecto. Será en las reuniones donde se tratarán aspectos importantes dentro del proyecto y donde se tomarán decisiones.
Consultas: Se utilizarán para resolver dudas puntuales.
Defensa: Se utilizará una presentación de duración máxima de 30 minutos para comunicar al Tribunal lo más relevante dentro del proyecto, en la cual se utilizarán medios como transparencias, demostraciones online y demás herramientas multimedia.
Almacenamiento en la nube (Dropbox). Con el fin de evitar la pérdida parcial o total del trabajo por fallo de los sistemas hardware de almacenamiento de datos, todo el proyecto se almacenará en una cuenta de Dropbox. Este sistema de almacenamiento cuenta con copias de seguridad periódicas.
JULIO
YO
Tribunal Profesores
13
1.5. Dirección de Riesgos La dirección de Riesgos es una parte muy importante dentro de todo proyecto. Con un buen
Plan de Dirección de Riesgos podemos tener todas las fuentes de riesgo identificadas y si algo
falla actuaremos según lo planificado en el Plan de Dirección de Riesgos. En este apartado se
identificarán las fuentes principales de riesgo y se creará un plan a seguir.
1.5.1 Fuentes de Riesgo
La poca experiencia en el análisis de proyectos es una fuente de riesgo muy importante, sobre
todo a la hora de planificar. En cuanto al desarrollo de aplicaciones, el riego es medio puesto
que pese a contar con algo más de cuatro años de experiencia en el desarrollo de soluciones
informáticas, mi área de trabajo son las páginas web y no el desarrollo de aplicaciones para
escritorio (Windows)
Riesgos:
1. Un mal diseño inicial, llevará a cometer errores en todos los aspectos del proyecto con cierta seguridad.
2. Una mala estimación de las fechas debido a la inexperiencia y debido también, a que tengo que compaginar trabajo y desarrollo del proyecto.
3. Querer hacer demasiadas herramientas o herramientas para todo tipo de tareas, el desarrollo de las mismas probablemente suponga la mitad de horas del proyecto.
4. Puede haber problemas software ocasionados por una mala instalación de alguna de las herramientas, por deterioro o por mal uso de las mismas.
5. Así mismo, puede haber algún problema hardware con los equipos que se usarán durante el desarrollo del proyecto.
6. El hecho de trabajar es ya por si un riego para el proyecto, puesto que cuando lleguen fechas criticas en la entrega de trabajos, las horas de dedicación a este proyecto se verán mermadas.
7. Al ser un proyecto propuesto por el alumno, existe la posibilidad de que la ambición pueda con el alumno, ocasionando que el diseño inicial sobrepase con creces a un proyecto de fin de carrera.
14
1.5.2 Síntomas de Riesgo
Al detectar alguno de estos síntomas se activará el Plan de Contingencia que se describe en el
punto 1.5.4.
Síntomas
1. Errores o incoherencias en el desarrollo del proyecto nos indicarán que algo está fallando.
2. Conforme el proyecto vaya avanzando, puede haber un continuo retraso de los entregables según las fechas iniciales.
3. El tiempo dedicado al desarrollo de herramientas supera el 40% de las horas del proyecto completo.
4. Mal funcionamiento de las herramientas para la generación de código u otros
productos.
5. Fallos por golpes, catástrofes o fallos desconocidos en el equipo informático.
6. Síntomas de enfermedad, aparte de los propios síntomas médicos, pueden ser el descenso de la productividad y el uso continuo de trabajo excesivo al no llegar a tiempo a las fechas planificadas.
7. Si en continuas revisiones del proyecto (en su diseño inicial) el trabajo aumenta considerablemente. Continúas revisiones que tampoco suponen un cambio importante en el diseño o que se sale del ámbito del proyecto.
1.5.3 Cuantificación de Riesgos
Cada fuente de riesgo tiene diferente evaluación, desde una fuente de riesgo potencial cuyo
daño se considera elevado, hasta una fuente de riesgo cuyo daño se considera mínimo.
1. Mal diseño inicial: Alto
2. Mala estimación de fechas: Alto
3. Tiempo excesivo en desarrollo de herramientas. Medio
4. Problemas de software: Bajo
5. Problemas de hardware: Bajo
6. Enfermedad: Bajo
7. Diseño excesivo: Medio
15
1.5.4 Plan de Dirección de Riesgos (Plan de Contingencia)
Para cada fuente de riesgo se actuará según lo descrito en este punto.
1. Reunión con el Director del Proyecto, para ver en que se ha fallado e intentar reorientar el Proyecto.
2. Cambios en la estimación de las fechas y muy probablemente un aumento de horas de dedicación al Proyecto.
3. Reducción de las funcionalidades de las herramientas. Priorización de las mismas.
4. Se procederá a reinstalar la herramienta, perdiendo un día de trabajo en la
reinstalación, y comprobación del buen funcionamiento.
5. Mientras se repara el ordenador, se analizará el estado del proyecto. Se trabajará desde otros dispositivos (ordenador portátil)
6. Se reducirá el número de horas invertidas en el proyecto, tratando de realizar otras tareas que exijan menos esfuerzo, para no perder demasiado tiempo.
7. Se procederá a revisar el diseño tratando de eliminar aquellas partes del diseño que sean innecesarias o que no tengan mucho que ver con el Proyecto que se está desarrollando. Es posible que se produzca alguna reunión con el Director del Proyecto para que dé su opinión.
1.6. Planificación del Proyecto A continuación se mostrará la primera planificación realizada para la ejecución de este
Proyecto. Se mostrará la primera Estructura de Descomposición del Proyecto realizada, así
como el Calendario de Trabajo Planificado por el alumno de todas las actividades resultantes
16
PT0
GESTOR
PROYECTOS
PT02
Análisis
PT03
Diseño
PT01
Recopilación
proyectos
PT05
Pruebas
PT07
Dirección del
Proyecto
PT070
Gestión del
Plan
PT071
Reuniones
PT072
Creación de
La Memoria
PT073
Documentación
PT074
Defensa
PT020
Identificar partes
repetitivas
PT06
Informes
PT030
Librerías
comunes
PT031
Herramientas
principales
PT050
Librerías
comunes
PT060
Tiempos sin
herramientas
PT061
Tiempos con
herramientas
PT021
BrainStorm
PT022
Bocetos de
herramientas
PT032
Herramientas
complementarias
PT04
Desarrollo
PT040
Librerías
comunes
PT041
Herramientas
principales
PT042
Herramientas
complementarias
PT051
Herramientas
principales
PT052
Herramientas
secundarias
PT062
Comparativa de
tiempos
PT063
Ahorro de
costes
Figura 2: Planificación del Proyecto
17
1.6.2 Listado de Actividades
Cada Paquete de Trabajo del EDP está compuesto por una o más actividades. En este apartado
describiremos cada Paquete de Trabajo y lo descompondremos en las actividades en que se
compone.
PT01 Recopilación de proyectos
Descripción
En este paquete de trabajo se llevará a cabo la recopilación de
proyectos finalizados, para su posterior estudio en etapas posteriores.
Actividades
A010 Recopilación de código de proyectos finalizados.
PT020 Análisis. Identificar partes repetitivas
Descripción
Análisis de las partes que se asemejan en los proyectos recopilados
anteriormente. Buscar las partes susceptibles a ser generadas
mediante herramientas.
Actividades
A0200 Identificación de secciones comunes.
A0201 Identificación de funciones comunes.
PT021 Análisis. BrainStorm
Descripción
Primera tormenta de ideas, enumerando las posibles herramientas
que se podrían generar así como sus funciones.
Actividades
A0210 Tormenta de ideas.
18
PT022 Análisis. Bocetos de herramientas
Descripción
Preparar los primeros bocetos con el diseño de las herramientas y sus
funcionalidades.
Actividades
A0220 Primeros bocetos.
PT030 Diseño. Librerías comunes
Descripción
Diseñar la estructura interna de las librerías. Librerías que tengan
operaciones comunes así como otras para otras funciones (acceso a
datos, etc.)
Actividades
A0300 Recopilación funciones comunes.
A0301 Diseño librería comunes.
A0302 Diseño librería acceso a datos.
A0303 Diseño otras librerías.
PT031 Diseño. Herramientas principales
Descripción
Diseñar la o las herramientas principales que abarcarán gran parte del
desarrollo del proyecto. Estas herramientas serán capaces de generar
grandes cantidades de líneas de código de manera semiautomática,
con la interacción de personas, mediante el uso de interfaces
gráficas.
Actividades
A0310 Especificar las tareas a realizar por estas herramientas.
A0311 Crear una o varias herramientas.
19
PT032 Diseño. Herramientas complementarias
Descripción
Diseñar la o las herramientas complementarias a las herramientas
principales diseñadas en el punto anterior.
Actividades
A0320 Identificar las tareas complementarias a realizar.
A0321 Crear una o varias herramientas.
PT040 Desarrollo. Librerías comunes
Descripción
Desarrollar las librerías diseñadas en el punto PT30.
Actividades
A0400 Desarrollo de las librerías.
PT041 Desarrollo. Herramientas principales
Descripción
Desarrollar las herramientas principales diseñadas en el punto PT31
Actividades
A0410 Desarrollo de las herramientas principales.
PT042 Desarrollo. Herramientas complementarias
Descripción
Desarrollar las herramientas complementarias diseñadas en el punto
PT32.
Actividades
A0420 Desarrollo de las herramientas complementarias.
20
PT050 Pruebas. Librerías comunes
Descripción
Realizar pruebas exhaustivas para comprobar y/o detectar
deficiencias o errores en las librerías. En caso de haber errores
subsanarlos.
Actividades
A0500 Crear proyecto para probar la librería.
A0501 Realizar pruebas.
A0502 Detectar errores o deficiencias.
A0503 Detectar puntos de mejora.
A0504 Corregir errores y agregar mejoras.
PT051 Pruebas. Herramientas principales
Descripción
Realizar pruebas exhaustivas para comprobar y/o detectar
deficiencias o errores en las herramientas desarrolladas.
Actividades
A0510 Probar las herramientas.
A0501 Detectar errores o deficiencias.
A0502 Detectar puntos de mejora.
A0503 Corregir errores y agregar mejoras.
21
PT052 Pruebas. Herramientas complementarias
Descripción
Realizar pruebas exhaustivas para comprobar y/o detectar
deficiencias o errores en las herramientas desarrolladas.
Actividades
A0520 Probar las herramientas.
A0521 Detectar errores o deficiencias.
A0522 Detectar puntos de mejora.
A0523 Corregir errores y agregar mejoras.
PT060 Informes. Tiempos sin herramientas
Descripción
Se trata de contabilizar el tiempo que se tarda en desarrollar código
sin el uso de herramientas.
Actividades
A0600 Crear proyecto pequeño para la simulación.
A0601 Programar el proyecto.
A0602 Contar el tiempo invertido.
PT061 Informes. Tiempos con herramientas
Descripción
Se trata de contabilizar el tiempo que se tarda en desarrollar código
con el uso de herramientas.
Actividades
A0610 Usar las herramientas para generar código.
A0611 Realizar modificaciones necesarias para que el proyecto funcione adecuadamente.
A0612 Contabilizar el tiempo invertido en el uso de herramientas y en las modificaciones.
22
PT062 Informes. Comparativa de tiempos
Descripción
Con los resultados obtenidos en los puntos PT060 y PT061 realizar una
comparación.
Actividades
A0620 Contabilizar líneas de código escritas en el punto PT060 y el tiempo invertido.
A0621 Contabilizar líneas de código escritas en el punto PT061 y el tiempo invertido.
PT063 Informes. Ahorro de costes
Descripción
Con la comparativa de tiempos, analizar los resultados y comprobar el
ahorro que supone o no el uso de estas herramientas, así como el
tiempo empleado en su análisis, definición y desarrollo.
Actividades
A0630 Analizar resultados de comparativas.
A0631 Informe final con las conclusiones.
PT070 Gestión del plan
Descripción
Este paquete de trabajo se encargará de toda la elaboración del Plan
de Proyecto.
Actividades
A0700 Documentación y recopilación de datos referentes a la realización del Plan de Proyecto.
A0701 Contabilizar líneas de código escritas en el punto PT061 y la Creación del Plan del Proyecto.
23
PT071 Reuniones
Descripción
Con este paquete de trabajo se realizará toda actividad referente a
las reuniones e intercambio de correos electrónicos.
Actividades
A0710 Preparación previa de los datos necesarios para cada reunión.
A0711 Realización del acta de la reunión.
A0712 Reuniones.
A0713 Guardar todos los datos y resultados obtenidos de la reunión.
PT072 Creación de la Memoria
Descripción
Este paquete de trabajo se refiere a toda actividad que se llevará a
cabo para tener preparada la memoria a la hora de presentarla al
tribunal.
Actividades
A0720 Recopilar la información necesaria.
A0721 Realización de la Memoria.
PT073 Documentación
Descripción
Toda clase de documentación que sea necesaria para realizar el
proyecto se encontrará en este paquete. Las actividades serán
continuas a lo largo del todo el proyecto. Cuando sea necesario
realizar un aprendizaje o una investigación, las actividades que
componen este paquete realizarán esta labor.
Actividades
A0730 Búsqueda de información o/y adquisición de libros.
A0731 Lectura y aprendizaje.
24
PT074 Defensa
Descripción
Este paquete de trabajo está compuesto de actividades que una vez
acabadas obtendremos como resultado todo el material necesario
para la realización de la defensa, así como un guión de la misma.
Actividades
A0740
Preparar datos relevantes a mostrar en la defensa, así como una
demostración del funcionamiento de la aplicación.
A0741 Defensa del Proyecto ante el Tribunal Evaluador.
1.6.3 Orden de Actividades
Tanto los paquetes de trabajo como las actividades de las que están compuestos tienen unos
requisitos temporales. A continuación se mostrarán el orden temporal de ejecución, tanto de
los paquetes de trabajo como de las actividades.
25
Orden de paquetes generales
ANÁLISIS
DISEÑOS DESARROLLO
DIRECCIÓN
RECOPILACIÓN de
PROYECTOS
PRUEBAS
INFORMES
Figura 3: Orden de paquetes generales
Orden de paquetes secundarios
Figura 4: Orden de paquetes secundarios
27
1.6.4 Calendario de trabajo
La dedicación del proyecto está condicionada a la jornada laboral que realizo actualmente.
Significa que de lunes a jueves, las horas dedicadas serán entorno a dos o tres horas, ya que
termino de trabajar sobre las 18:30 horas. Los viernes la dedicación aumentará a unas cinco
horas máximo puesto que termino de trabajar a las 14:30 horas. Los fines de semana, días
festivos y vacaciones la dedicación será máxima.
Leyenda
Color Significado.
De lunes a jueves, la dedicación máxima será de 3 horas.
Viernes o día anterior a festivo. La dedicación máxima será de 5 horas.
Día festivo o de vacación. La dedicación máxima será de 8 horas.
28
Figura 5: Calendario proyecto. Septiembre - Octubre
29
Figura 6: Calendario proyecto. Noviembre - Diciembre
30
Figura 7: Calendario proyecto. Enero - Febrero
31
1.6.5 Diagrama de Gantt
Figura 8: Diagrama de Gantt
32
2. Replanificación Durante el desarrollo del proyecto, éste ha sufrido cambios respecto a su estructura y tiempos.
Las primeras fases del proyecto PT01 Recopilación y PT02 Análisis, se han respetado. Pero de
aquí en adelante se ha realizado un desarrollo incremental en tres fases.
En cada fase se han realizado tareas de análisis, diseño, implementación y pruebas. Se ha
pasado a este sistema de fases ya que lo que se ha hecho es ir aumentando funcionalidades a
las herramientas que se han ido desarrollando.
Respecto al incumplimiento de los tiempos estimados varias son las causas:
- Poca experiencia en planificación de proyectos.
- Dificultades en el desarrollo de herramientas de escritorio. Estoy especializado en
aplicaciones web.
- Picos de trabajo en la empresa en la que trabajo, reducen de forma considerable las
horas de dedicación al proyecto.
33
3. Análisis. Identificación de partes repetitivas
En este capítulo se muestra el análisis llevado a cabo para la identificación de las partes
comunes existentes en el desarrollo de aplicaciones.
3.1. Ámbito del análisis. Para poder identificar las partes comunes de los proyectos, he tomado como base, tres
proyectos en los cuales he participado. Estos proyectos tiene en común:
1. Son aplicaciones web.
2. Desarrollados en lenguaje C# con Visual Studio 2008.
3. El servidor de la base de datos que usa es SQL SERVER 2005.
4. El acceso a los datos desde las aplicaciones se realiza mediante el uso de Servicios
Web.
5. Todos los accesos que realiza el Servicio Web contra la base de datos se realizan
utilizando procedimientos almacenados.
Los proyectos escogidos, por orden de antigüedad, son:
- Tramitación de permisos de Pesca (desarrollado en el año 2010): Es un sistema para la
gestión y tele tramitación de los permisos de pesca. Consta de dos aplicaciones web, parte
privada que se encarga de gestionar datos como los ríos, cuencas, etc. (gestión) y una parte
pública desde la cual se pueden solicitar los permisos de pesca y de un servicio web.
- Gestión de proyectos de Investigación (desarrollado en el año 2011): Sistema de gestión
integral de los proyectos de investigación del departamento de Salud. Consta de tres
aplicaciones web, una se encarga de la gestión de datos (datos maestros), otra se encarga de
realizar solicitudes de proyectos y una tercera que se encarga de valorar las solicitudes de los
proyectos. Consta además de un servicio web.
- Web del Instituto de Estadística (desarrollado en el año 2012): Consta de dos aplicaciones
web. Una aplicación interna o de gestión que se encarga de mantener la información que se
mostrará en la segunda aplicación web de cara al público. Consta al igual que los proyectos
anteriores de un servicio web.
Por temas de confidencialidad con los clientes de estos proyectos, el código fuente de los
proyectos no puede hacerse público y por tanto en este documento no aparecerá ninguna
línea de código de estos proyectos. Sí que se mostrará cómo están los proyectos organizados y
llegado el momento se pondrán ejemplos simulados.
Una vez presentados los proyectos sobre los cuales se ha realizado el análisis, es hora de
analizar cada una de las principales secciones de estos proyectos. Estas son:
- Base de datos (Tablas, procedimientos almacenados, funciones, seguridad, etc.)
- Servicios Web (Acceso a datos, definición de clases, métodos web, etc.)
- Aplicaciones Web (Páginas web, Acceso a datos vía servicios web, etc.)
34
3.2. Bases de datos Todos las proyectos usan una única Base de Datos (SQL SERVER 2005). En las bases de datos
encontramos los siguientes elementos:
- Tablas
- Procedimientos almacenados.
- Funciones.
- Usuario (Seguridad)
3.2.1 Tablas
El recuento de tablas por proyectos es el siguiente:
Proyecto Pesca Investigación Estadística
Nº tablas 25 46 17 Tabla 1: Recuento de tablas por proyecto
El número de tablas suele ser un indicador de la complejidad del proyecto que se va a
desarrollar. A mayor número de tablas, mayor será el número de procedimientos almacenados
que haya que crear y por consiguiente más líneas de código habrá que escribir para poder
hacer uso de estos procedimientos almacenados.
No obstante el número de tablas no es un factor determinante, ya que aunque seguro que un
mayor número de tablas supone un aumento de las líneas de código que ha de desarrollarse,
la dificultad para escribir estas líneas de código no suele ser elevada. La verdadera complejidad
suele encontrarse realmente en la lógica de negocio.
Otro factor a tener en cuenta relativo a las tablas es el número de campos de las mismas. A
continuación se muestra el recuento de campos de las tablas por proyecto.
Proyecto Pesca Investigación Estadística
Nº campos 163 373 101
Media 6.52 9.09 7.76
Nº campos en tabla con más campos
34 41 13
Nº campos en tabla con menos campos
2 2 2
Tabla 2: Recuento de campos por tablas por proyecto.
El número medio de campos por tabla es bastante similar en los tres proyectos, ninguno de los
tres llega a diez campos por tabla. Las tablas que contienen el mínimo de campos
corresponden a tablas del tipo código / descripción (tablas maestras) o a tablas que relacionan
una tabla con otra (tablas M:N).
Las tablas maestras tienen en las aplicaciones web de gestión pantallas para agregar, actualizar
o borrar datos de las mismas. Estas pantallas de mantenimiento son bastante sencillas. A
continuación se muestra el número de tablas maestras por proyecto.
35
Proyecto Pesca Investigación Estadística
Nº tablas 6 12 4
% sobre total 24 % 26% 23% Tabla 3: Recuento de tablas maestras por proyecto
El porcentaje de tablas maestras es similar, en torno a la cuarta parte del total. No todas
tienen sólo dos campos, sino que pueden tener algunos más, pero su número no suele ser muy
grande. Además estas tablas se caracterizan por tener pocas claves foráneas con otras tablas y
si las hay son con otras tablas maestras.
Por ejemplo, las tablas país y provincia son tablas maestras. La tabla provincia tiene una clave
foránea con la tabla país, que nos permite indicar a que país corresponde la provincia.
Pais
PK Codigo int
Descripcion varchar(200)
Provincia
PK Codigo int
Descripcion varchar(200)
FK1 Pais int
Figura 9: Ejemplo de tablas maestras
Las tablas cuyo número de campos se corresponden con el máximo de campos por tabla, son
las tablas sobre las cuales se basa toda la aplicación. Si dibujáramos la estructura de las tablas
en forma de árbol, siendo las claves externas los enlaces entre los distintos nodos del árbol,
estas tablas estarían en la cabeza del mismo. Además el nombre de las tablas suele
corresponder con la finalidad del proyecto.
3.2.2 Procedimientos almacenados
Definición: Un procedimiento almacenado (stored procedure en inglés) es un programa el cual
es almacenado físicamente en una base de datos. La ventaja de un procedimiento almacenado
es que al ser ejecutado, en respuesta a una petición de usuario, lo hace directamente en el
motor de bases de datos, el cual usualmente se ejecuta en un servidor separado. Además el
uso de procedimientos almacenados previene a la aplicación de sufrir inyección de código por
SQL.
Todas las operaciones que se realizan con los datos de las tablas, se llevan a cabo mediante el
uso de procedimientos almacenados. El procedimiento almacenado aporta eficiencia y
seguridad a las aplicaciones.
El uso de consultas dinámicas, en vez de usar procedimientos almacenados, se puede llegar a
dar, por razones de funcionalidad, pero es altamente desaconsejable.
36
En los tres proyectos analizados todas las operaciones de acceso a datos se han realizado
mediante el uso de procedimientos almacenados. En la programación de los procedimientos
almacenados se siguen unas reglas básicas:
Un procedimiento almacenado sólo realiza una única operación. Esto es que
dentro de un procedimiento almacenado sólo encontraremos una de las siguientes
operaciones:
SELECT: Consulta de datos
INSERT: Agregar datos.
UPDATE: Actualizar datos.
DELETE: Borrar datos.
El nombre del procedimiento almacenado se compone en primera instancia por el
nombre de la tabla seguido por las tres primeras letras de la operación que se lleva
a cabo dentro del mismo (SEL, INS, UPD y DEL). En las operaciones de selección de
datos se indica además la forma en la que se buscan los datos, por ejemplo:
Búsquedas: TABLA_SEL_Busqueda
Por código: TABLA_SEL_Por_Codigo
Todos los elementos: TABLA_SEL_Todos.
Como se muestra en los ejemplos, como elemento de separación se usa el
carácter '_'
A continuación se muestra una tabla con el número de procedimientos almacenados creados
para cada proyecto, clasificados según la operación que realizan.
Proyecto Pesca Investigación Estadística
Número Porcentaje Número Porcentaje Número Porcentaje
SELECT 104 70.27 180 66.42 38 67.85
INSERT 19 12.83 38 14.02 6 10.71
UPDATE 13 8.78 32 11.80 6 10.71
DELETE 12 8.10 21 7.75 6 10.71
TOTAL 148 100 271 100 56 100 Tabla 4: Número de procedimientos almacenados por operación y proyecto.
Si analizamos los datos obtenidos, observamos que dos terceras partes de los procedimientos
almacenados son sólo de consulta. Y la otra tercera parte se reparte en operaciones de
inserción, actualización y borrado de datos.
37
En la siguiente tabla se compara el número de procedimientos almacenados respecto al
número de tablas existentes.
Proyecto Pesca Investigación Estadística
Nº procedimientos 148 271 56
Nº de tablas 25 46 17
Proporción 5.92 5.89 3.29 Tabla 5: Comparativa número procedimientos almacenados y tablas
En los primeros proyectos, la proporción es prácticamente idéntica, pero en el tercer proyecto
la proporción es casi la mitad, por lo que este dato no aporta gran información.
3.2.3 Funciones
En SQL se pueden definir funciones. Estas funciones suelen ser comunes entre los proyectos.
Algunas de las funciones más utilizadas son:
- Split: Dada una cadena de entrada y un carácter de separador, se encarga de separar cada
uno de los valores que están unidos por el separador. Esta función es útil para simular el paso
de datos como si fuera un array de valores. Los arrays no son un tipo de datos admitido en SQL
SERVER 2005.
- Quitar acentos: Cuando se realizan búsquedas y es necesario comparar cadenas, se usa esta
función para que sustituya todos las vocales acentuadas por sus correspondientes no
acentuadas.
El uso de estas funciones, depende de las necesidades de cada proyecto.
3.2.4 Usuario
Para poder ejecutar un procedimiento almacenado, es necesario tener permisos de ejecución
sobre éste. Para ello se crea un usuario que es capaz de autenticarse contra la base de datos y
ejecutar los procedimientos almacenados.
3.3. Servicio web En los proyectos analizados, todos los accesos a datos se realizan mediante el uso de servicios
web. El hecho de separar las aplicaciones web del acceso a datos mediante servicios web es
una práctica muy extendida y se realiza así en casi todos los proyectos.
Básicamente estos servicios web contienen la lógica de acceso a datos:
- Definición de las entidades.
- Accesos a la base de datos, mediante el uso de procedimientos almacenados.
- Conjunto de clases que ayudan a encapsular estas conexiones.
- Fichero asmx, que contiene el listado de métodos web.
Estructura de carpetas: A continuación se muestra cómo se estructura un servicio web.
En la imagen se muestra, la estructura del servicio web del proyecto de Pesca. Esta estructura
es común a todos los proyectos.
38
La carpeta DAO: Contiene cuatro clases que encapsulan el acceso a datos. Básicamente lo que
hacen es definir clases que al hacer uso de ellas, crean los objetos necesarios para acceder a la
base de datos y ejecutar los procedimientos almacenados. Entre los objetos encapsulados
están: SQLConnection, SQLCommand, SQLTransaction, etc.
La carpeta files: Contiene un fichero XML en el cual se definen los valores de varios parámetros
que usa la aplicación. Por ejemplo, el proyecto tiene una tabla que define los tipos de días,
laborables, festivos, días de campeonato, etc. Estos tipos de días tienen asignados un código,
1, 2, 3, ... en su tabla correspondiente. En el fichero XML están definidos una serie de entradas,
una por cada tipo de día, junto con su correspondiente
valor. Esto facilita la transformación de los códigos 1, 2, 3...
a una propiedad de tipo enumerada (enum), de forma que
en la aplicación sea más fácil trabajar con estos datos.
La carpeta ModeloDatos: Esta carpeta contiene a su vez dos
carpetas más DAL y Modelo.
Figura 10: Ejemplo estructura proyecto
39
3.3.1 Carpeta Modelo
Contiene un listado de clases.
- Cada clase representa a una tabla de la base de datos, pero no todas las tablas están
representadas en forma de clases. Por ejemplo las tablas M:N no tienen
representación. Se pueden crear clases que engloben a varios campos y que se
encuentran en varias tablas.
- Cada clase contiene un listado de propiedades que representan a los campos de las
tablas.
- Las clases se definen como clases parciales.
Veamos un ejemplo, tenemos las siguientes tablas:
Figura 11: Ejemplo tablas para modelo de datos.
De la siguiente representación de tablas se pueden sacar las siguientes clases:
+Dirección : string
+Teléfono : string
Domicilio
+Codigo : int
+Nombre : string
+Domicilio : Domicilio
Departamento
+Código : int
+Nombre : string
+Apellido1 : string
+Apellido2 : string
+Domicilio : Domicilio
+Departamento : Departamento
+Jefe : Persona
Persona
Figura 12: Ejemplo clases de modelo de datos.
El resultado obtenido son tres clases, la clase Persona representa a la tabla Persona y la clase
Departamento a la tabla Departamento. Se ha creado una tercera clase llamada Domicilio que
engloba a los campos Dirección y Teléfono y que se ha agregado como propiedad de las clases
Persona y Departamento.
El código de estas clases queda de la siguiente manera:
public partial class Domicilio
{
public string Direccion { get; set; }
public string Telefono { get; set; }
}
40
public partial class Departamento
{
public int Codigo { get; set; }
public string Nombre { get; set; }
public Domicilio Domicilio { get; set; }
}
public partial class Persona
{
public int Codigo { get; set; }
public string Nombre { get; set; }
public string Apellido1 { get; set; }
public string Apellido2 { get; set; }
public Domicilio Domicilio { get; set; }
public Departamento Departamento { get; set; }
public Persona Jefe { get; set; }
}
Y la estructura de carpetas es la siguiente:
Figura 13: Ejemplo de estructura de carpetas para modelo de datos
41
3.3.2 Carpeta DAL (Data Access Layer)
La carpeta DAL contiene un listado de clases, las cuales contienen el código necesario para
acceder a la base de datos mediante el uso de las clases definidas en la carpeta DAO y el uso
de los procedimientos almacenados alojados en la base de datos.
Los nombres de los ficheros que contienen estas clases, se forman utilizando el nombre de la
clase más la palabra DAL.
Las clases se definen como parciales y su nombre es el mismo que el que se le da en la carpeta
Modelo. De esta manera separamos en dos ficheros el contenido de la clase, por un lado la
definición con todas sus propiedades y en el otro tenemos todos los métodos, pero
conceptualmente ambos ficheros forman una única clase.
No todas las clases definidas en la carpeta Modelo tienen su correspondiente clase en la
carpeta DAL, por ejemplo, en el ejemplo propuesto no existiría el fichero DomicilioDAL.cs,
puesto que esta clase sólo encapsula dos propiedades.
Para poder entender mejor el funcionamiento de estas clases DAL, se muestra a continuación
cuatro ejemplos de código, uno por cada operación que se realiza en los procedimientos
almacenados:
- Select
- Insert
- Update
- Delete
Ejemplo de Select (Página 42): Obtener todas las personas
Ejemplo de Insert (Páginas 43 y 44): Insertar los datos de una persona.
Ejemplo de Update (Páginas 45 y 46): Actualizar los datos de una persona.
Ejemplo de Delete (Página 47): Borrar una persona.
42
public List<Persona> obtenerTodas()
{
DAOAcceso m_acceso = null;
ListaParametros m_parametros = null;
IDataReader m_datareader = null;
List<Persona> m_personas = new List<Persona>();
try
{
#region Parametros
m_parametros = new ListaParametros();
#endregion
m_acceso = new DAOAcceso();
m_datareader = m_acceso.ExecuteReader("Persona_SEL_Todas", m_parametros);
using (m_datareader)
{
while (m_datareader.Read())
{
m_personas.Add(new Persona
{
Codigo = (Int32)m_datareader["Codigo"],
Nombre = m_datareader["Nombre"].ToString(),
Apellido1 = m_datareader["Apellido1"].ToString(),
Apellido2 = m_datareader["Apellido2"].ToString(),
Domicilio = new Domicilio
{
Direccion = m_datareader["Direccion"].ToString(),
Telefono = m_datareader["Telefono"].ToString()
},
Jefe = new Persona { Codigo = (Int32)m_datareader["Jefe"] }
});
}
}
}
finally
{
if (m_datareader != null)
{
m_datareader.Close();
m_datareader.Dispose();
}
if (m_acceso != null)
m_acceso.CerrarConexion();
}
return m_personas;
}
43
public bool grabar()
{
DAOAcceso m_acceso = null;
ListaParametros m_parametros = null;
int m_filasAgregadas = 0;
bool m_exito = false;
try
{
#region Parametros
m_parametros = new ListaParametros();
//Nombre
if (!String.IsNullOrEmpty(Nombre))
m_parametros.Add(new Parametro { Nombre = "Nombre", Valor = Nombre, Tipo = DbType.String });
else
m_parametros.Add(new Parametro { Nombre = "Nombre", Valor = DBNull.Value, Tipo = DbType.String });
//Apellido 1
if (!String.IsNullOrEmpty(Nombre))
m_parametros.Add(new Parametro { Nombre = "Apellido1", Valor = Apellido1, Tipo = DbType.String });
else
m_parametros.Add(new Parametro { Nombre = "Apellido1", Valor = DBNull.Value, Tipo = DbType.String });
//Apellido 2
if (!String.IsNullOrEmpty(Nombre))
m_parametros.Add(new Parametro { Nombre = "Apellido2", Valor = Apellido2, Tipo = DbType.String });
else
m_parametros.Add(new Parametro { Nombre = "Apellido2", Valor = DBNull.Value, Tipo = DbType.String });
//Domicilio
if (Domicilio != null)
{
//Direccion
if (!String.IsNullOrEmpty(Domicilio.Direccion))
m_parametros.Add(new Parametro { Nombre = "Direccion", Valor = Domicilio.Direccion, Tipo = DbType.String });
else
m_parametros.Add(new Parametro { Nombre = "Direccion", Valor = DBNull.Value, Tipo = DbType.String });
//Telefono
if (!String.IsNullOrEmpty(Domicilio.Direccion))
m_parametros.Add(new Parametro { Nombre = "Telefono", Valor = Domicilio.Telefono, Tipo = DbType.String });
else
m_parametros.Add(new Parametro { Nombre = "Telefono", Valor = DBNull.Value, Tipo = DbType.String });
}
else
{
m_parametros.Add(new Parametro { Nombre = "Direccion", Valor = DBNull.Value, Tipo = DbType.String });
m_parametros.Add(new Parametro { Nombre = "Telefono", Valor = DBNull.Value, Tipo = DbType.String });
}
//Departamento
if (Departamento != null && Departamento.Codigo != 0)
44
m_parametros.Add(new Parametro { Nombre = "Departamento", Valor = Departamento.Codigo, Tipo = DbType.Int32 });
else
m_parametros.Add(new Parametro { Nombre = "Departamento", Valor = DBNull.Value, Tipo = DbType.Int32 });
//Jefe
if (Jefe != null && Jefe.Codigo != 0)
m_parametros.Add(new Parametro { Nombre = "Jefe", Valor = Jefe.Codigo, Tipo = DbType.Int32 });
else
m_parametros.Add(new Parametro { Nombre = "Jefe", Valor = DBNull.Value, Tipo = DbType.Int32 });
#endregion
m_acceso = new DAOAcceso();
m_filasAgregadas = m_acceso.ExecuteNonQuery("Persona_INS", m_parametros);
m_exito = (m_filasAgregadas == 1);
}
finally
{
if (m_acceso != null)
m_acceso.CerrarConexion();
}
return m_exito;
}
45
public bool actualizar()
{
DAOAcceso m_acceso = null;
ListaParametros m_parametros = null;
int m_filasAgregadas = 0;
bool m_exito = false;
try
{
#region Parametros
m_parametros = new ListaParametros();
//Codigo
if(Codigo != 0)
m_parametros.Add(new Parametro { Nombre = "Codigo", Valor = Codigo, Tipo = DbType.Int32 });
else
m_parametros.Add(new Parametro { Nombre = "Codigo", Valor = DBNull.Value, Tipo = DbType.Int32 });
//Nombre
if (!String.IsNullOrEmpty(Nombre))
m_parametros.Add(new Parametro { Nombre = "Nombre", Valor = Nombre, Tipo = DbType.String });
else
m_parametros.Add(new Parametro { Nombre = "Nombre", Valor = DBNull.Value, Tipo = DbType.String });
//Apellido 1
if (!String.IsNullOrEmpty(Nombre))
m_parametros.Add(new Parametro { Nombre = "Apellido1", Valor = Apellido1, Tipo = DbType.String });
else
m_parametros.Add(new Parametro { Nombre = "Apellido1", Valor = DBNull.Value, Tipo = DbType.String });
//Apellido 2
if (!String.IsNullOrEmpty(Nombre))
m_parametros.Add(new Parametro { Nombre = "Apellido2", Valor = Apellido2, Tipo = DbType.String });
else
m_parametros.Add(new Parametro { Nombre = "Apellido2", Valor = DBNull.Value, Tipo = DbType.String });
//Domicilio
if (Domicilio != null)
{
//Direccion
if (!String.IsNullOrEmpty(Domicilio.Direccion))
m_parametros.Add(new Parametro { Nombre = "Direccion", Valor = Domicilio.Direccion, Tipo = DbType.String });
else
m_parametros.Add(new Parametro { Nombre = "Direccion", Valor = DBNull.Value, Tipo = DbType.String });
//Telefono
if (!String.IsNullOrEmpty(Domicilio.Direccion))
m_parametros.Add(new Parametro { Nombre = "Telefono", Valor = Domicilio.Telefono, Tipo = DbType.String });
else
m_parametros.Add(new Parametro { Nombre = "Telefono", Valor = DBNull.Value, Tipo = DbType.String });
}
46
else
{
m_parametros.Add(new Parametro { Nombre = "Direccion", Valor = DBNull.Value, Tipo = DbType.String });
m_parametros.Add(new Parametro { Nombre = "Telefono", Valor = DBNull.Value, Tipo = DbType.String });
}
//Departamento
if (Departamento != null && Departamento.Codigo != 0)
m_parametros.Add(new Parametro { Nombre = "Departamento", Valor = Departamento.Codigo, Tipo = DbType.Int32 });
else
m_parametros.Add(new Parametro { Nombre = "Departamento", Valor = DBNull.Value, Tipo = DbType.Int32 });
//Jefe
if (Jefe != null && Jefe.Codigo != 0)
m_parametros.Add(new Parametro { Nombre = "Jefe", Valor = Jefe.Codigo, Tipo = DbType.Int32 });
else
m_parametros.Add(new Parametro { Nombre = "Jefe", Valor = DBNull.Value, Tipo = DbType.Int32 });
#endregion
m_acceso = new DAOAcceso();
m_filasAgregadas = m_acceso.ExecuteNonQuery("Persona_UPD", m_parametros);
m_exito = (m_filasAgregadas == 1);
}
finally
{
if (m_acceso != null)
m_acceso.CerrarConexion();
}
return m_exito;
}
47
public bool borrar()
{
DAOAcceso m_acceso = null;
ListaParametros m_parametros = null;
int m_filasBorradas = 0;
bool m_exito = false;
try
{
#region Parametros
//Codigo
if (Codigo != 0)
m_parametros.Add(new Parametro { Nombre = "Codigo", Valor = Codigo, Tipo = DbType.Int32 });
else
m_parametros.Add(new Parametro { Nombre = "Codigo", Valor = DBNull.Value, Tipo = DbType.Int32 });
#endregion
m_acceso = new DAOAcceso();
m_filasBorradas = m_acceso.ExecuteNonQuery("Persona_DEL", m_parametros);
m_exito = (m_filasBorradas == 1);
}
finally
{
if (m_acceso != null)
m_acceso.CerrarConexion();
}
return m_exito;
}
48
En los cuatro ejemplos mostrados, el objeto m_acceso de tipo DAOAcceso es el encargado de
abrir una conexión con la base de datos y ejecutar el procedimiento almacenado que
corresponda. Éste objeto tiene dos métodos:
- ExecuteReader: Ejecuta el procedimiento almacenado y obtiene los datos que éste
devuelve en forma de Datareader.
- ExecuteNonQuery: Ejecuta el procedimiento almacenado y devuelve el número de registros
de la tabla que corresponda que se han agregado, actualizado o borrado.
La mayor parte del código se dedica a realizar comprobaciones de si los datos tienen valores o no, a cargar los datos como parámetros de los procedimientos almacenados y a leer los datos obtenidos tras la ejecución de los éstos. En los ejemplos mostrados, no hay ninguno en el que se realicen varias operaciones con la misma o distintas tabla, esto es transacciones. Para ejecutar las transacciones basta con agregar un parámetro más a las funciones de ExecuteReader y ExecuteNonQuery, este parámetro es de tipo booleano que lo que indica es si la operación que va a ejecutar se va a realizar dentro de una transacción o no. Esto en código quedaría de la siguiente manera: m_filasBorradas = m_acceso.ExecuteNonQuery("Persona_DEL",
m_parametros, true);
Por defecto, si no se especifica ningún valor, este es false, que es lo que se ha utilizado en los ejemplos anteriores. Para confirmar o anular una transacción, se ha de llevar en un campo el éxito de cada operación y después de que todas las operaciones hayan finalizado con éxito, antes de cerrar la conexión con la base de datos, es necesario confirmarla. Para ello la clase DAOAcceso tiene dos métodos:
ConfirmarTransaccion, es el commit de la base de datos
AnularTransaccion, es el rollback de la base de datos. Esto en código se traduce de la siguiente manera. if (m_exito)
m_acceso.ConfirmarTransaccion();
else
m_acceso.AnularTransaccion();
Una vez explicado cómo se realiza el acceso a datos mediante código, es hora de analizar el número de clases que se ha desarrollado por proyecto, así como el número de líneas que se han escrito:
Proyecto Pesca Investigación Estadística
Modelo
Nº clases 55 46 33
Líneas de código
1.924 999 1.168
Líneas por clase 34,98 21,71 35,39
DAL
Nº clases 39 43 19
Líneas de código
7.245 11.462 2.393
Líneas por clase 185,76 266,55 125,94 Tabla 6: Recuento de clases y número de líneas de código por proyecto.
49
En el recuento de número de líneas de código, se excluyen todas las líneas en blanco, así como todas las líneas de comentarios.
3.3.3 Métodos web (fichero asmx)
En cada servicio web se crea siempre al menos un fichero asmx, por lo general es siempre un único fichero, en el cual se definen los métodos web. Se define un método web por cada función/método público que exista en los ficheros DAL.
3.4. Aplicaciones web En casi todos los proyectos se crean al menos dos aplicaciones web. Una aplicación privada
dedicada a la gestión o mantenimiento de datos y otra pública que explota los datos
introducidos en la anterior. No obstante, no es raro que haya operaciones comunes en ambas
aplicaciones.
La estructura de estas aplicaciones web es siempre la misma:
- Referencia a una librería de Utilidades que contiene una suma de funciones que se han
ido recopilando a lo largo de varios proyectos desarrollados, en este proyecto se
tratará de darle un orden adecuado y de mejorar las actuales funciones.
- La carpeta App_GlobalResources que contiene ficheros de literales, en los cuales se
almacenan todos los literales y mensajes que la aplicación muestra en algún momento.
Esto nos permite convertir la aplicación multi-idioma realizando unos pequeños
cambios si hiciera falta en algún momento.
- Una carpeta llamada "controles" donde se guardan todos los controles web que se
desarrollan en la aplicación.
- Una carpeta llamada "css" que contiene todas las hojas de estilo que usan las páginas
web.
- Una carpeta llamada "files" que contiene todos los ficheros XML que se usa en la
aplicación.
- Una carpeta para imágenes.
- Una carpeta llamada "js" donde se incluyen todos los scripts de javascript que se usen.
- Una carpeta llamada "negocio" en la cual se incluyen todas las clases de código que la
aplicación utiliza. Dentro de esta carpeta se encuentran las siguientes subcarpetas
habitualmente:
o "AccesoDatos": Dentro de esta carpeta se encuentran todas las clases que
acceden a los distintos métodos web de los distintos servicios web que use la
aplicación. Los nombres de las clases y del fichero de estas clases se forma
uniendo la palabra AccesoDatos y el nombre de la entidad. Por ejemplo todos
50
los accesos a datos relativas a la entidad Persona se encuentra en la clase
AccesoDatosPersona y el fichero es AccesoDatosPersona.cs.
o "Clases": En esta carpeta se incluyen todas las clases que se definen en la
aplicación y no son utilizadas en ningún servicio web.
o "DatosSession": Contiene una serie de clases que gestionan todos los datos
que se guardan en sesión. Al igual que las clases de acceso a datos, se crea una
clase por entidad. El nombre de las clases se crea uniendo la palabra Datos y el
nombre de la entidad. Ejemplo: DatosPersona.
o " Gestion": Contiene una serie de clases que se dedican a realizar operaciones
con los datos antes de ser enviados al servicio web, o en algunas ocasiones
estas clases contienen funciones para generar ficheros excel, pdf, etc. También
se crea una clase por entidad, se usa el prefijo Gestion, así tendremos por
ejemplo la clase GestionPersona.
o "Paginacion": Contiene una serie de clases que facilitan la paginación de los
resultados.
o "Parametros": Contienen una serie de clases que facilitan el acceso a los datos
que están parametrizados en la aplicación. Estos parámetros pueden estar
definidos en ficheros XML o en el fichero de configuración de la aplicación
(web.config). Se crea una clase de parámetros por cada fichero xml de
configuración que haya en la carpeta files.
- Dependiendo del número de páginas que vaya a contener la aplicación, se crean
carpetas para alojar las diferentes páginas web. En caso de que el número de páginas
vaya a ser escaso, no se crea ninguna carpeta.
- Una página maestra o máster page, en la cual se definen los elementos comunes a
todas las pantallas, estos elementos son:
o Un control web para mostrar la cabecera.
o Un control web para mostrar el menú.
o Un control web para mostrar el pie de la aplicación.
o Se reserva una parte de la pantalla para mostrar el título de la página, así
como para mostrar los avisos de validaciones, errores, etc.
o Un control de tipo ContentPlaceHolder, donde cada página que se
desarrolle partiendo de esta página maestra mostrará su contenido.
No en todas las aplicaciones que aquí se analizan a modo de ejemplo, usan páginas
maestras. De los proyectos analizados el proyecto de "Proyectos de investigación" no
usa páginas maestras. El resto, Permisos de Pesca y la Web del Instituto de Estadística
sí. El uso de páginas maestras es una buena práctica que tardó en asimilarse.
51
A continuación se muestra una imagen de ejemplo de
cómo está organizada la aplicación de gestión del
proyecto de la Web del Instituto de Estadística.
3.4.1 Aplicaciones internas o de gestión
Estas aplicaciones se caracterizan por realizar un mantenimiento de los datos que hay en las tablas de las base de datos, para ello utiliza los métodos web definidos en el servicio web. Para acceder a los métodos web se crean clases intermedias que encapsulan éstos accesos (negocio / AccesoDatos). Los mantenimientos de los datos se realizan en pantallas que suelen tener muchos elementos comunes y la apariencia (diseño) de las mismas es muy similar. En general estas pantallas están organizadas de la siguiente manera:
- Una pantalla inicial, sobre la cual podemos realizar una búsqueda en base a una serie de filtros, que son los campos de la tabla sobre la cual se realiza el mantenimiento de los datos. Los resultados de la búsqueda incluyen un enlace a editar los resultados. Además en esta primera pantalla se incluye un botón que permite dar de alta un nuevo registro. En otros casos la pantalla inicial consiste en un mero listado de los elementos que se han dado de alta anteriormente.
- Una pantalla para realizar altas o modificaciones, se distingue si es un alta o una modificación en función de si la url contiene un parámetro con el código o no. La pantalla contiene una serie de cajas de texto donde se introduce o modifica la información de ese registro. Esta pantalla tiene un botón para guardar los cambios y otro para volver a la pantalla anterior.
Figura 14: Ejemplo organización proyecto
52
- Al pulsar el botón de guardar, se realizan las validaciones de los datos y si cumple todas las validaciones se guarda o actualiza el registro en la base de datos. Se muestran mensajes tanto en caso de éxito como de fracaso.
Estos mantenimientos que son relativamente sencillos existen en casi todos los proyectos de
gestión. En los proyectos analizados se han encontrado el siguiente número de
mantenimientos sencillos.
Proyecto Pesca Investigación Estadística
Número 3 10 2 Tabla 7: Recuento de mantenimientos sencillos.
Estos mantenimientos suelen tener el siguiente aspecto:
Figura 15: Ejemplo mantenimiento sencillo.
En los mantenimientos descritos anteriormente toda la información que se guarda se recoge
de campos de texto o checkbox. No obstante existen otros mantenimientos en los que además
se muestra información en elementos desplegables o de listados. La información que se
muestran en estos elementos, se obtiene por medio del servicio web y son elementos
guardados en otra tabla de la base de datos. Al final lo que se recoge de estos elementos es
qué elemento o elementos están seleccionados y esta información se guarda en la base de
datos. A estos mantenimientos les voy a llamar mantenimientos intermedios. Un ejemplo:
53
Figura 16: Ejemplo mantenimiento intermedio.
Conforme a esta definición, nos encontramos las siguientes pantallas en los proyectos
analizados que cumplen con estos requisitos:
Proyecto Pesca Investigación Estadística
Número 4 7 1 Tabla 8: Recuento de pantallas con mantenimientos intermedios.
Y por último existen otros mantenimientos más complicados donde ya se mezclan elementos
más complejos como pestañas, búsquedas en páginas modales, etc. Estos mantenimientos
"avanzados" suelen ser el núcleo de las aplicaciones y su desarrollo es bastante costoso.
De todas formas tanto los mantenimientos sencillos, como los intermedios, como los
avanzados tienen en común, la validación de los datos:
- Campos obligatorios.
- Fechas.
- Números enteros, decimales, etc.
- Longitud de campos.
- Etc.
54
3.4.2 Aplicaciones públicas
Las aplicaciones web que son públicas se dedican en general a explotar los datos cargados en
la aplicación de gestión. No obstante también pueden hacer tareas de alta y modificación de
datos, pero rara vez suele poder darse de baja registros de la base de datos. Estas aplicaciones
son en gran parte de los casos, aplicaciones multi-idiomas. Para poder cambiar el idioma que
está activo a otro idioma se agregan botones o enlaces en la cabecera de la aplicación, que
gestionan el cambio del idioma.
También es común que tengan búsquedas de datos, pudiendo buscar por una serie de filtros
para luego poder acceder a una ficha de datos del elemento seleccionado. Además las
aplicaciones web públicas se caracterizan por tener una presentación de los datos mucho más
vistoso.
La lógica de negocio de estas aplicaciones suele ser lo más complejo de todo el proyecto,
puesto que aparte de recuperar los datos de la base de datos, es necesario darles cierto
formato, para mostrar los datos de forma que se entienda fácil y rápido. Además en muchos
casos es necesario cumplir unos requisitos mínimos de accesibilidad, actualmente es necesario
cumplir con el segundo nivel (AA). Es por ello que en las aplicaciones públicas el diseño de las
pantallas es muy importante y debido a ello el esfuerzo es mayor al de las aplicaciones de
gestión.
55
3.5. Conclusiones Tras haber analizado las diferentes partes que componen un proyecto podemos decir que los
principales esfuerzos se dedican a:
- El acceso a datos: Creación de procedimientos almacenados, creación de las clases, tanto del
modelo de datos (entidades) como las clases para el acceso a datos (DAL), métodos web para
acceder a cada método público definido en la capa de acceso y clases en las aplicaciones para
acceder a los métodos web.
- Formularios de mantenimiento de datos: En toda aplicación siempre hay una serie de páginas
web (generalmente en las aplicaciones de gestión) desde las cuales los datos son introducidos,
modificados o eliminados.
- Validación de datos: Tanto en el servicio web, para comprobar si una propiedad de la clase
tiene valor, como en las aplicaciones web, para ver si el dato introducido es correcto.
En el siguiente capítulo PT021 Análisis. BrainStorm se analiza las posibles herramientas a
desarrollar y qué funciones desempeñarán.
56
4. Brainstorm A continuación se muestra el listado de posibles funcionalidades a implementar:
1. Evolucionar la actual librería de utilidades, para que comprendan un amplío abanico de
funciones que puedan ser necesarias en un proyecto. Conversiones de tipo, validaciones
de datos, etc. Introducir el uso de funciones genéricas.
2. Generador de procedimientos almacenados. Eligiendo una base de datos, tabla y
operación se generará el procedimiento almacenado en la base de datos elegida. Estudiar
la posibilidad de crear una interfaz gráfica sobre la cual se pueda elegir una serie de tablas
que estén relacionadas y elegir varios campos de ellas, para generar procedimientos
almacenados de búsquedas.
3. Posibilidad de agregar a una base de datos una serie de funciones comunes (split,
quitarAcentos, etc.)
4. Generador de clases. A partir de una tabla de una base de datos, crear una clase con tantas
propiedades como campos tiene la tabla. La conversión de los tipos podrá escogerse o
estar parametrizada. En caso de estar parametrizada, debería existir la posibilidad de
poder cambiar los diferentes tipos de conversión.
5. Buscar una manera de automatizar la creación de objetos a partir de los datos obtenidos
tras la ejecución de un procedimiento almacenado. Algunas de las posibles opciones son:
agregar una función o constructor de clases que reciba los datos obtenidos del
procedimiento almacenado ejecutado o intentar crear un constructor universal, de manera
que dados los resultados del procedimiento almacenado, éste sea capaz de crear un objeto
del tipo que corresponda con las propiedades que correspondan informadas.
6. Generador de código de acceso a datos, que sea capaz con pocas instrucciones por parte
del usuario de crear el código necesario para ejecutar un procedimiento almacenado,
agregando los parámetros necesarios para cada caso, leer los datos obtenidos del
procedimiento almacenado y crear el objeto que corresponda.
7. Herramienta para la generación de código de los métodos web y su correspondientes
llamadas a las clases que contienen las funciones de acceso a datos.
8. Crear una librería de controles web, que agreguen funcionalidad para la validación de
datos, que compruebe si un campo es obligatorio, si el contenido del control se
corresponde al tipo que tiene establecido, si el valor del control es válido, etc. Además esta
librería deberá ser capaz de generar los mensajes de aviso correspondientes.
9. Crear una herramienta que sea capaz de, dado un boceto de una página web HTML o aspx,
una clase (que representa a una tabla) y la librería desarrollada en el punto 8, de generar
los controles web estableciendo las propiedades de cada control según el tipo de datos
57
que va a contener. Se trata de relacionar cada campo de la página web con las
propiedades de la clase y así escoger el control que va a contener la información.
Crear una aplicación de escritorio (Windows) que reúna todas las características mencionadas
y que permita gestionar toda la información de tablas, procedimientos almacenados, clases,
propiedades, etc. pudiendo recuperar en cualquier momento la información que estas
herramientas han generado. Esta aplicación deberá poder ser ejecutada por varios usuarios a
la vez, por lo cual toda la información que deba ser almacenada, deberá hacerse en una base
de datos a la cual tengan acceso todos los usuarios. Para ello se utilizará un servidor de base de
datos.
El desarrollo de estas herramientas, librerías y en definitiva utilidades se plantean como
diferentes módulos de la aplicación, que compartirán información y en muchas ocasiones la
información que un módulo recupere o genere, será usado por otros módulos posteriormente.
58
5. Análisis. Librerías Utilidades y Controles Web
Personalizados. En este capítulo se va a realizar el análisis de las librerías que han de desarrollarse. Estas
librerías son:
- Librería de Utilidades, abarca un amplio abanico de funciones comunes a varios
proyectos.
- Librería de Controles Web personalizados, que permitan la validación de los datos
introducidos. Esta librería utilizará funciones definidas en la librería Utilidades.
5.1 Librería Utilidades. Antes de empezar a listar las posibles funciones que va a tener esta librería, se ha de definir la
estructura que va a tener.
La idea es agrupar las funciones en diferentes clases, según el tipo de datos que manejen,
siempre que sea posible. Así tendremos una clase para todas las funciones que operen con
fechas, otra para números, cadenas, listas, etc. Habrá ocasiones en las que existan funciones
que no sean posible agruparlas de esta manera. Por ejemplo hay funciones que se encargan de
generar logs y escribirlos en ficheros de texto. En este caso las funciones estarán agrupadas en
clases donde se comparta una misma funcionalidad.
Cada clase estará almacenada en un único fichero cuyo nombre seguirá el patrón
Utiles[TipoDato][Funcionalidad]
La librería constará además de una clase raíz, con nombre Utilidades, que contendrá tantas
propiedades como clases del tipo Utiles[TipoDato][Funcionalidad] existan. Estas propiedades
se crearán siguiendo el patrón Lazy, es decir, se crearán los objetos si son solicitados.
Todas las clases y funciones se definirán no estáticas, ya que esta librería está pensada para
utilizarse en aplicaciones web y el hecho de utilizar clases y funciones estáticas puede dar lugar
a serios problemas de compartición de recursos dentro de los servidores, es lo que sucede
actualmente en la versión actual de esta librería, por lo cual muchas de sus funciones han
caído en desuso.
Otra diferencia respecto a la versión actual de la librería de Utilidades es el cambio de tipo de
nomenclatura, pasando de la Camel a la nomenclatura Pascal. En la nomenclatura Camel la
primera letra del identificador está en minúscula y la primera letra de las siguientes palabras
concatenadas en mayúsculas, mientras que en la Pascal todas las primeras letras comienzan
por mayúsculas.
5.1.1 Clases Útiles según tipos de datos
- Arrays:
Función ContieneDatos: Recibirá un array y comprobará que no sea valor nulo y
que tenga al menos un elemento.
59
- ArrayList:
Función ContieneDatos: Recibirá un objeto de tipo arrayList y comprobará que no
sea nulo y que tenga al menos un elemento.
- Booleanos:
Función ConvertirCadenaABooleano: Recibirá dos cadenas de texto, devolverá el
resultado de la comparación entre ambas cadenas, siempre y cuando ambas
tengan valor. Esta función se usa para cuando un campo de una base de datos usa
dos valores diferentes para almacenar información pero el tipo de dato no es bit
(booleano) y nos interesa trabajar con variables booleanas.
- Bytes:
Función ObtenerBytes: Recibirá un objeto de tipo HttpPostedFile (este objeto se
obtiene de los controles FileUpload, que se utilizan para elegir ficheros concretos
del equipo del usuario para posteriormente guardarlos en otro repositorio) y
devolverá el array de bytes del documento escogido.
- Cadenas:
Función ContieneDatos: Recibirá una cadena de texto y comprobará que la cadena
ni es nula ni es vacía.
Función Concatenar, recibe una lista de cadenas de texto y un separador,
devolverá una cadena de texto que contenga todas las cadenas de texto unidas por
la cadena separador. Tendrá una sobrecarga, en la cual se añadirán dos
parámetros más, uno es la longitud máxima que la cadena puede alcanzar y otro
que será un parámetro de salida que indicará el número de cadenas que se han
empleado en la concatenación de las mismas. Esta sobrecarga es útil cuando se
quieren pasar múltiples valores a un procedimiento almacenado separados por un
carácter, para posteriormente usar la función split. La longitud máxima de un
parámetro de entrada de un procedimiento almacenado es de 8000 caracteres,
por lo que en algunos casos es necesario ejecutar varias veces el mismo o agregar
varios parámetros de entrada.
Función ConvertirBooleanoACadena, recibe tres parámetros, un booleano y dos
cadenas de texto. La primera cadena de texto contiene el valor que se devolverá
en caso de que el parámetro booleano tenga valor verdadero y en caso contrario
se devolverá el segundo. Esta función es muy utilizada cuando en la base de datos
en vez de guardar el dato como tipo bit (booleano) se guarda como cadena de
texto.
- DataReader:
Función ExisteCampo: Recibirá un objeto de tipo DataReader (este objeto es el
resultado obtenido tras ejecutar un procedimiento almacenado de selección de
datos o select, su funcionamiento es parecido al de un DataSet) y el nombre de un
60
campo. Se comprobará que dentro del objeto DataReader existe un campo con el
nombre recibido.
Función ContieneDatos: Recibirá un objeto de tipo DataReader y un parámetro de
tipo cadena que contendrá el nombre del campo. Se comprobará que el
DataReader contiene el campo y que el campo contiene datos (sólo se comprobará
que el valor sea diferente a nulo).
Desarrollar múltiples funciones para obtener los valores de los campos, dado un
DataReader y el nombre de un campo, obtener el valor del campo como objetos
de tipo numérico, fechas, cadenas, booleanos, etc.
- DataSet:
Función ContieneDatos: Recibirá un objeto de tipo DataSet y comprobará que no
es nulo y que al menos contiene un objeto DataTable.
- DataTable:
Función ContieneDatos: Recibirá un objeto de tipo DataTable y comprobará que
no es nulo y que al menos contiene un objeto DataRow.
- DataRow:
Función ContieneDatos: Recibirá un objeto de tipo DataRow y comprobará que no
es nulo y que al menos contiene un elemento.
- Fechas:
Función EsFechaValida: Recibirá una cadena de texto. Comprobará que la cadena
de texto tiene valor, y si es así comprobará si la cadena de texto se corresponde
con una fecha válida. Devolverá un valor booleano que indique si la cadena de
texto se corresponde con un fecha válida o no. Esta función tendrá una
sobrecarga, en ella recibirá un parámetro más que indicará el formato de la fecha.
Función Convertir: Recibirá una cadena de texto. Se comprobará si se corresponde
con una fecha válida y en caso afirmativo devolverá un objeto de tipo fecha con el
valor que le corresponda. Esta función tendrá una sobrecarga, en ella recibirá un
parámetro que indicará el formato de la fecha.
- Listas:
Función ContieneDatos: Recibirá una lista de objetos y comprobará que la lista no
sea nula y que al menos contenga un elemento.
Función ObtenerRango: Función que recibirá una lista de objetos y dos valores
numéricos que indicarán desde qué posición inicial hasta qué posición final se
toma de la lista de objetos inicial, devolverá una lista con los elementos que se
encuentren dentro del rango establecido.
61
- Números:
Función ContieneDatos: Esta función recibirá un parámetro de tipo numérico y
devolverá un booleano que indicará si el valor del número se considera un valor o
no. Por defecto se validará que el valor sea diferente a 0. Esta función se
sobrecargará para que reciba otro parámetro que indique contra que valor se ha
de comprobar para dar por bueno el dato que contiene.
Conversiones desde cadenas de texto a números, conversiones a números enteros,
decimales, etc. Estas funciones tendrán como parámetro de entrada cadenas de
texto y devolverán el tipo de dato que corresponda a cada función.
5.1.2 Clases Útiles según funcionalidad
- BaseDeDatos:
Función ObtenerValorAGrabar con múltiples sobrecargas: Esta función obtendrá
un objeto de un determinado tipo y comprobará si tiene valor en cuyo caso
devolverá el mismo valor recibido pero en caso contrario devolverá DBNull.Value
que es el valor equivalente a grabar nulo en la base de datos.
- Configuración:
Función ObtenerValorClave: Esta función recibirá el nombre de la clave que pueda
existir en el archivo de configuración (web.config) y devolverá su valor en caso de
que exista como cadena de texto.
- ControlesWeb:
Función CargarDatos con múltiples sobrecargas: Esta función recibirá un control
web, un objeto o una lista de objetos y se encargará de cargar la lista de objetos
dentro del control.
Función con múltiples sobrecargas: Esta función comprobará para cada tipo de
control web que reciba (cajas de texto, combos, etc.) si contiene algún elemento.
Función ObtenerDato con múltiples sobrecargas: Esta función recibirá un control
web y devolverá una lista de los objetos seleccionados.
Función SeleccionarElemento con múltiples sobrecargas: Esta función recibirá un
control web y un objeto que contenga la información del elemento que se quiera
seleccionar. Está función está pensada para controles web que admiten varios
elementos al mismo tiempo, como es el caso de los combos, listas, etc.
- Email:
Función EsValido: Recibe una cadena de texto y la función validará si la cadena de
texto recibida se corresponde con un correo electrónico válido o no.
- Logs:
62
Función RegistrarError: Recibe un objeto de tipo Exception y la función se
encargará de guardar el log en un fichero, escribirá la palabra ERROR seguido de la
fecha y hora del momento. A continuación escribirá el mensaje de la excepción así
como la pila del error. El fichero sobre el que tiene que escribir la función estará
descrito en el fichero de configuración de la aplicación.
Función RegistrarAviso: Genera el mismo mensaje que la función RegistrarError
salvo que se sustituye la palabra ERROR por AVISO.
Función RegistrarInformación: Genera el mismo mensaje que la función
RegistrarError salvo que sustituye la palabra ERROR por INFORMACIÓN.
En las tres funciones se comprobará si se puede escribir el mensaje de error, aviso o
información. En el fichero de configuración se definirá los mensajes que se pueden
registrar. Esta configuración tendrá un valor numérico 0, 1, 2 ó 3.
o La función RegistrarError podrá escribir la excepción siempre que el valor sea
mayor que 0.
o La función RegistrarAviso podrá escribir la excepción siempre que el valor sea
mayor que 1.
o La función RegistrarInformación podrá escribir la excepción siempre que el
valor sea mayor que 2.
- Serialización:
Función Serializar: Recibe un objeto y devuelve una cadena de texto con el objeto
serializado.
Función Deserializar: Recibe una cadena de texto y el tipo del objeto que se quiere
obtener y devuelve un objeto del tipo recibido con los datos deserializados.
- Xml:
Función LeerFichero: Recibe la ruta de un fichero XML y devuelve un objeto de tipo
DataSet con los datos del fichero si este existe.
Función ObtenerParámetro: Recibe la ruta de un fichero XML y el nombre de de
uno de los nodos del fichero. La función devuelve el valor del nodo dentro del
fichero XML Internamente esta función llamará a la función LeerFichero para
obtener los datos del XML
En principio éstas son las funciones que previsiblemente más se pueden llegar a usar. Los
nombres de las mismas pueden tener alguna variación durante el desarrollo de las mismas. En
caso de que surjan nuevas necesidades, se crearán las funciones que se consideren oportunas
dentro de las clases que ya existan o puede que se cree alguna clase nueva.
63
5.2 Librería de Controles Web personalizados. El objetivo de esta librería es automatizar, en la manera de lo posible, la validación de los datos
introducidos en los controles web, cajas de texto, combos, listas, etc., así como los mensajes
de avisos.
Actualmente existen en .NET controles de validación, Validators. Para hacer uso de ellos hay
que crear un nuevo control por cada validación que se quiera hacer. Por ejemplo, para validar
que un campo es obligatorio y además que el valor introducido es de tipo fecha han de
crearse dos controles más.
Lo que se pretende con esta librería es crear una serie de controles personalizados que
permitan automatizar la validación de los datos sin tener que recurrir a nuevos controles, para
validar su contenido. Estos controles heredarán de los controles que ya existen pero estarán
incluidos en un espacio de nombre diferente.
5.2.1 Controles y validaciones más comunes
En casi cualquier aplicación web, los controles web más utilizados son:
- TextBox: en este control se puede introducir casi cualquier dato, cadenas de texto,
números, fechas, direcciones de correo electrónico, contraseñas, etc.
- DropDownList: este control se caracteriza por tener una serie de elementos cargados,
de los cuales sólo se puede elegir uno de ellos.
- ListBox: este control es parecido a los DropDownList, sólo que está permitido la
selección múltiple de sus elementos, aunque esta opción se puede activar o no.
- CheckBoxList: este control es parecido al control ListBox, puesto que al lado de cada
elemento aparece un Check que permite marcarlo como seleccionado.
- RadioButtonList: este control es parecido al CheckBoxList, sólo que en vez de tener un
control Check, tiene un control de tipo Radio, por lo que sólo es posible seleccionar
uno de sus elementos.
Por otra parte las validaciones más comunes son:
1. Campo obligatorio, validar que se hayan introducido datos, escogido o marcado una
opción.
2. Validar el tipo de información que contiene el control, fechas, números enteros,
números decimales, emails, etc.
3. Validaciones funcionales, por ejemplo si se ha introducido una fecha, validar que esta
sea mayor o menor comparada con otra fecha que exista en otro campo, validar que el
número introducido en un control no sea superior a una cantidad establecida, etc.
Es en el tercer grupo de validaciones donde hay que analizar las posibles validaciones a
automatizar. Éstas se pueden concretar más si las separamos según el tipo de control que es y
el tipo de datos que va a contener. Es en el control TextBox donde más variantes va a haber, ya
que en el resto de controles lo que más interesa saber es cuál o cuáles son los elementos
seleccionados.
64
Aparte de las validaciones que se puedan llevar a cabo, es interesante agregar una serie de
propiedades comunes a todos los controles que aporten nuevas funcionalidades:
- Obligatorio: Indicar de forma explícita si el control ha de contener algún valor en caso de
ser un TextBox o tener algún elemento seleccionado en el resto de casos.
- Literal del control: En general todos los controles webs tienen anteriormente una etiqueta
que contienen una descripción del campo que se va rellenar (nombre, apellido, fecha de
nacimiento, etc.), sería útil asociar esta etiqueta o literal al control, para así poder generar
mensajes de aviso más concretos, por ejemplo: El campo Nombre es obligatorio.
- Orden: No siempre el orden aparente de los controles en las páginas webs, es el que
corresponde dentro de la página aspx, esto es debido a que hoy en día se trabaja con
bloques flotantes (divs), y por ello es necesario indicar cuál es el orden en el que se van a
validar los controles y por tanto cuál va a ser el orden de los mensajes de validación que se
van a generar.
- Estilo (de CSS) a aplicar cuando el control no cumpla sus validaciones. Por ejemplo se
podría hacer que cuando un control haya sido marcado como obligatorio y este no
contenga ningún dato, el control aparezca con un borde rojo y si el dato introducido no se
corresponde con su tipo, el borde aparezca de otro color.
Aparte de estas propiedades comunes a todos los controles, para cada tipo de control, se
agregarán propiedades específicas para cada uno.
A continuación se muestra para cada tipo control la lista completa de propiedades que va a
tener.
5.2.2 TextBox
Este control es sin lugar a dudas el más complejo de todos,
puesto que admite cualquier tipo de contenido. Es por ello que
se ve necesario crear varios controles según el tipo de dato que va a contener, de esta manera
se van a crear los siguientes controles:
- TextBoxTexto: Para almacenar información que sea texto, admitirá cualquier
contenido, pero no validará el tipo de contenido.
- TextBoxEntero: Almacenará información de tipo numérico, no admitirá decimales.
- TextBoxDecimal: Almacenará información de tipo numérico admitiendo decimales.
- TextBoxFecha: Almacenará información de tipo fechas.
Todos estos controles tendrán propiedades y validaciones comunes, por lo que todos ellos
heredarán de una clase intermedia (y abstracta) que se creará a tal efecto, que ésta a su vez
heredará del control TextBox.
Figura 17: TextBox
65
Esta clase intermedia tendrá las siguientes propiedades:
- Obligatorio: Indica si el campo lo es o no.
- Orden: Indica el orden en el que se valida los datos y el orden en que se generarán los
avisos de validación.
- IdLiteralCampo: Es el id de la etiqueta (label) que contiene la descripción del campo.
Esta etiqueta tendrá que ser un control de servidor, es decir debe tener la propiedad
runat="server" establecida, para que la librería pueda recuperar la descripción del
campo.
- LiteralCampo: Se indica de forma explícita la descripción del campo, se agrega esta
propiedad por si hubiera algún control que no fuera a tener una etiqueta con la
descripción del campo.
- Dato: Devuelve el contenido del control como tipo de dato cadena.
- ContieneDato: Esta propiedad indicará si el control tiene datos o no. Sólo validará que
la longitud del dato introducido es mayor que cero.
- EsValido: Esta propiedad dirá si el control cumple con todas las validaciones
requeridas.
- Avisos: Es el listado de avisos que se generen al validar los datos del control.
Además tendrá las siguientes funciones:
- ObtenerDato: Devolverá el contenido del control como cadena de texto. Esta función
se llamará desde la propiedad Dato.
- Validar: Realizará todas las comprobaciones que hayan sido establecidas. Esta función
se llamará desde la propiedad EsValido.
Puesto que esta clase hereda de la clase TextBox, hereda sus propiedades y sus funciones.
Cabe destacar la propiedad MaxLength, que se corresponde con la longitud máxima que
admite el control. El valor de esta propiedad se tendrá en cuenta en las validaciones.
5.2.2.1 TextBoxTexto
Se agrega la propiedad TipoDato que admite como posible opciones:
- Texto: no se agregará ninguna nueva validación.
- Email: se validará que el contenido se corresponda con un email válido.
Se agrega la propiedad Valor que devuelve el contenido del control como tipo numérico string.
5.2.2.2 TextBoxEntero
Se agrega la propiedad TipoSigno con los siguientes posibles valores:
- Positivo: Sólo se admitirán números con signo positivo.
- Negativo: Sólo se admitirán números con signo negativo.
- Ambos: Opción por defecto, se admite cualquiera de las dos anteriores.
Se agrega la propiedad TipoUso que según el valor que tenga establecido hará uso de unas u
otras propiedades.
66
Todas se explican a continuación:
- Simple: Se usa cuando se quiere introducir un número entero, sin compararlo con
ningún otro valor.
- MenorA: Se usa cuando el valor que se va a introducir debe ser inferior a otro
establecido, para ello se agregan dos nuevas propiedades:
o ValorSuperior: Indica que el valor introducido debe ser inferior al valor de esta
propiedad.
o AdmitirIgualSuperior: Indica si se admite la igualdad del valor como válido, por
defecto no se admitirá.
- MayorA: Se usa cuando el valor que se va a introducir debe ser superior a otro
establecido, para ello se agregan dos nuevas propiedades:
o ValorInferior: Indica que el valor introducido debe ser superior al valor de esta
propiedad.
o AdmitirIgualInferior: Indica si se admite la igualdad del valor como válido, por
defecto no se admitirá.
- Rango: Usaremos esta opción cuando el valor introducido en el control deba estar
dentro de un rango de valores, que se establecerán en el mismo control. Para ello se
usarán las propiedades ya presentadas: ValorSuperior, ValorInferior,
AdmitirIgualSuperior y AdmitirIgualInferior.
- RangoDesde: Esta opción indicará que el control actual actuará como el valor desde
dentro de una relación de dos controles. Existirá por tanto otro control que indicará
que es el control hasta (RangoHasta) Para usar esta opción se presentan las siguientes
propiedades:
o EsDesde: Indica que el control se comporta como el valor desde.
o IdentificadorRango: Esta propiedad identifica a la pareja de controles que van
a actuar como un único rango. El valor de esta propiedad será el mismo tanto
en el control desde (RangoDesde) como en el control hasta (RangoHasta)
- RangoHasta: El control con esta propiedad actuará como el valor hasta dentro del
grupo que tenga el mismo identificador (IdentificadorRango) del rango. Para usar esta
opción se presenta la siguiente propiedad:
o EsHasta: Indica que el control se comporta como el valor hasta.
Se agrega además la propiedad Valor, que devuelve el valor de la caja de texto, en caso de que
este sea válido (sea un número)
Todas las propiedades descritas usarán el tipo numérico int, salvo EsDesde y EsHasta que serán
de tipo booleano.
5.2.2.3 TextBoxDecimal
Para este control se agregan las mismas propiedades que para el control TextBoxEntero, sólo
que el tipo de datos que manejan internamente es decimal.
Se agregan además las siguientes propiedades:
- DigitosEnteros: Indica el número máximo de dígitos de la parte entera del número.
- DigitosDecimales: Indica el número máximo de dígitos de la parte decimal del número.
67
5.2.2.4 TextBoxFecha
Para este control se agregan las mismas propiedades que para el control TextBoxEntero, sólo
que el tipo de datos que manejan internamente es DateTime. Además se agregan tres nuevas
opciones dentro de la propiedad TipoUso, estas son:
- FechaNacimiento: El valor que se va a introducir se corresponderá con una fecha de
nacimiento. Se validará que la fecha introducida sea menor que la actual y además que
la diferencia en años respecto a la actual no sea superior a 130 años. Este valor estará
parametrizado dentro de la librería.
- MayorHoy: Este uso es un uso particular del caso MayorA, lo que se pretende es
mostrar un mensaje específico, indicando que la fecha introducida no puede ser mayor
a la de "hoy".
- MenorHoy: Uso particular del caso MenorA, al igual que en el caso MayorHoy se
pretende mostrar un mensaje específico, pero esta vez indicando que la fecha sea
menor a la de "hoy".
Se agrega además la propiedad FormatoFecha, en la cual se podrá indicar como cadena de
texto el formato de la fecha que ha de introducirse. Esta propiedad es muy importante en
páginas multi-idiomas, puesto que el formato de fecha es diferente entre los distintos idiomas.
5.2.3 DropDownList
Este control es después del TextBox de los más utilizados. Este control
muestra una serie de elementos en una lista desplegable y permite
escoger uno de ellos.
Los elementos (objetos) que se agregan al control son de los más
variados, aunque todos ellos tienen en común que cada elemento tiene una propiedad que se
utiliza para mostrar la descripción y otra propiedad (en ocasiones es la misma propiedad de la
descripción) que tiene el identificador del elemento mostrado.
Además en este control se suele agregar un elemento al principio, éste suele tener la
descripción "Seleccionar" y su valor se establece a "0".
Al igual que hemos hecho para todos los controles TextBox... , que heredan de una clase
intermediaria, lo mismo haremos para este control. Esta clase intermedia tendrá las mismas
propiedades y funciones que la descrita anteriormente, sin embargo su nombre será diferente.
Esto debe hacerse así puesto que C# no admite herencia múltiple, si no habría una única clase
intermedia y luego cada control a desarrollar heredaría de esta clase intermedia y del control
al que se quiere agregar funcionalidad.
Además para este control se agregan las siguientes propiedades:
- TextoPoDefecto: es el literal del elemento que se muestra al inicio del control.
- ValorPorDefecto: es el valor del elemento que se muestra al inicio del control.
- HayElementoSeleccionado: Determina si hay un elemento seleccionado o no, el
elemento que se agrega para mostrarlo por defecto no se tiene en cuenta.
- ElementoSeleccionado: Devuelve como objeto el elemento seleccionado en el control.
Figura 18: DropDownList
68
5.2.4 ListBox
Este control muestra una lista de elementos, de los cuales se pueden
seleccionar uno o varios elementos. Al igual que en el control anterior,
DropDownList, los elementos que se agregan pueden ser muy variados
pero tienen los mismos elementos en común, se eligen el nombre de dos
propiedades, uno para mostrar una descripción y otra para identificar a
cada valor mostrado.
Este control también heredará de una clase intermediaria con las mismas propiedades y
funciones que la descrita para el control TextBox, la diferencia estará en que esta clase
intermedia heredará del control ListBox.
Para este control se agregan las siguientes propiedades:
- HayElementosSeleccionados: Determina si hay algún elemento seleccionado.
- ElementosSeleccionados: Devolverá una lista de los objetos
que estén seleccionados.
5.2.5 CheckBoxList
Este control es muy similar al ListBox, puesto que al lado de cada
elemento aparece un Check que permite marcarlo como seleccionado.
Este control también heredará de una clase intermediaria con las
mismas propiedades y funciones que la descrita para el control TextBox, la diferencia estará en
que esta clase intermedia heredará del control CheckBoxList.
Para este control se agregan las siguientes propiedades:
- HayElementosSeleccionados: Determina si hay algún elemento seleccionado.
- ElementosSeleccionados: Devolverá una lista de los objetos que estén seleccionados.
5.2.6 RadioButtonList
Este control es parecido al CheckBoxList, sólo que en vez de tener un
control check, tiene un control de tipo radio, por lo que sólo es
posible seleccionar uno de sus elementos.
Este control también heredará de una clase intermediaria con las
mismas propiedades y funciones que la descrita para el control
TextBox, la diferencia estará en que esta clase intermedia heredará
del control RadioButtonList.
Para este control se agregan las siguientes propiedades:
- HayElementoSeleccionado: Determina si hay un elemento seleccionado o no, el
elemento que se agrega para mostrarlo por defecto no se tiene en cuenta.
- ElementoSeleccionado: Devuelve como objeto el elemento seleccionado en el control.
Figura 19: ListBox
Figura 20: CheckBoxList
Figura 21: RadioButtonList
69
5.2.7 Validación de los controles
Para poder validar todos los controles es necesario crear una clase que sea capaz de
localizarlos dentro de la página web e ir llamando a la función de validar de cada uno de ellos.
Deberá acumular los avisos que se vayan generando y ser capaz de devolverlos en el orden
establecido.
Se creará por tanto un método con nombre ValidarControles que recibirá o bien el formulario
de la página web o un control div. Este proceso buscará todos los controles definidos en la
librería e irá llamando a la función de validar de cada uno de los controles.
70
6. Fase I En este capítulo se va a realizar el análisis de la primera fase (iteración) de la aplicación
principal, que en realidad se trata de un conjunto de herramientas que permitirán generar
código de una manera rápida y eficiente con la participación del usuario. Las herramientas de
que dispondrá en esta fase son:
Generador de procedimientos almacenados para realizar operaciones contra las tablas
de una base de datos.
Herramienta para agregar funciones a una base de datos, por ejemplo: quitarAcentos,
split, etc.
Esta aplicación implementará y utilizará la librería de Utilidades definida en esta primera fase y
cuya descripción de la misma se encuentra en el capítulo 3.
Todas estas herramientas tienen en común que el código generado parte del uso de una base
de datos en concreto.
Como ya se comentó en el capítulo 4, la idea es que esta herramienta pueda usarse por varias
personas al mismo tiempo. Para llevar esto a cabo lo que se va hacer es, usar ficheros XML
guardados en una carpeta compartida a la cual puedan acceder varias personas (aplicaciones)
al mismo tiempo. Estos ficheros XML contendrán información necesaria para la aplicación.
Los ficheros XML utilizados en la aplicación son en realidad listas de objetos, de ciertos tipos de
clases definidos en la aplicación, serializados. Cuyo contenido se guardan en ficheros XML. De
esta manera no es necesario el uso de base de datos para guardar y recuperar la información
generada.
En los puntos sucesivos se mostrarán las pantallas que tendrá la aplicación y se explicará el
funcionamiento de las mismas.
71
6.1 Aplicación La herramienta se desarrollará como una aplicación de escritorio, entorno de Windows. Al
ejecutar la aplicación nos encontraremos la siguiente pantalla:
Figura 22: Diseño inicial aplicación
6.1.1 Menú
El menú de la aplicación consta de las siguientes opciones:
Proyecto, con las opciones de crear un nuevo proyecto, modificar uno ya existente, y
salir de la aplicación.
Crear con las siguientes opciones:
o Base de datos, consta de
Procedimientos.
Funciones.
Figura 23. Menú proyecto de la aplicación
Figura 24: Menú crear de la aplicación
72
6.2 Opción Proyecto
6.2.1 Nuevo proyecto
Cuando seleccionemos esta opción se mostrará la siguiente pantalla:
Los datos que se recojan de esta pantalla se guardarán en la tabla Proyecto y
ConfiguracionPersonalProyecto:
Nombre: es el nombre del proyecto.
Servidor: Nombre del servidor donde está alojada la base de datos.
Base de datos: Nombre de la base de datos.
Usuario: Es el nombre del usuario con el cual la aplicación deberá ser capaz de poder
consultar las tablas que tiene la base de datos.
Contraseña: Es la contraseña del usuario definido anteriormente.
Usuario grant: Es el nombre del usuario que tendrá permisos de ejecución sobre los
procedimientos almacenados.
Todos los datos son obligatorios salvo el usuario grant. Para poder guardar la configuración del
Proyecto primero se validará que los datos introducidos son correctos, para ello será necesario
pulsar el botón Probar conexión. Hasta que no se valide que es posible conectarse a la base de
datos indicada, no se habilitará el botón de Guardar. En caso de que la conexión no sea
correcta, se mostrará un aviso de error.
Los datos introducidos para este proyecto se guardarán en un fichero XML llamado
Proyectos.xml.
Figura 25: Formulario para crear un nuevo proyecto
73
6.2.2 Modificar proyecto
Al seleccionar esta opción se muestra una pantalla donde aparece un combo con todos los
proyectos creados anteriormente. El listado de proyectos se obtiene del fichero Proyectos.xml.
Figura 26: Formulario para modificar un proyecto.
Al seleccionar alguno de ellos, se cargarán todos los datos que existan para este proyecto en el
fichero XML.
Para poder guardar las modificaciones realizadas será necesario pulsar el botón probar
conexión para poder habilitar el botón de guardar.
74
6.2.3 Seleccionar proyecto
En esta opción se mostrará el listado de proyectos que existan en el fichero Proyectos.xml. Se
mostrará solo el nombre.
Figura 27: Formulario para seleccionar un proyecto.
Una vez se haya escogido uno de los proyectos se pulsará el botón Seleccionar. Al pulsar este
botón se iniciará un proceso mediante el cual se obtendrá información de todas las tablas y
campos de la base de datos, configurada en el proyecto. Para obtener esta información se
ejecutarán unas consultas sobre la base de datos.
De cada tabla se obtendrá el nombre del esquema al que pertenece la tabla y el nombre de la
tabla.
De cada uno de los campos se obtendrá la siguiente información:
- El nombre de la tabla a la cual pertenece para así poder relacionarlo con su
correspondiente tabla.
- El nombre del campo.
- El nombre del tipo de dato, por ejemplo, string, int, bit, etc.
- La longitud del campo si es de tipo texto.
- El número de dígitos enteros cuando el tipo de dato sea numérico.
- El número de dígitos decimales cuando el tipo de dato sea numérico.
- Si el campo admite o no nulos, es decir si es obligatorio.
- Si el campo forma parte de la primary key de la tabla.
- Si el campo es identity. El que un campo sea identity significa que cada vez que se
inserte un registro en esa tabla, este campo cogerá el valor máximo de la tabla y lo
incrementará en uno su valor.
Con la información obtenida se crearán objetos de tipo Tabla o Campo que almacenarán esta
información. Los objetos de tipo Tabla tendrán el listado de campos que pertenecen a la tabla.
75
Esta información recuperada al seleccionar un proyecto, no se guardará en ficheros XML, por
lo menos en esta primera fase, pero sí que se almacenará de forma temporal por la aplicación,
mientras ésta esté en funcionamiento.
6.3 Opción Crear
6.3.1 Base de datos
En esta opción del menú se podrán crear procedimientos almacenados o funciones sobre la
base de datos configurada en el proyecto escogido.
6.3.1.1 Crear procedimientos almacenados
La finalidad de esta pantalla es poder crear procedimientos almacenados de forma rápida
mediante la participación del usuario. Para ello se mostrará una pantalla con el siguiente
aspecto:
Figura 28: Formulario para crear procedimientos almacenados
Esta pantalla está compuesta por los siguientes elementos o controles:
- Una lista desplegable (comboBox) que contendrá todas las tablas de la base de datos
definida en el proyecto seleccionado.
- Una lista desplegable con las siguientes operaciones básicas:
Seleccionar todos: se trata de crear un procedimiento almacenado que devuelva todos
los registros de la tabla. Se devuelven todos los campos de la tabla.
76
Seleccionar por código: se trata de crear un procedimiento almacenado que devuelva
aquél registro que tenga por código (clave primaria) el código que se reciba como
parámetro de entrada. En caso de que la clave primaria esté compuesta por varios
campos, se recibirán como parámetros de entrada todos ellos. Se devuelven todos los
campos de la tabla.
Seleccionar activos: creará un procedimiento almacenado que devolverá todos los
registros que estén activos. Se devuelven todos los campos de la tabla.
Grabar nuevo: crea un procedimiento almacenado que permite agregar un nuevo
registro a la tabla seleccionada. Por defecto esta operación recibirá todos los campos
de la tabla como parámetro de entrada menos aquellos campos que formen parte de
la clave primaria y que además sean campos identity (auto numéricos), ya que será la
propia base de datos la encargada de dar valor a este campo. Se permitirá devolver el
código generado de forma automática.
Actualizar: crea un procedimiento almacenado que permite actualizar un registro en la
tabla. Se reciben como parámetros todos los campos de la tabla. Los campos que
forman parte de la clave primaria de la tabla formarán parte de la condición para
encontrar y actualizar el registro correspondiente, estos campos no estarán en la
sección set del procedimiento.
Baja lógica: crea un procedimiento almacenado que se encarga de modificar el estado
del registro. Para ello recibe como parámetro de entrada todos aquellos campos que
forman parte de la clave primaria de la tabla. Estos campos formarán parte de la
condición para encontrar el registro correspondiente.
Baja física: crea un procedimiento almacenado que se encarga de borrar un registro de
la tabla. Recibe como parámetros de entrada todos los campos que formen parte de la
clave primaria de la tabla.
- Una caja de texto que tendrá el nombre del procedimiento almacenado. Este nombre se
genera de forma automática siguiendo el siguiente formato.
NombreDelEsquema.NombreDeLaTabla_SufijoDelProcedimientoAlmacenado
Los sufijos a utilizar son:
Seleccionar todos: SEL_Todos
Seleccionar por código: SEL_Por_Codigo
Seleccionar activos: SEL_Activos
Grabar nuevo: INS
Actualizar: UPD
Baja lógica: UPD_Baja_Logica
Baja física: DEL
77
Se permitirá que el nombre del procedimiento almacenado sea modificado por el usuario.
- Una sección para configurar y personalizar los procedimientos almacenados. Estas secciones
se muestran en un control que utiliza pestañas, para facilitar la gestión de las mismas. Las
secciones de que dispondrá son las siguientes:
- Campos: En esta sección se permite agregar y quitar campos al procedimiento
almacenado. El comportamiento de esta sección según la operación escogida será el
siguiente:
o Operaciones de selección, variar el número de campos a devolver, por defecto
se devuelven todos.
o Grabar y actualizar: Variar el número de campos a grabar o actualizar en la
tabla escogida. No sólo afecta a la operación de insertar (INSERT INTO) o
actualizar (UPDATE), sino que además se reducirán o aumentarán los
parámetros de entrada del procedimiento almacenado.
o Baja lógica y física: Variar el número de parámetros de entrada del
procedimiento almacenado. Si se elimina el campo activo y el o los campos
que forman la clave primaria también se eliminará la condición por la cual se
busca un registro en concreto (WHERE).
Esta pestaña tiene la siguiente apariencia:
Figura 29: Pestaña de configuración de campos
En la lista de la izquierda aparecerán todos los campos que no estén agregados al
procedimiento almacenado y en la lista de la derecha los que sí. Para agregar o quitar
78
uno o varios campos, tan sólo hay que seleccionarlos y pulsar sobre los botones
agregar o quitar.
- Filtros: Se permite modificar los filtros o condiciones (WHERE) del procedimiento
almacenado. Cada campo que se agregue se agregará como parámetro de entrada,
siempre que no exista ya. Estos filtros se podrán aplicar a todas las operaciones salvo a
Grabar nuevo. La apariencia será la siguiente.
Figura 30: Pestaña de configuración de filtros
Para agregar un campo, tan sólo hay que seleccionarlo de la lista desplegable y darle al
botón agregar. El campo se agregará al listado inferior. Si en el filtro se quisiera usar la
comparación por LIKE, antes de pulsar sobre el botón agregar hay que marcar la casilla
"Utilizar LIKE en la comparación". Para este caso el campo agregado a la lista aparecerá
con el sufijo "- LIKE".
79
- Ordenar por: permite agregar campos para ordenar los resultados según los criterios
que se establezcan. Los campos agregados en esta opción se agregarán como
parámetros de entrada del procedimiento almacenado siempre que no haya sido
agregado anteriormente.
El aspecto de esta sección es la siguiente:
Figura 31: Pestaña de configuración del orden de los campos
Para agregar un nuevo filtro, se seleccionará un campo de la lista desplegable y se
pulsará el botón agregar. Por defecto el filtro aplicará un orden ascendente (es así en
SQL), pero para poder cambiar este orden lo que hay que hacer es marcar la casilla
"Descendente". Los campos se agregarán una lista, se indicará en cada uno de ellos el
tipo de orden, mediante los sufijos "- Descendente" y "- Ascendente".
Se podrá seleccionar uno o varios campos y eliminarlos de la lista, para ello se
seleccionarán los campos deseados y se pulsará el botón de "Quitar".
80
- Configuración: En esta pestaña se establecerá qué campo es el campo activo de la
tabla, necesario para las operaciones de Seleccionar activos y baja lógica.
También permitirá dar la opción de devolver el código auto numérico generado al
insertar un registro en una tabla, cuando disponga de un campo de este tipo.
La apariencia de la pestaña es la siguiente:
Figura 32: Pestaña configuración campo activo y código grabado
Para seleccionar el campo activo, se escogerá el campo de la lista desplegable. La
aplicación por defecto entenderá que el campo activo será de tipo bit y que para
devolver los registros activos la condición será @Campo = 1, pero en caso de que esto
no sea así, habrá que marcar la casilla "No es booleano" que activará la caja de texto
"Valor comparación", en la cual se introducirá el valor por el cual se entiende que un
campo está activo.
En la operación de Grabar nuevo, para devolver el código auto numérico, habrá que
marcar el check "Devolver código grabado". Esta opción agregará una consulta de
selección al procedimiento almacenado para recuperar el último código grabado. Al
código recuperado mediante una función de SQL se le asignará un alias, que será el
nombre del campo auto numérico.
81
- Script: En esta pestaña se mostrará a modo de vista previa el script del procedimiento
almacenado que se generará en la base con todos los criterios establecidos en las
pestañas anteriores. Por defecto se mostrará esta pestaña activa.
La apariencia de esta pestaña es la siguiente:
Figura 33: Pestaña vista previa script procedimiento almacenado
Esta pestaña dispone de dos cajas de texto. En la primera se muestra el script de
creación del procedimiento almacenado y en la segunda se muestra el script para dar
permisos de ejecución sobre el procedimiento almacenado al usuario grant
configurado en el proyecto. En caso de no haber especificado ninguno, no se mostrará
nada.
Una vez que se haya configurado todos los parámetros del procedimiento almacenado, para
poder crear éste en la base de datos, hay que pulsar el botón Crear. Antes de crear el
procedimiento en la base de datos la aplicación comprobará que no exista ya uno con el
mismo nombre y en el mismo esquema. En caso de que existe, se preguntará al usuario si
quiere modificarlo, en caso afirmativo se sustituirá el existente por el actual.
82
Figura 34: Aviso detectada existencia de procedimiento almacenado
Si el procedimiento almacenado se ha creado correctamente, se mostrará un aviso indicando
que se ha creado correctamente.
Figura 35: Aviso procedimiento almacenado creado
En el mismo proceso de creación del procedimiento almacenado se ejecutará la instrucción
GRANT, que es la que da permiso al usuario grant establecido sobre el procedimiento
almacenado creado.
La aplicación dispone de otro botón llamado "Copiar" cuya función es copiar el contenido de
ambas cajas al portapapeles. En ambas instrucciones se agregará la instrucción GO que
permite la ejecución de la instrucción, en el entorno de SQL.
El botón Limpiar resetea la pantalla, limpiando todas las configuraciones realizadas.
Gracias a todas las posibles variantes en la configuración del procedimiento almacenado,
partiendo de una operación básica, se pueden crear la mayoría de los procedimientos que
pueden llegar a usarse en una aplicación de desarrollo.
En esta primera fase queda fuera los procedimientos almacenados relativos a búsquedas de
datos.
83
6.3.1.2 Agregar funciones
Desde esta pantalla se pueden agregar funciones a la base de datos. Las funciones estarán
definidas en un fichero XML. No existirá un mantenimiento de estas funciones, si se quisiera
agregar nuevas funciones, están se agregarán directamente al fichero XML.
En base a este fichero se configura la siguiente pantalla:
Figura 36: Formulario para agregar funciones de SQL
En primer lugar aparece una lista desplegable con todos los nombres de las funciones. Al
seleccionar una de ellas se cargará el script de creación de la función en la caja de texto
posterior.
El botón Agregar, creará la función en la base de datos, pero se comprobará que no exista
anteriormente una función con el mismo nombre, en caso de existir se mostrará un mensaje
para indicar esta situación. No se permite la sustitución de la función existente por la actual. En
caso de que no exista, la función se creará en la base de datos y si se crea con éxito se
mostrará un mensaje.
El botón Copiar, copiará al portapapeles el script de creación de la función.
84
7. Fase II En la primera fase de la aplicación se desarrolló herramientas que recuperaban datos sobre la
composición de una base de datos, tablas, campos, tipos de datos de los campos, claves
primarias, foráneas, etc. Se desarrolló también una herramienta capaz de crear
procedimientos almacenados dada una tabla y una operación básica. Toda la información
recuperada de la base de datos y la configuración de los procedimientos almacenados creados
se almacena en ficheros XML para poder usar más adelante.
En esta segunda fase se utiliza toda esta información, para crear el modelo de datos, a partir
de la información de tablas y campos recuperados y para crear métodos de acceso a datos que
utilizan la configuración de los procedimientos almacenados creados. A continuación se
describen todas las novedades y mejoras que se han desarrollado en esta segunda fase.
Mejoras:
1. Modificación del menú de la aplicación.
2. Separación en varios ficheros XML la información/configuración de cada uno de los
proyectos.
3. Mejoras en el generador de procedimientos almacenados.
4. Se agregan nuevos campos en el alta/modificación de proyectos.
También se han corregido varios fallos detectados provenientes de la primera fase.
Novedades:
1. Al ejecutar la aplicación se abre el último proyecto con el que se estaba trabajando,
cuando se cerró la aplicación.
2. Detección de tablas agregadas, modificadas y borradas, detección de campos
agregados, modificados y borrados.
3. Generador del modelo de datos, esto es generar clases a partir de tablas y sus campos
de una base de datos.
4. Creación de clases y métodos para automatizar la lectura de datos provenientes de los
procedimientos almacenados (Se incluye en la librería Utilidades).
5. Generador de métodos de acceso a datos (DAL) a partir de los procedimientos
almacenados generados y de las clases y funciones desarrolladas en el punto cuatro.
85
7.1 Mejoras respecto a la fase primera A continuación se describen las mejoras desarrolladas con respecto a la primera fase de la
aplicación.
7.1.1 Modificación del menú de aplicación .
Con el fin de hacer más ágil la selección de las diferentes pantallas de la aplicación, el
elemento del menú anterior "Crear" desaparece, y se agregan dos nuevos elementos:
Bases de datos, con las opciones:
o Procedimientos. Accede al generador de procedimientos almacenados.
o Funciones. Accede al generador de funciones de SQL.
Modelo datos, con las opciones:
o Entidades. Accede al generador de clases (NUEVO)
o Acceso a datos. Accede al generador de métodos de acceso a datos (NUEVO)
El menú queda de la siguiente manera:
7.1.2 Separación en varios ficheros XML la información relativa a los proyectos.
En la fase anterior se guardaba en un único fichero llamado "Proyectos.xml" toda la
información que se obtenía de la base de datos, tablas, campos, tipos de de datos de los
campos, etc. y toda la información que se generaba con la herramienta de generación de
procedimientos almacenados, y todo esto por cada uno de los proyectos con los que se
trabajaba.
Para evitar que el fichero pudiera crecer muy rápido en el número de líneas (hablamos de
varios miles de líneas por cada proyecto agregado) se decide separar en varios ficheros.
La organización de los ficheros XML queda de la siguiente manera:
- En el fichero Proyectos.xml se guarda la configuración básica de cada proyecto,
prácticamente es la información que se recoge al crear un nuevo proyecto, más algunos datos
internos.
- Por cada proyecto se crea un fichero XML. El nombre de este fichero es la unión del nombre
que se le haya dado al proyecto junto con el sufijo "_información.xml".
Figura 37: Nueva configuración del menú de la aplicación
86
7.1.3 Mejoras en el generador de procedimientos almacenados.
En el generador de procedimientos alamacenados se han llevado a cabo las siguientes
mejoras:
Se habilita la pestaña de configuración de filtros para todas las operaciones.
Se modifica la pestaña de configuración relativa a las operaciones de selección de
registros activos y bajas lógicas. Se elimina el check para indicar si el campo es o no
booleano y se agregan dos cajas de texto para indicar cuál es el valor activo y otra para
indicar el valor en la función ISNULL que se aplica sobre el campo.
Al seleccionar un campo, para marcarlo como el campo que determina si un registro
está activo o no, según el tipo de dato que tenga en la base de datos, se establecen
por defecto una serie de valores, quedando de la siguiente forma:
Figura 38: Mejoras en la configuración de campo activo
En la vista previa del procedimiento almacenado al aplicar estas mejoras se consigue lo
siguiente:
En la pestaña de configuración se agrega un nuevo check, para decidir si se quiere utilizar
el modelo de datos. Esta funcionalidad se explica más adelante.
Figura 40: Check para utilizar el modelo de datos
Figura 39: Vista previa procedimiento almacenado
87
7.1.4 Nuevos campos en el alta y modificación de proyectos
En la pantalla para la creación y modificación de la configuración de un proyecto, se ha
agregado dos nuevos campos:
Namespace (o espacio de nombres): Se establece el espacio de nombres que se
utilizará más adelante en la creación de clases del modelo de datos.
Version de la librería Utilidades: Permite establecer la versión de la librería Utilidades
que se va a utilizar en el proyecto, permitiendo elegir entre la versión 1.5 que es la que
actualmente se utiliza o entre la versión 2.0 que es la que se desarrolla con la
aplicación y que es una evolución importante de la 1.5.
Dependiendo de la versión de librería escogida, se generará diferente código en las
herramientas de creación del modelo de datos y funciones de acceso a datos.
La librería de Utilidades se ha evolucionado y modernizado en este proyecto, puesto
que en la versión 1.5 se utilizaba la sobrecarga de métodos o muchas funciones con
nombres similares para realizar tareas similares, como por ejemplo recuperar valores
de DataReaders. Pero en esta nueva versión se ha optado por el uso de funciones
genéricas, de forma que, según el tipo de dato recibido es la propia y única función
que decide qué hacer en cada caso.
La pantalla de modificación y selección de proyecto queda de la siguiente manera:
Figura 41: Formulario modificar proyecto
88
7.2 Nuevas funcionalidades A continuación se describen las nuevas funcionalidades y herramientas desarrolladas.
7.2.1 Abrir el último proyecto con el cual se estaba trabajando
Cuando se está desarrollando un proyecto, lo normal es estar trabajando en él varios meses
seguidos, por tanto lo más probable cuando se ejecute esta aplicación sea querer seguir
trabajando con el mismo proyecto. Para evitar tener que elegir un proyecto concreto cada vez
que se ejecuta la aplicación, se agrega esta nueva funcionalidad.
Para llevar a cabo esta nueva funcionalidad, en el fichero de Proyectos.xml se guarda por cada
proyecto, la fecha en que se seleccionó éste por última vez. Y al abrir la aplicación se escoge el
proyecto que tenga la fecha de selección más alta.
7.2.2 Detección de tablas y campos agregados, modificados y eliminados.
Cuando se crea un nuevo proyecto la aplicación internamente lanza consultas contra la base
de datos del proyecto para obtener la información de tablas, campos, tipos de datos de
campos, claves primarias y claves foráneas. Esta información obtenida se guarda en el
correspondiente fichero XML, para luego poder usarla en las distintas herramientas de la
aplicación sin tener que estar continuamente leyendo está información en la base de datos.
Además a partir de esta información se generará el modelo de datos y posteriormente los
métodos de acceso a datos.
Puesto que toda base de datos a lo largo de su desarrollo sufre cambios, es necesario la
creación de una función que sea capaz de reconocer y recoger esos cambios que se han
producido en la base de datos. Esta función ha de ser capaz de conservar las decisiones que se
tomaron al crear el modelo de datos (se explica su funcionamiento más adelante)
Este proceso se ejecutará cuando se seleccione un proyecto y al arrancar la aplicación, siempre
que no sea la primera vez que se ejecuta la aplicación, es decir siempre que ya se haya
trabajado anteriormente y por tanto se pueda abrir el último proyecto con el cual se estaba
trabajando.
Tanto si se detectan que se han agregado y/o borrado tablas y campos, se mostrará un
mensaje indicando el número de campos y tablas que han sido agregados y/o borrados.
Figura 42: Cambios detectados al abrir proyecto. Tablas
89
La modificación de un campo es más complicada. Si se modifica el nombre del campo, la
aplicación no es capaz de determinar que el campo ha sido modificado, en su lugar detecta
que se ha eliminado un campo de la tabla y que se ha agregado otro. Sin embargo si se
modifica cualquier otra propiedad del campo, la aplicación
sí es capaz de determinar que se ha modificado el campo.
La detección de estos cambios en la base de datos es muy importante a la hora de generar el
modelo de datos y las funciones de acceso a datos.
Cada vez que se detecte que se ha producido un cambio en la base de datos será necesario
reajustar el modelo de datos, para agregar, quitar o modificar clases o propiedades de las
clases.
7.2.3 Generador de modelos de datos
En todos los proyectos que se desarrollan se dedica una parte importante de tiempo a la
generación del modelo de datos a partir de las tablas de la base de datos. Con este modelo de
datos se construyen todas los accesos a datos, lógica de negocio y presentación de los datos al
usuario. La generación de estas clases a partir de las tablas de la base de datos, es un proceso
repetitivo y mecánico, puesto que siempre se siguen las mismas reglas. Es por ello que se ha
decidido desarrollar esta herramienta.
Para poder utilizar esta herramienta hay que seleccionar en el menú de la aplicación la opción
de "Modelo datos" y dentro la opción "Entidades". Una vez seleccionada esta opción se
cargará la pantalla con la cual se podrá generar el modelo de datos. Esta pantalla está dividida
en tres pestañas:
Configuración general.
Configuración de clases.
Generar clases.
En las dos primeras pestañas se configuran una serie de opciones a partir de las cuales se
generará el código del modelo de datos. La tercera pestaña permite escoger la o las clases del
modelo de datos que se quieren generar.
Cuando todavía no se ha generado el modelo de datos se muestra activa la pestaña de
Configuración general, pero cuando ya se haya generado, será la pestaña de Configuración de
clases la que esté activa.
Figura 43: Cambios detectados al abrir un proyecto. Campos
90
7.2.3.1 Configuración general
La pestaña de configuración general presenta el siguiente aspecto:
Figura 44: Configuración general en la creación del modelo de datos
Opciones para calcular clases
En la parte superior se permite configurar tres opciones que se tendrán en cuenta a la hora de
generar el modelo de datos. Estas opciones son:
- Detectar y quitar prefijos de tablas: En muchas bases de datos, sobre todo en
las antiguas, todas las tablas tienen una o varias letras a modo de prefijo. Un
prefijo muy utilizado es y ha sido la letra T. Si se marca esta casilla la
herramienta busca cuál o cuáles son estas letras para ignorarlas.
- Detectar y quitar prefijos de campos: Al igual que ocurre con las tablas, en
muchas ocasiones los campos tiene una o varias letras a modo de prefijo. Este
prefijo suele variar en función del nombre de la tabla. Si marcamos esta casilla
la herramienta detectará estas letras de prefijo y las ignorará.
- Definir foreign keys como clases: Si se marca esta opción cuando se genere el
modelo de datos, todos los campos de las tablas que sean claves foráneas se
convertirán en propiedades cuyo tipo de datos no es el correspondiente al de
la tabla, sino la clase que se genere a partir de la tabla con la que está
relacionada.
Por ejemplo, si tenemos las tablas TEmpleado y TDepartamento y la tabla
TEmpleado tiene un campo llamado Empleado de tipo entero que es clave
foránea con la tabla TDepartamento, tendremos que la propiedad
91
Departamento de la clase Empleado será de tipo Departamento si esta opción
está marcada y de tipo entero si no.
Por defecto, las tres opciones están marcadas. Las dos primeras hacen más limpios los
nombres de las clases y campos y la última opción es muy utilizada si se trabaja en una
programación orientada a objetos, que es la mayoría de los casos.
Una vez configuradas las opciones para calcular las clases basta con pulsar el botón "Calcular",
para que la herramienta en base a las opciones establecidas calcule las clases y campos y los
tipos de datos de los campos.
La conversión del tipo de dato de un campo de una tabla (SQL) al tipo de dato de una
propiedad (C#) se realiza siempre de la misma manera. No obstante, es posible modificar el
tipo de dato en la pestaña de configuración de clases que se explica más adelante.
Opciones para generar clases
Después de las opciones para calcular las clases, se encuentran las opciones de configuración
para generar las clases de forma física, es decir, para generar los ficheros con extensión .cs
relativos al código del lenguaje C#.
Estas opciones son:
- Agregar/Quitar imports: Todas las clases agregan por defecto referencias a
librerías, lo que se trata con esta opción es poder escoger qué librerías se van
a agregar en la clase que se va a generar. Por defecto se cargan una serie de
librerías, pero se pueden agregar más seleccionándolas del combo o
escribiéndolas en la lista desplegable y agregándolas mediante el botón
"Agregar". Se pueden quitar las librerías de una en una o seleccionado varias a
la vez y luego pulsar el botón "Quitar".
- Namespace: Esta caja de texto se rellena con lo que se haya introducido en la
configuración del proyecto. Pero es posible modificarlo, o incluso agregarlo, en
caso de que no se hubiera configurado anteriormente. El valor de este control
se utilizará cómo espacio de nombres de la clase que se genere.
- Ruta: Al pulsar sobre el botón "Escoger" aparecerá una pantalla que nos
permitirá escoger el directorio sobre el cual se generarán los ficheros de las
clases.
Si se marca la casilla "Sobrescribir" y al generar las clases se detecta que ya
existe un fichero con el mismo nombre, el archivo existente se sobrescribirá,
en caso contrario no sufrirá cambio alguno.
En la opción de configuración Ruta se ha hablado del nombre de las clases y de la posibilidad o
no de sobrescribir ficheros existentes. Pero no se ha descrito cómo se van a nombrar estos
ficheros. La forma en que se va a dar nombre a las clases será la siguiente:
NombreDeLaClase.cs. El nombre de la clase se ve influenciado por la opción escogida en
"Detectar y quitar prefijos de tablas". No obstante en la segunda pestaña de configuración,
Configuración de clases, es posible modificar el nombre de la clase.
92
7.2.3.2 Configuración de clases
La pestaña de configuración de clases presenta el siguiente aspecto:
En la parte superior de la pantalla se muestran los siguientes elementos:
- por un lado, el prefijo de las tablas que se ha detectado al calcular las clases,
siempre que se haya marcado en la pestaña anterior la casilla de detectar los
prefijos de las tablas.
- Después hay una lista desplegable donde aparece cada una de las tablas que
hay en la base de datos.
- Posteriormente se muestra el nombre de la clase que se ha calculado en
función del nombre de la tabla y el prefijo de la tabla. Es posible modificar el
nombre de la clase.
- Un check para incluir la función de crear entidad. Esta función crea una lista de
objetos de la clase actual en base a los datos recogidos en un objeto de tipo
DataReader, que se usa para leer los datos de la tabla. Se explica en el punto
7.2.4. En función de la versión de la librería Utilidades escogida llamará a unas
u otras funciones.
- Por último el prefijo de los campos que se ha detectado al calcular las clases,
siempre que se haya marcado en la pestaña anterior la opción de detectar y
quitar los prefijos de los campos. Es posible modificar el valor del prefijo, por si
este pudiera estar incorrecto o incompleto. Al modificar el valor del prefijo
automáticamente se modificarán los nombres de los campos de la clase.
Al seleccionar una de las tablas en la lista desplegable, automáticamente se completarán los
campos nombre de la clase, prefijo de campos y se mostrará en la parte posterior de la
pantalla, en la rejilla, la lista de campos que contiene la tabla. La rejilla dispone de una serie de
columnas donde se muestra información relativa al campo de la tabla e información relativa a
la propiedad que se crea a partir de ese campo. Las columnas son:
- Campo: es el nombre del campo en la tabla. No se puede modificar.
- Tipo campo: es el tipo de dato que tiene el campo en la tabla. No se puede
modificar.
Figura 45: Configuración de clases
93
- Propiedad: es el nombre de la propiedad que se calcula a partir del nombre del
campo y del prefijo que se ha detectado o configurado. Es posible modificar
este valor.
- Activo: Al marcar esta casilla indicaremos que el campo actual es el que
diferencia si un registro está o no activo. Sólo se puede marcar como activo
uno de los campos. Si un campo está marcado como activo y marcamos otro
como activo, el primero dejará de estarlo. El hecho de marcar el campo como
activo hace que cuando se vaya a generar procedimientos almacenados
relativos a las operaciones básicas de "Seleccionar activos" o "Baja lógica", en
la sección de configuración del generador de procedimientos
automáticamente se marcará este campo como campo activo. En la fase
anterior era necesario escoger cuál de los campos de la tabla era el que
indicaba que el registro estaba activo o no.
-
Tipo básico: es la conversión del tipo de dato de la base de datos al tipo de
dato que le corresponde en el lenguaje de programación C#. Pese a que las
conversiones entre tipos son algo conocido y constante, se permite modificar
el tipo de dato.
- Tipo clase: cuando el campo tiene una clave foránea con otra tabla y se ha
marcado en la configuración del cálculo de clases la casilla "Definir foreign keys
como clases", esta casilla contiene el nombre de la clase correspondiente a la
tabla con la que está relacionada. Si se hace doble clic sobre este campo la
pantalla se recargará y mostrará la información relativa a esta tabla, como si
hubiéramos escogido la tabla relacionada en la lista desplegable.
Figura 46: Listado de propiedades de una clase
Figura 47: Configuración procedimientos almacenados. Usar modelo de datos
94
- Propiedad clase: el valor de esta casilla está relacionada con la casilla
anterior, si en la anterior se mostraba el nombre de la clase correspondiente a
la tabla con la que está relacionado el campo, en esta casilla se muestra el
nombre de la propiedad correspondiente al campo de la tabla con la cual tiene
la relación. No es posible modificar su valor.
Una vez que se ha explicado el significado de todas las columnas, falta por comentar que al
modificar el nombre de la columna Propiedad, automáticamente se modificará el valor de la
columna Propiedad clase, en todos aquellos campos que tenga una clave foránea con la tabla a
la que representa esta clase. Esto se explica a continuación de forma gráfica:
1. La tabla TUsuarios tiene un campo en la base de datos llamado UPerfil que tiene una clave
foránea con la tabla TPerfiles y el campo PerCodigo.
2. Modificamos en la clase Perfiles correspondiente a la tabla TPerfiles la propiedad del campo
PerCodigo y lo llamamos Codigo2.
3. Al regresar a la tabla TUsuarios el valor de la Propiedad clase ya no es Codigo, sino Codigo2
Esto que se ha explicado para el nombre de la propiedad, funciona de igual manera con el
nombre de la clase. Al modificar el nombre de la clase automáticamente modificará el valor de
la columna Tipo clase de todas las claves foráneas que tengan relación con la tabla a la que
representa esta clase.
Figura 48: Modificación del nombre de una propiedad que es clave foránea. Paso 1
Figura 49: Modificación del nombre de una propiedad que es clave foránea. Paso 2
Figura 50: Modificación del nombre de una propiedad que es clave foránea. Paso 3
95
7.2.3.3 Generar clases
Esta pestaña tiene la siguiente apariencia:
En la parte de la izquierda hay una lista con checks que contiene todas las clases que existen
en el proyecto actual. Aparece seleccionada la clase con la que se está trabajando. Al lado de
esta lista hay tres botones que facilitan el marcar o desmarcar los checks de la lista.
En la parte de la derecha aparece la vista previa de la clase seleccionada, en ella se tienen en
cuenta todas las opciones que se han seleccionado en las pestañas anteriores de
configuración.
En la parte inferior derecha hay dos botones:
- Copiar: Copia todo el contenido de la vista previa en el portapapeles. Al
realizar esta acción el color de la letra pasa de negra a azul.
- Generar clases: Este botón sólo estará habilitado si se ha escogido una ruta en
la pestaña de configuración general. Si está habilitado y se pulsa el botón, se
generarán tantos archivos como clases hayan
sido marcadas en la lista de la derecha. Al
finalizar la creación de los archivos se mostrará
un mensaje, indicando si se han generado o no
las clases.
Figura 51: Vista previa generación de clases
Figura 52: Aviso generación de clases
96
7.2.4 Creación de clases y métodos para automatizar la lectura de datos
provenientes de los procedimientos almacenados
En todos los proyectos de desarrollo de aplicaciones se obtienen datos de la base de datos
mediante el uso de procedimientos almacenados, ya que este sistema es más rápido y más
seguro que las consultas dinámicas.
En los proyectos desarrollados la lectura de estos datos ha ido evolucionando muy lentamente.
Al principio, o por lo menos cuando yo empecé, los datos se recuperaban en objetos llamados
DataSets, que venía a ser un conjunto variable de tablas (DataTables) que a su vez contenían
filas (DataRows). Para poder acceder a ellos era necesario especificar la tabla a la que se quería
acceder, el número de fila dentro de la tabla y la columna de la fila. De estos objetos DataSets
se ha pasado en la actualidad a usar otro objeto llamado DataReader. La ventaja del
DataReader frente al DataSet es que utiliza menor cantidad de memoria, aunque es cierto que
los DataReader no son objetos serializables. De todas formas para el uso que se le da a ambos
objetos, el hecho de que sean o no serializables es irrelevante.
Tanto si se usan objetos de tipo DataSet o DataReader, en ambos casos lo que se obtiene es
una serie de registros de las tablas y a partir de estos registros se inicia un proceso de
conversión de datos por el cual estos registros se convierten en entidades. Para este proceso
de conversión es necesario leer campo a campo e ir asociando el valor obtenido a una
propiedad de la entidad que se está creando. Para ello, en los proyectos actuales lo que se
hace es generar una línea de código por cada campo de la tabla, para después asociarlo a una
propiedad de la clase. Estas líneas de códigos se apilan en una función llamada "crearEntidad".
Esta función tiene las siguientes características:
- Se crea una función por clase y se agrega en el fichero que contiene la
definición de la clase.
- Devuelve una lista de entidades que son del tipo de la clase actual.
- Recibe como parámetro de entrada un objeto DataReader con los registros
obtenidos de la base de datos.
- Intenta asignar valor a cada una de las propiedades de la clase, siempre que
cada una de las propiedades se correspondan a un campo de la tabla. Se
suelen agregar propiedades a la clase para saber el estado del registro, por
ejemplo, si es un alta, modificación o baja u otras finalidades.
- Para intentar asignar el valor a la propiedad de la clase utiliza funciones de la
librería utilidades (UtilesDataReader), que comprueban si existe el campo en el
registro actual y si éste existe intenta asignar el valor a lo propiedad de la
clase. En función del tipo de dato usará funciones diferentes. Este último paso
sólo es cierto si el proyecto utiliza la versión 1.5 de la librería utilidades, puesto
que en la versión 2.0 se ha creado una única función que comprueba el tipo de
dato que recibe y en función de él llamará a la función que le corresponda.
La creación de esta función se ha automatizado en esta segunda fase, mediante la selección
del check "Crear entidad", dentro de la herramienta de creación de clases.
97
Pese a haber mejorado y automatizado la creación de esta función, he creído necesario
intentar evolucionar la lectura de estos datos, para intentar reducir la gran cantidad de líneas
de código que se generan para leer los datos de la base de datos.
Para ello he investigado el objeto DataReader, para descubrir qué información se obtiene al
recuperar información de la base de datos, mediante la ejecución de procedimientos
almacenados. Como resultado de esta investigación he creado una nueva clase en la librería de
Utilidades llamada UtilesEntidad y he mejorado la herramienta que genera los procedimientos
almacenados que se desarrolló en la fase primera de este proyecto, para que se adaptara a
esta nueva forma de leer los datos.
Esta nueva clase, que se encuentra dentro de la librería de Utilidades, tiene una única función
pública, que es la siguiente:
public List<T> CrearEntidades<T>(IDataReader datos)
Básicamente, esta función es prácticamente igual a la función explicada anteriormente llamada
CrearEntidad. Puesto que devuelve una lista de entidades de cierto tipo y recibe un único
parámetro de entrada que es un objeto de tipo DataReader.
La diferencia está en que está función es un método genérico y puede recibir cualquier tipo de
objeto. Devuelve y recibe el mismo tipo de dato, esto es posible gracias al tipo genérico T. Los
tipos genéricos se incluyen por primera vez en el framework 2.0 de .NET, por lo tanto, para
poder usar esta función, será necesario que el proyecto utilice una versión igual o superior a la
2.0. No obstante, todos los proyectos que se inician hoy en día, parten cómo mínimo de la
versión 3.5 (actualmente la máxima posible es la 4.0) por lo que no es un problema en
proyectos nuevos.
Lo primero que hace esta función, tras recibir la información de registros de tablas dentro del
objeto datos de tipo DataReader, es obtener información de cada uno de los campos de que
consta el DataReader recibido. Por cada campo se obtiene la siguiente información:
- Nombre del campo: El nombre del campo se corresponde con el nombre que
se le haya dado al campo dentro del procedimiento almacenado. Por lo que si
al campo se le da un alias, el nombre del campo será el alias que se le haya
puesto. Resalto lo del alias puesto que lo usaré más adelante para establecer
valor a aquellos campos de la entidad que son claves foráneas y han sido
definidas como clases en vez de usar tipos de datos comunes, como son
cadenas de texto, números, fechas, etc.
- Tipo de dato que tiene el campo en la tabla de la base de datos. Enfatizar en
este caso que es el tipo de dato que tiene en la tabla y no el tipo de dato que
tiene en la clase.
Toda esta información es almacenada para poder usarla más adelante.
98
Tras recuperar la información relativa a los campos que se ha recibido del DataReader, se
instancia una lista de entidades del tipo recibido.
Mediante un bucle se recorre cada uno de los registros del DataReader. En cada bucle se
instancia una entidad del tipo recibido y se recorre la lista de campos que se ha guardado
anteriormente (que contiene el nombre y el tipo de dato de cada uno de los campos del
DataReader). Con el nombre del campo y el registro del DataReader se obtiene el valor de
campo para ese registro.
Con la entidad instanciada, el nombre del campo, su valor y su tipo se llama a una función que
recibe toda esta información y tratará de asignar el valor del campo a la propiedad de la clase
que corresponda. Llegados a este punto nos encontramos con un problema, que es, ¿Cómo
saber a qué propiedad le corresponde el valor de este campo? Para solucionar este problema,
se ha modificado el generador de procedimientos almacenados, de forma que a cada campo
que se va a recuperar, es decir en las operaciones básicas de selección de datos, se le pone
como alias el nombre de la propiedad que le corresponde, siempre y cuando el nombre del
campo y el de la propiedad sean diferentes. Claro está que, para que esto sea posible, es
necesario que se haya calculado primero el modelo de datos. Para utilizar esta opción hay que
activar una casilla que se ha agregado en la configuración del generador de procedimientos
almacenados. Se muestra una imagen a continuación de esta casilla.
Como resultado de activar esta casilla se generaría un procedimiento similar a:
SELECT Campo1 [Propiedad1], Campo2 [Propiedad2] ...
From Tabla
Al poner estos alias a los campos es posible relacionar los campos y propiedades y así poder
asignar a la propiedad de la entidad el valor del campo. Pero esto sólo funciona cuando las
propiedades de la entidad son de tipos básicos, no cuando el tipo de la propiedad es otra clase.
En el ejemplo que vamos siguiendo, la clase Usuarios tiene una propiedad llamada Perfil que
es de tipo Perfiles. Cuando se recuperan los registros de la tabla TUsuarios lo que se está
obteniendo del perfil es el código del perfil y de alguna manera hay que recoger este valor y
asignarlo a la Propiedad Código de la clase Perfiles. Para poder llevar a cabo esto, lo que se ha
hecho es asignarle un alias al campo, algo similar a lo anterior, pero esta vez el alias estará
construido de la siguiente manera: primero el nombre de la propiedad de la clase "principal"
Figura 53. Casilla utilizar modelo de datos en generación de procedimientos almacenados
99
(en el ejemplo es Perfil) y después, separado por un punto, el nombre de la propiedad de la
clase a la que pertenece la propiedad anterior (en el ejemplo Codigo)
De esta manera el procedimiento almacenado que obtiene los datos de la tabla TUsuarios y
que usa esta función para leer los datos, queda de la siguiente manera:
Figura 54: Vista previa generación procedimientos utilizando el modelo de datos
De esta manera ya se pueden leer todos los datos de los campos de las tablas y asociarlos con
sus respectivas propiedades en la clase.
No obstante, queda un elemento más a tener en cuenta para asignar el valor recibido a la
propiedad correspondiente, que es ¿qué sucede si el tipo de dato del campo no se
corresponde con el mismo tipo de dato que el de la propiedad a la cual le corresponde recibir
el valor? Esto se podría dar si por ejemplo, tenemos un campo en la base de datos que es de
tipo cadena y que almacena dos valores, como podrían ser Si y No, True y False, etc. y el tipo
de dato que tiene la propiedad fuera de tipo booleano.
Esto que se comenta, sucede en aplicaciones viejas donde no se utilizaban correctamente los
tipos de datos, puesto que en el ejemplo comentado, lo más correcto hubiera sido tener un
campo de tipo bit (booleano) y así se hace en las nuevas aplicaciones. Para poder hacer estas
conversiones de tipos se ha creado una clase llamada AtributoCampo que extiende de la clase
Attribute y permite asignar ciertos atributos a las propiedades de las clases. Se han creado
dos atributos posibles a agregar en el caso de que el tipo de dato de la propiedad sea de tipo
booleano, pero el tipo de dato del campo que proviene de la tabla no lo sea:
ValorTrueInt: En el caso de que el tipo de dato del campo sea de tipo numérico,
mediante el uso de esta propiedad se establece qué valor se corresponde con el valor
verdadero.
ValorTrueString: En el caso de que el tipo de dato del campo sea de tipo cadena de
texto, mediante el uso de esta propiedad se establece qué valor se corresponde con el
valor verdadero.
No se han definido más posibles casos, puesto que estas excepciones no deberían darse, ya
que las conversiones entre los tipos de datos de la base de datos y los tipos de datos del
lenguaje C# deberían realizarse correctamente.
100
7.2.5 Generador de métodos de acceso a datos (Data Access Layer)
Una vez que se ha definido el modelo de datos y se han generado procedimientos
almacenados, es hora de crear métodos que puedan llevar a cabo las acciones de éstos
últimos. Para ello se ha generado una herramienta, que en base a un procedimiento
almacenado es capaz de realizar la acción del mismo.
La herramienta desarrollada tiene el siguiente aspecto:
La herramienta está dividida en una parte superior donde tenemos:
Una lista desplegable que contiene todas las clases sobre las cuales se pueden crear
métodos de acceso a datos. Esto es, clases sobre cuyas correspondientes tablas se han
generado uno o varios procedimientos almacenados. Al seleccionar uno de los
elementos de la clase se cargará la segunda lista desplegable.
La segunda lista desplegable contiene la lista de procedimientos almacenados que se
han generado para la tabla correspondiente de la clase seleccionada.
La parte inferior se ha dividido en dos pestañas, en la primera se puede configurar una serie de
parámetros para generar el método y en la segunda pestaña se muestra la vista previa del
método. Los parámetros que se pueden establecer en la primera pestaña dependen de la
operación que realiza el procedimiento almacenado. Los parámetros que se pueden configurar
son:
Acceso del método, hay que escoger una de estas opciones: public, protected o
private.
Tipo de dato devuelto, determina lo que va a devolver el método de acceso a datos.
Las opciones posibles son: Una lista de entidades del tipo de clase escogida, una
entidad de la clase escogida, un valor booleano, el código que se ha insertado o el
número de registros que se han visto afectados tras ejecutar el procedimiento
almacenado. Según la operación que realiza el procedimiento almacenado estarán
Figura 55. Configuración del método de acceso a datos
101
habilitadas más o menos opciones. A continuación se muestra una relación entre el
tipo de operación del procedimiento almacenado y las opciones que están activas.
Lista<Clase> Clase Booleano Código Nº registros
Seleccionar todos X
Seleccionar por código X X
Seleccionar activos X
Grabar nuevo X X X
Actualizar X X
Baja lógica X X
Baja física X X
Tabla 9: Tipos de operación y opciones activas en generación de métodos de acceso a datos
Nombre del método: Según qué operación realice el procedimiento almacenado
escogido, la herramienta propone un nombre, no obstante es posible modificar este
valor.
Recibe la conexión, se refiere a si recibe o no como parámetro de entrada del método
el objeto que tiene establecida la conexión con la base de datos. Los casos en que se
recibe la conexión en general son porque realizan transacciones y además de tener la
conexión con la base de datos contiene la transacción.
try /catch/finally, con esta opción se determina si el método implementará el control
de errores o no. En general todos los métodos de acceso tendrán activada esta
opción, pero en los casos en los que se estén llevando a cabo operaciones en los que
se requiera grabar, modificar y/o borrar registros en varias tablas o varios registros en
la misma y en consecuencia sea necesario realizar transacciones, lo más común es que
sólo el método inicial sea el que tenga definida el control de errores y el resto no.
¿Con transacción?, esta opción determina si el proceso de ejecutar el procedimiento
almacenado se realizará o no con transacción.
En función de todos estos parámetros la herramienta es capaz de generar el código necesario
para ejecutar el procedimiento almacenado y devolver el dato que se le ha marcado que
devuelva.
También se tiene en cuenta la versión de la librería Utilidades seleccionada en la configuración
del proyecto a la hora de utilizar unas u otras funciones. Estas funciones son utilizadas a la
hora de establecer los valores de los parámetros de los procedimientos almacenados. Los
valores de los parámetros se toman de las propiedades de la propia clase.
Comentar por último que este generador, por lo menos en la fase actual, sólo genera los
métodos y no clases donde dentro están los métodos. Estas clases que se han de generar para
luego agregar estos métodos, deben heredar de una clase llamada BaseDAL, que se ha creado
102
y definido y que contiene una serie de métodos que facilitan el cierre de las conexiones y
liberación de recursos utilizados.
La pestaña de vista previa tiene un botón Copiar que permite copiar todo el contenido de la
vista previa en el portapapeles y así agilizar el proceso de generación del método. Al pulsar
este botón todo el contenido de la vista previa cambiará a color azul.
8. Fase III En la primera fase de la aplicación se desarrollaron herramientas que recuperaban datos sobre
la composición de una base de datos, tablas, campos, tipos de datos de los campos, claves
primarias, foráneas, etc. En la segunda fase se desarrollaron herramientas para generar el
modelo de datos y los métodos de acceso a datos.
En esta tercera fase, se han realizado mejoras en la herramientas de generación de
procedimientos almacenados y en la herramienta de generación de métodos de acceso a
datos. Además se han desarrollado controles web que permiten la automatización del proceso
de validación de datos que contienen.
Mejoras:
En la herramienta de generación de procedimientos almacenados, se ha agregado un
botón que permite un acceso rápido para generar su método de acceso a datos.
En la herramienta de generación de métodos de acceso a datos, se agrega la
posibilidad de generar las clases DAL.
Novedades:
Se ha desarrollado una librería llamada ControlesValidacion, que contiene controles para
aplicaciones web, que agregan funcionalidad a controles web ya existentes. Los controles a
los que se ha agregado estas funcionalidades son:
o TextBox: Son las cajas de texto, es el control más extendido. Dependiendo del dato
que vaya a contener se realizarán diferentes validaciones.
o DropDownList: Son las listas desplegables o combos, es el segundo control más
utilizado.
o CheckBoxList: Este control se representa como una lista que contiene una sucesión
de checks seguido de un literal. El uso de este control es inferior a los anteriores.
En esta primera versión de la librería no se han incluido otros controles como pueden ser:
- RadioButtonList: Este control es parecido al CheckBoxList, pero en vez de usar
un control check, usa el control radio. Al revisar varias aplicaciones que he
desarrollado este control apenas ha aparecido en un par de ocasiones, motivo
por el cual no lo he incluido.
- FileUpload: Este control permite subir ficheros desde el equipo del cliente al
servidor, para más tarde grabarlo en una base de datos. No he incluido este
control porque para poder realizar esta "subida" es necesario la ejecución de
algún evento cuando el usuario ha agregado el archivo. Además la información
103
del fichero, subido no permanece en el control de manera indefinida, como
ocurre con el resto de controles, sino que se realiza la captura de estos datos
en el instante que se agrega el fichero o se pierden.
8.1 Mejoras respecto a la segunda fase A continuación se describen las mejoras desarrolladas con respecto a la segunda fase de la
aplicación.
8.1.1 Modificación de la herramienta de generación de procedimientos almacenados
Con el fin de hacer más rápido el proceso de generar un procedimiento almacenado y después
crear el método de acceso a datos para el procedimiento creado, se ha incluido un botón, con
nombre DAL en la herramienta, que permite acceder directamente a la herramienta de
generación de métodos de acceso para el procedimiento creado.
El botón permanecerá desactivado hasta que se cree el procedimiento almacenado. No
obstante aún cuando se haya creado el procedimiento almacenado, si para el proyecto actual
no se ha generado el modelo de datos, el botón no se activará.
Si el modelo de datos se ha generado y se ha creado el procedimiento correctamente, el botón
se activará y al pulsarlo nos abrirá la herramienta de generación de métodos de acceso a
datos, donde automáticamente se seleccionará la clase donde se va a incluir el método de
acceso y se seleccionará el procedimiento almacenado generado en la herramienta anterior.
8.1.2 Mejora de la herramienta de generación de métodos de acceso.
La herramienta de generación de métodos de acceso ha sido mejorada en varios aspectos:
6. Se incluye una nueva pestaña que permite la configuración de las clases que se
generarán y contendrán los métodos de acceso.
7. En la pestaña de Configuración del método, se agrega una opción más de
configuración.
8. Se modifica el proceso de generación del código para poder generar el código de la
clase y que esta incluya el código del método actual y el código de los métodos
generados anteriormente.
Figura 56: Botón DAL en generación de procedimientos almacenados
104
8.1.2.1 Nueva pestaña Configuración general
En la fase anterior la herramienta de generación de métodos de acceso generaba
exclusivamente el código del método de acceso a datos para el procedimiento almacenado
seleccionado y tenía el siguiente aspecto:
En esta tercera fase, se permite la generación de las clases de acceso a datos que contienen los
métodos de acceso a datos. Para ello es necesario agregar una tercera pestaña llamada
Configuración general, que se situa como la primera de ellas, que permite configurar la
generación de estas clases. Esta nueva pestaña tiene el siguiente aspecto:
Las opciones de configuración de esta nueva pestaña son:
9. Clase base: En los desarrollos actuales, todas las clases que contienen los métodos de
acceso a datos, heredan de una clase llamada "BaseDAL" que contienen al menos la
siguiente propiedad y método:
- Propiedad Utilidades: Esta propiedad de tipo Utilidades permite el acceso a las
funciones de la librería Comunes.
Figura 58: Nuevas opciones en la pestaña de configuración del método de acceso a datos
Figura 57. Nuevas opciones en la configuración general para la generación de clases de acceso a datos
105
- Método Finalizar: Recibe como parámetros de entrada un objeto de tipo
DataReader y otro objeto de tipo DAOAcceso. Esta función se encarga de
liberar los recursos que el objeto DataReader haya utilizado al leer los datos
obtenidos de la ejecución de un procedimiento almacenado y se encarga de
cerrar la conexión establecidoa con la base de datos.
Por defecto el nombre de la clase es "BaseDAL", pero es posible modificarlo. De todas
formas es requisito indispensable que la clase tenga definido al menos esta propiedad
y este método.
10. Namespace: Espacio de nombres de la clase, por defecto esta caja de texto se cargará
con el espacio de nombres que se haya configurado al crear el proyecto. Este espacio
de nombres ha de ser igual al definido en las clases del modelo de datos, ya que sino
los métodos de acceso no podrán acceder a las propiedades definidas en la clase.
11. Imports: En esta sección se pueden agregar o quitar referencias de qué librerías se van
a cargar. Se utiliza el mismo sistema que en la generación de clases del modelo de
datos.
12. Ruta: Se especifica la ruta sobre la cual se van a generar las clases de acceso a datos.
Sólo si se ha seleccionado una ruta, será posible generar las clases que incluyan los
métodos de acceso a datos, en caso contrario, sólo será posible generar el código de
los métodos de acceso. Esto se explica más adelante con más detalle.
En base a estos parámetros se generará el código de las clases que contendrán el código de los
métodos de acceso.
El nombre de estas clases será el mismo que el nombre que se le dio en la generación del
modelo de datos, pero el nombre del archivo que contendrá el código de la clase se construye
concatenando el nombre de la clase y la palabra DAL.
106
Si se ha escogido una ruta y el fichero que se va a generar ya existe en la ruta seleccionada, se
deshabilitan las opciones de configuración: clase base, namespace y los de botones agregar y
quitar imports.
8.1.2.2 Nueva opción en la pestaña Configuración del método
En la fase anterior sólo se permitía que el valor de los parámetros que se agregaban a los
procedimientos almacenados lo recuperase de las propias propiedades de la clase. Pero esto
no siempre es así y por ello se ha agregado una nueva opción que permite escoger de dónde se
obtiene el valor. Esta nueva opción se llama Valor parámetros y permite escoger entre dos
opciones:
Propiedad de la clase: Esta opción es la que se utilizaba en la fase anterior, el valor de
los parámetros se obtiene de las propiedades de la clase.
Parámetro de entrada: Al elegir esta opción, se agrega en la definición del método
tantos parámetros de entrada como parámetros se van a agregar al procedimiento
almacenado. El nombre de los parámetros es el mismo que el nombre de las
propiedades de la clase, salvo que la primera letra se pone en minúsculas. Luego a la
hora de generar el código que agrega los parámetros al procedimiento almacenado se
tiene en cuenta estos nombres.
Figura 60: Nuevas opciones en la pestaña de configuración de método de acceso a datos.
Figura 59: Escoger ruta en la generación de clases de acceso a datos
107
Esta nueva opción que se ha agregado, tiene sentido utilizarla cuando por ejemplo se van a
buscar elementos en base a unos criterios, pero no tiene sentido utilizarla a la hora de grabar o
actualizar datos en la base de datos, puesto que nos podemos encontrar con métodos que
tienen decenas de parámetros de entrada y esto no es correcto.
Por ello, en función de la operación básica del procedimiento almacenado seleccionado se
seleccionará una u otra opción, aunque será posible modificarla. A continuación se muestra la
relación entre operaciones básicas y la opción que se seleccionará por defecto.
Parámetro Propiedad
Seleccionar todos X
Seleccionar por código X
Seleccionar activos X
Grabar nuevo X
Actualizar X
Baja lógica X
Baja física X
Tabla 10: Relación entre operaciones básicas y opciones activadas en la configuración de los parámetros de entrada
8.1.2.3 Modificación del proceso de generación del código de acceso a datos
En la fase anterior el proceso de generación del código de acceso a datos se reducía a la
generación del método seleccionado, pero en esta nueva fase al incorporar la pestaña de
configuración de la clase, es necesario modificar el proceso de generación del código.
Para poder generar el código de las clases y que estas contengan el código de los métodos, es
requisito imprescindible que se haya seleccionado una ruta en la pestaña de configuración
general. Si no se ha seleccionado ninguna ruta, sólo se generará el código del método de
acceso a datos para el procedimiento almacenado seleccionado.
En cambio si se ha seleccionado una ruta, en función de si la clase que se va a generar exista o
no, el proceso de generación de código variará.
Si la clase no existe, en la ruta seleccionada se generará una clase en base a la configuración
escogida en la pestaña de configuración general, que contendrá el método de acceso a datos
para el procedimiento almacenado seleccionado.
Si la clase existe, lo primero que se hace es recuperar el contenido de la clase y se comprueba
si el nombre del método junto con el tipo de acceso y los parámetros de entrada configurados,
existe en la clase. Si ya existe no se agrega nada, pero si no existe, al contenido de la clase se le
agrega el nuevo método. El método se agrega después del último método que contenga la
clase.
108
Para poder generar estas clases se ha agregado un botón en la pestaña Vista previa con
nombre Generar, que sólo estará activo si se ha configurado una ruta en la pestaña de
Configuración general.
8.2 Novedades. Librería de validación de controles. Con el objetivo de automatizar en lo mayor posible la validación de los datos que se
introducen en los formularios web, se ha desarrollado esta librería llamada
ControlesValidacion.
Lo que se pretende simplificar mediante el uso de esta librería, es la gestión de los diferentes
mensajes que se muestran a la hora de validar los datos introducidos. Las validaciones que se
pueden realizar dependen del tipo de control que se haya utilizado para introducir datos. No
es lo mismo validar el contenido de una caja de texto, que validar un control de lista
desplegable.
En la librería se han definido una serie de clases que permiten la validación de datos
introducidos en los controles de cajas de texto (TextBox), listas desplegables (DropDownList) y
listas de checks (CheckBoxList). El uso de estos controles abarca entorno al 90% de los
controles utilizados en los formularios web.
Puesto que no es posible modificar las clases originales del framework .NET para agregar las
validaciones deseadas, lo que se ha hecho es crear una clase por cada control y cada una de
ellas hereda del control original. Así tenemos las siguientes clases:
TextBoxV: hereda de la clase TextBox.
Figura 61: Vista previa de clase de acceso a datos
109
DropDownListV: hereda de la clase DropDownList
CheckBoxListV: hereda de la clase CheckBoxList.
Cada una de estas clases pueden usarse como controles web en los formularios web, pero para
ello es necesario configurar varios elementos en el proyecto donde se quieran usar. Esto se
explica en el apartado 2.5
En cada una de estas clases se definen una serie de propiedades que permiten configurar
cómo han de validarse los datos introducidos o seleccionados. Todas estas clases tienen en
común una serie de propiedades y una función.
Las propiedades son:
1. Obligatorio: De tipo booleano, se indica al control si ha de validar que tenga datos.
2. ValidarContenido: De tipo booleano indica se ha de validarse el contenido del control.
3. LiteralCampo: De tipo cadena, se indica el nombre del campo al que está asociado al
control. Se utiliza para la construcción de los mensajes de validación. Es obligatorio.
4. ClaseCssObligatorio: De tipo cadena, se indica el nombre de un estilo que se aplicará al
control cuando se haya indicado que el control es Obligatorio y no se cumpla esta
condición.
5. Orden: De tipo entero, se indica al control el orden en el que deben aparecer los
mensajes de validación. Si no se informa, ésta tendrá el mismo valor que la
propiedad TabIndex del control.
6. Avisos: Es una lista de cadenas, que contiene todos los avisos que se generan al validar
el dato del control, conforme a las propiedades establecidas.
7. ContieneDatos: De tipo booleano, indica si el control tiene dato introducido o datos
introducidos, dependerá del tipo de control, hacer una validación u otra.
Las propiedades del uno al cinco se usan para configurar el control, mientras que las dos
últimas se usan para la gestión interna de las validaciones de los controles.
Las función que tienen en común es:
ComprobarControlEsValido: Esta función está definida con acceso público y se encarga
de comprobar en base a los parámetros establecidos, si el contenido del control es
válido o no.
Más adelante se explicará por cada control, las propiedades que tienen aparte de las comunes.
En la librería, aparte de definir tres clases que luego pueden ser usadas como controles web,
se han definido otras clases que se pueden clasificar en dos grandes grupos:
Clases para la validación de los datos introducidos en los controles web. Se ha creado
una clase para el control DropDownListV y otra para el control CheckBoxListV, pero
para el control TextBoxV se han creado varias clases de validación. Se ha creado una
por cada tipo de dato que se ha pensado en validar en el control: texto libre, números,
fechas, correos electrónicos, etc.
110
Clases para gestionar los diferentes avisos que se obtienen al aplicar las validaciones
del anterior grupo de clases. Estas clases incluyen funciones para validar los controles
dentro de un formulario, div o panel. Incluyen también funciones para poder agregar
avisos que la librería no sea capaz de realizar, como pueden ser validaciones lógicas.
Otra característica de esta librería es que todos los mensajes que se generan, se han separado
en ficheros de recursos. Esto permite la traducción de los mismos a otros idiomas, de forma
que podríamos tener los avisos de validación en varios idiomas. Todo ello pensando en páginas
web multi idioma.
A continuación se describen los diferentes controles desarrollados así como las propiedades
que se han agregado y las posibles validaciones que pueden realizarse.
8.2.1 Clase TextBoxV
Aparte de las propiedades comunes ya comentadas anteriormente, en este control se han
agregado más propiedades que aportan nuevas posibilidades de validación:
Las propiedades públicas que se han agregado para validar el contenido en este control son:
TipoDato: Es una enumeración en la cual se especifica el tipo de dato que va a
contener el control y en función del cual se realizarán unas u otras validaciones. Las
posibles opciones son:
o TextoLibre: Opción por defecto, que se escoge si no se especifica ninguna.
o Fecha
o FechaNacimiento
o Email
o NumeroEntero
o NumeroDecimal
FormatoFecha: De tipo cadena, se utiliza para validar si la fecha introducida está en el
formato indicado. Esta propiedad solo se aplica cuando el tipo de dato es Fecha o
FechaNacimiento.
EdadMinima: De tipo entero, se utiliza cuando el tipo de dato es FechaNacimiento y ha
de validarse que la edad mínima no es inferior al valor introducido.
EdadMaxima: De tipo entero, se utiliza cuando el tipo de dato es FechaNacimiento y
ha de validarse que la edad máxima no supera el valor introducido.
Minimo: De tipo decimal, se utiliza cuando el tipo de dato es NumeroEntero o
NumeroDecimal, para validar que el valor introducido no sea inferior al valor definido.
Maximo: De tipo decimal, se utiliza cuando el tipo de dato es NumeroEntero o
NumeroDecimal, para validar que el valor introducido no sea superior al valor definido.
Aparte de todas estas propiedades que se han agregado para configurar el tipo de dato que va
a contener y delimitar sus posibles valores, se han agregado otra serie de propiedades públicas
que permiten recuperar el valor del control ya transformado al tipo correspondiente, así
tenemos:
111
ValorTexto: Devuelve un objeto de tipo cadena con el contenido de la caja de texto.
ValorEntero: Devuelve un objeto de tipo entero, que se obtiene al llamar a la función
de ConvertirAEntero de la clase UtilesNumeros de la librería Utilidades.
ValorDecimal: Devuelve un objeto de tipo decimal, que se obtiene al llamar a la
función de ConvertirADecimal de la clase UtilesNumeros de la librería Utilidades.
ValorFecha: Devuelve un objeto de tipo fecha, que se obtiene al llamar a la función de
Convertir de la clase UtilesFechas de la librería Utilidades.
8.2.2 Clase DropDownListV
En este control de lista desplegable se han agregado dos propiedades para la configuración del
control, que son:
ValorPorDefecto
TextoPorDefecto
Ambas propiedades están relacionadas, ya que se usarán
para cargar un elemento nuevo en la lista desplegable, este
elemento tendrá como texto el valor de la propiedad
TextoPorDefecto y como valor código el valor de la
propiedad ValorPorDefecto. Este elemento que se agrega se sitúa al comienzo de la lista, lo
que permite introducir elementos del tipo "Seleccionar".
Para conseguir esta funcionalidad se sobrescribe el evento DataBind del control.
8.2.3 Clase CheckBoxListV
En este control se ha agregado una nueva propiedad llamada MinimoASeleccionar donde se
estable el mínimo número de elementos que han de seleccionarse. Este propiedad es de tipo
numérico y nulable con lo que si no se estable ningún valor, en vez de tener valor cero si fuese
de tipo numérico, tendrá valor nulo al ser de tipo numérico y nulable.
También se han agregado varias propiedades que dan información acerca de los elementos
que se han seleccionado o no:
Seleccionados: Devuelve una lista cuyos elementos son de tipo ListItem con todos
aquellos elementos del control que han sido seleccionados.
NoSeleccionados: Devuelve una lista cuyos elementos son de tipo ListItem con todos
aquellos elementos del control que no han sido seleccionados.
HaySeleccionados: Devuelve un objeto de tipo booleano indicando si hay o no
elementos seleccionados.
8.2.4 Uso de la librería
Para usar esta librería, aparte de agregar estos tipos de controles a las páginas web, es
necesario instanciar un objeto de la clase de la librería. Esta clase se llama Validacion, que
tiene una serie funciones que permiten validar los controles agregados. Estas funciones que
validan los controles son:
ValidarFormulario: valida los controles que encuentra dentro de un objeto de tipo
HtmlForm que recibe como parámetro de entrada.
Figura 62. Ejemplo elemento por defecto en controles DropDownList
112
ValidarControlesEnDiv: valida los controles que encuentra dentro de un objeto de tipo
HtmlGenericControl que recibe como parámetro de entrada.
ValidarControlesEnPanel: valida los controles que encuentra dentro de un objeto de
tipo Panel que recibe como parámetro de entrada.
Las tres funciones son prácticamente idénticas, puesto que lo que hacen es recorrer todos los
controles que contiene el objeto que reciben como parámetro de entrada. Por cada control
que recorren comprueban si se corresponde con alguno de los tipos de control que define la
librería y si esto es así, llama a la función ComprobarControlEsValido del propio control.
Los mensajes de validación que los controles van generando los acumula en una propiedad
pública llamada Avisos.
Esta clase dispone también de una función llamada AgregarAvisos con sobrecarga. Permite
agregar uno o varios avisos a un control en concreto, para ello se recibe como parámetros de
entrada una cadena de texto o una lista de cadenas de texto y el nombre del control sobre el
cual han de agregarse los avisos.
La finalidad de esta función, es permitir agregar avisos que la librería no es capaz de generar. El
hecho de tener que pasar como parámetro de entrada un nombre del control, es para poder
mostrar los mensajes agrupados por controles.
8.2.5 Configuración de los proyectos para poder utilizar la librería.
Las tres clases mencionadas anteriormente, pueden usarse como controles web en los
formularios web, pero para ello es necesario:
En el proyecto web que se vaya a usar, es necesario agregar una referencia a la librería
ControlesValidacion.
Figura 63: Referencia a librería de validación de controles
En el fichero web.config (fichero de configuración) del proyecto web, es necesario
agregar una línea dentro del bloque "controls" que se encuentra dentro de "pages". En
este bloque se definen que controles se permiten usar en las páginas web. Por defecto
aparecen dos líneas que agrega Visual Studio y que hacen referencia a los controles
estándar del framework.
En la línea que se agrega se define el prefijo que se pone antes de utilizar el control y
el nombre del espacio de nombres y assembly. El nombre del espacio de nombres y
assembly es el nombre de la librería que es ControlesValidacion. El nombre del prefijo
puede variar, pero lo recomendable es utilizar la palabra asp. De esta forma
tendríamos lo siguientes:
113
Figura 64: Ejemplo de configuración de la librería validación de controles
Agregando esta línea y compilando el proyecto, en el diseñador de las páginas web ya
se pueden agregar los controles de la librería.
Figura 65: Ejemplo control web disponible en diseño de pantalla
114
9. Pruebas En este capítulo se muestran algunas de las pruebas que se han realizado para validar lo
desarrollado en el proyecto. Las pruebas se centran en dos grandes bloques:
Por una parte comprobar que el código que genera la herramienta para acceder a la
base de datos, compila, y ejecuta de manera correcta los procedimientos almacenados
creados con otra herramientas de la aplicación.
Por otro lado pantallas de mantenimiento que utilizan los controles de validación, para
comprobar que se muestran los mensajes de validación correctamente.
No realizo pruebas de la librería de Utilidades, puesto que en los bloques anteriores, se utiliza
de forma interna esta librería. De forma que al realizar pruebas sobre ellos, de forma implícita,
estoy realizando pruebas de la librería de Utilidades.
9.1 Herramienta de generación de procedimientos y código Puesto que la aplicación desarrollada, genera código para acceder a una base de datos, he
creado una base de datos de ejemplo. Esta base de datos llamada Empresa, gestiona de
manera muy simple la información de una empresa. Muestro a continuación las tablas
definidas en la base de datos.
Figura 66: Modelo de datos para pruebas
Además he preparado un proyecto en Visual Studio de tipo servicio web, con todo los
necesario para su funcionamiento, en el cual agregaré las clases que se creen. Este proyecto
tiene agregado:
115
Carpetas para clasificar las clases que se van a generar.
Una referencia a la librería Utilidades que se ha desarrollado en el proyecto, puesto
que el código que se genera la utiliza.
Clases que gestionan la conexión con la base de datos, abrir conexión, agregar
parámetros a los procedimientos almacenados y la ejecución de éstos. Carpeta DAO.
La clase BaseDAL que utilizan las clases de acceso a datos (heredan de ella) y que
contiene una propiedad de tipo Utilidades y la función que se encarga de cerrar la
conexión con la base de datos (Finalizar).
Un servicio web (fichero con extensión asmx), en el cual definiré métodos web que
llamen a las operaciones que se creen de acceso a datos, para ver el resultado de su
ejecución.
El proyecto creado a tal efecto tiene el siguiente aspecto:
Figura 67: Configuración del proyecto para probar la herramienta
Una vez definida la base de datos y creado el proyecto en Visual Studio, es hora de poner en
marcha la herramienta. Lo primero es crear un nuevo proyecto.
Figura 68: Configuración del nuevo proyecto.
116
Una vez creado el proyecto, lo selecciono de la lista de proyectos existentes, tras ello, la
herramienta me informa que ha detectado ocho nuevas tablas, es correcto.
Tras haber recuperado la información de tablas y campos, ya se pueden crear procedimientos
almacenados, aunque para poder usar todo el potencial de la herramienta, que genera los
accesos a datos, es recomendable definir primero el modelo de datos.
En la herramienta que se encarga de calcular el modelo de datos, dejo marcados todos los
checks de configuración, que es como viene por defecto. Tras pulsar el botón Calcular, procedo
a revisar que los tipos de datos de las propiedades son las correctas. Además establezco en la
clase Empleado, que la propiedad Activo es la que determina si el registro se considera activo o
no.
Puesto que todo está correcto procedo a generar todas las clases del modelo de datos en la
carpeta Entidades del proyecto de prueba. La generación de las clases funciona correctamente
y al actualizar la carpeta de Entidades en el proyecto de prueba, ya puedo ver las clases que ha
generado por lo cual las agrego al proyecto, quedando la carpeta Entidades así:
Figura 69: Clases generadas e incluidas en el proyecto.
A continuación muestro la clase de Empleado, que en esta base de datos, se corresponde con
la tabla más importante.
Figura 70: Ejemplo de clase generada. Empleado
117
Una vez que ya he generado el modelo de datos, procedo a crear métodos de acceso a datos,
para ello he de generar primero los procedimiento almacenados. Para estas pruebas creo
procedimientos que me permitan:
Obtener todas las sedes, ordenando el resultado por el nombre.
Obtener la información de un empleado buscándolo por código
Obtener los empleados que están activos, ordenando el resultado por nombre y
apellidos.
Grabar un nuevo departamento y devolver el código que se le ha asignado.
Actualizar la información de un cliente
Dar de baja lógica un empleado
Baja física de un cliente
Tras la creación de cada uno de estos procedimientos procedo a crear su método de acceso a
datos, accediendo a la correspondiente herramienta. Establezco que los valores de los
parámetros se reciben como parámetros de entrada de los propios métodos, para agilizar las
pruebas. Tras configurar los métodos continuo con la creación de las clases en la carpeta DAL
del proyecto de pruebas, obteniendo como resultado las siguientes clases:
Figura 71: Clases DAL generadas
Para poder probar estas funciones, agrego al servicio web, tantos métodos web, como
operaciones se han creado anteriormente, dando como resultado:
Figura 72: Métodos web para probar las operaciones creadas.
A continuación pruebo uno a uno los métodos web creados, para verificar que el resultado de
su ejecución se corresponde con el esperado. Por ejemplo el método web
ObtenerTodasLasSedes devuelve como resultado:
118
Figura 73: Resultado de invocación de un método web de pruebas
Todos los resultados que se obtienen en un servicio web al invocarlos directamente, se
muestran en formato XML, este XML se corresponde con una lista de objetos de tipo Sede que
ha sido serializado.
Uno a uno se prueban cada uno de los métodos web creados para verificar el funcionamiento
de cada función de acceso a datos. En caso de detectarse algún resultado no esperado, se
procede a buscar qué es lo que ha fallado, para corregirlo.
9.2 Controles de validación Para realizar las pruebas de la librería de validación de controles, he creado varias páginas web
en las cuales agrego varios controles que me permitan comprobar el correcto funcionamiento
de la misma.
Un ejemplo de una de estas páginas es:
Figura 74: Ejemplo de página web para probar los controles de validación.
119
En esta página en concreto valido los siguientes elementos con la siguiente configuración:
Campos Nombre y Apellidos con la configuración:
o TipoControl: TextBoxV
o TipoDato: TextoLibre
o LiteralCampo: El nombre del campo en cada caso.
o Obligatorio: Sí
o ClaseCssObligatoria: obligatorio
o MaxLength: 50
Campo Sexo:
o TipoControl: DropDownListC
o LiteralCampo: Sexo
o Obligatorio: Sí
o ValorPorDefecto: 0
o TextoPorDefecto: Seleccionar
o ClaseCssObligatoria: obligatorio
Campo Email:
o TipoControl: TextBoxV
o TipoDato: Email
o LiteralCampo: Email
o MaxLength: 150
Campo Fecha nacimiento:
o TipoControl: TextBoxV
o TipoDato: FechaNacimiento
o FormatoFecha: dd/mm/yyyy
o LiteralCampo: FechaNacimiento
o EdadMinima: 18
o EdadMaxima: 65
o MaxLength: 10
Campo Dias trabajados:
o TipoControl: TextBoxV
o TipoDato: NumeroEntero
o LiteralCampo: Dias trabajados
o Minimo: 1
o Maximo: 365
Campo Horas trabajadas:
o TipoControl: TextBoxV
o TipoDato: NumeroDecimal
o LiteralCampo: Horas trabajadas
o Minimo: 1
120
o Maximo: 2000
Campo Departamentos:
o TipoControl: CheckBoxListV
o Obligatorio: Sí
o ClaseCssObligatoria: obligatorio
o LiteralCampo: Departamento
o MinimoASeleccionar: 1
Con todos estos parámetros de configuración, tan solo hace falta agregar al evento del botón
validar, el código necesario para llamar a la función de validación de los controles. Una vez
hecho esto ya es posible empezar a probar la página.
Al pulsar el botón por primera vez sin introducir nada en ningún control, aparece lo siguiente:
Figura 75: Primera prueba de validación de controles.
Como se ve en la imagen, todos los controles que se habían configurado como obligatorios,
aparecen con un borde rojo, este borde se debe al estilo configurado en la propiedad
ClaseCssObligatoria.
Si completo los campos obligatorios e introduzco valores incorrectos en el resto, al pulsar el
botón de validación aparece lo siguiente:
121
Figura 76: Segunda prueba de validación de controles.
En esta segunda prueba, como ya he introducido valores a los controles obligatorios
desaparece el borde rojo de los mismos, puesto que ya no se aplica la css obligatorio. En los
mensajes de validación que se muestran al comienzo de la página, se lee que los campos
email, fecha de nacimiento, días trabajados y horas trabajadas tienen valores que no se
corresponden con el tipo de dato esperado o no se encuentran dentro del rango de valores
establecido.
A partir de aquí todas las pruebas se centran en introducir valores diferentes a los que se
esperan y comprobar que la librería de validación de los controles, se comporta según lo
planificado.
En caso de encontrar comportamientos incorrectos o incluso la misma falta de ellos, se revisa
el código y se corrige el problema detectado.
122
10. Conclusiones En el transcurro de este proyecto se han creado los siguientes elementos:
Evolución de la librería Utilidades.
Generador de procedimientos almacenados para operaciones básicas.
Herramienta para agregar funciones SQL a bases de datos.
Generadores de modelos de datos y métodos de acceso a datos a partir de los
procedimientos almacenados creados anteriormente.
Librería para la validación del contenido de controles web.
Todos estos elementos permiten una reducción del trabajo de desarrollo de aplicaciones
informáticas.
Este capítulo trata de cuantificar esta reducción de tiempo.
10.1 Librería Utilidades La evolución de esta librería se caracteriza por:
Mejora de la clasificación de las funciones
Uso de funciones genéricas que hacen más simple su uso. Utilizado principalmente en
los módulos que agregan datos a los procedimientos almacenados y leen datos de
DataReaders tras la ejecución de los primeros (UtilesBaseDatos y UtilesDataReader)
El usar esta librería no reducirá especialmente el tiempo de desarrollo de futuras aplicaciones,
porque anteriormente ya se usaba otra versión de esta librería, aunque bien es cierto que no
contaba con estas características. Además el uso de las funciones genéricas se utiliza
sobretodo en los métodos de accesos a datos, y estos métodos han sido automatizados. Por lo
tanto se puede decir que la reducción en tiempo de desarrollo al usar esta librería es mínimo.
En cambio si no se hace uso de esta librería se perderá tiempo en el desarrollo de las
aplicaciones.
10.2 Generador de procedimientos almacenados Para poder analizar el ahorro al utilizar la herramienta de generación de procedimientos
almacenados, voy a recuperar primero la tabla número 4 donde estaba la relación del número
de procedimientos almacenados por proyecto de ejemplo usado en esta memoria.
Proyecto Pesca Investigación Estadística
Número Porcentaje Número Porcentaje Número Porcentaje
SELECT 104 70.27 180 66.42 38 67.85
INSERT 19 12.83 38 14.02 6 10.71
UPDATE 13 8.78 32 11.80 6 10.71
DELETE 12 8.10 21 7.75 6 10.71
TOTAL 148 100 271 100 56 100 Tabla 11: Número de procedimientos almacenados por operación y proyecto.
123
El generador de procedimientos almacenados sólo es capaz de generar procedimientos de una
única tabla al mismo tiempo. Por tanto quedan excluidos todos aquellos que trabajan con dos
o más tablas al mismo tiempo. Éstos son los que recuperan datos de varias tablas al mismo
tiempo, que casi siempre se corresponden con procedimientos almacenados para realizar
búsquedas y con la operación básica SELECT.
Estas búsquedas se centran principalmente en la tablas sobre la que giran las proyectos, que
en general no suelen rebasar el 10% sobre el total de tablas. A continuación se muestra por
cada proyecto de ejemplo el número de tablas sobre las cuales se centran las aplicaciones.
Sobre estas tablas se concentran más del 90% de todas las búsquedas.
Proyecto Pesca Investigación Estadística
Nº de tablas 25 46 17
Nº tablas principales 3 4 1
10% sobre el total 3 5 2 Tabla 12: Relación del número de tablas principales
Por cada tabla principal, el número de procedimientos almacenados creados para buscar datos
sobre estas tablas y algunas de sus relacionadas, dependen de cada proyecto. Por lo general se
suele crear un procedimiento almacenado por cada sección de la aplicación. Por ejemplo si un
proyecto consta de una parte pública y otra privada (o de gestión) se crearían al menos dos,
uno para cada parte. Esto se hace así para facilitar las futuras modificaciones, ya que no tienen
por qué aplicarse los mismos filtros en ambas partes.
En las proyectos analizados la media del número de procedimientos almacenados de búsqueda
respecto al número de tablas principales es algo inferior a cuatro. Si restamos estos
procedimientos almacenados de búsqueda al total de procedimientos creados tenemos los
siguientes resultados
Proyecto Pesca Investigación Estadística
Total 148 271 56
Búsqueda 9 14 2
Diferencia 139 257 54
% sobre total 93.91 94.83 96.42 Tabla 13: Procedimientos almacenados sin búsquedas
Los resultados hablan de un ahorro cercano al 95 por ciento, es decir que el 95 por ciento de
los procedimientos almacenados pueden crearse utilizando esta herramienta.
10.3 Agregar funciones SQL a base de datos El uso de esta herramienta depende de las necesidades de cada proyecto, pero aún y todo el
tiempo que se puede llegar a ahorrar es muy pequeño, ya que aunque ahora el proceso de
agregar estas funciones está automatizado, lo que se hacía anteriormente era copiarlas de
otros proyectos donde se habían utilizado anteriormente.
Así pues el tiempo que se ahorra aquí, es el tiempo en localizar las funciones en otras bases de
datos, generar los scripts de su creación y el tiempo de ejecutar los scripts en la nueva base de
datos.
124
10.4 Generadores del modelo de datos y métodos de acceso a datos. Pese a ser dos herramientas diferentes, las trato como un único elemento debido a su directa
relación, ya que los métodos de acceso a datos no pueden entenderse sin la definición del
modelo de datos.
Para poder valor el ahorro que supone el uso de estas herramientas, muestro a continuación el
recuento de líneas de código realizado sobre los proyectos de ejemplo. En este recuento se
ignoran muchos ficheros que Visual Studio genera de manera automática, líneas de
comentarios y líneas en blanco.
Proyecto Pesca % Investigación % Estadística %
Modelo 1.924 5.12 999 2.16 1.168 6.84
DAL 7.245 19.35 11.462 24.81 2.396 14.04
Modelo + DAL 9.169 24.43 12.461 26.97 3.564 20.89
Total 37.528 100 46.191 100 17.061 100 Tabla 14: Recuento del número de líneas de código
Como se puede ver en la tabla, el ahorro de trabajo es considerable, oscila entre un 21% y un
27%. No obstante el ahorro en tiempo no se puede trasladar en el mismo porcentaje, ya que
pese a que este porcentaje de código se genera de manera automatizada, se requiere a una
persona para configurar las herramientas y hacer uso de su interfaz. Pese a todo el ahorro en
tiempo puede rondar el 18-20%.
10.5 Librería validación del contenido de controles web. Con el uso de esta librería se simplifica la gestión de la validación del contenido que se ha
agregado en los controles web de las páginas. Mediante el uso y configuración de los controles
definidos en esta librería se abarcan casi todas de las validaciones de datos que se pueden
llegar a hacer. Cierto es que algunas validaciones lógicas no pueden realizarse, pero para ello la
librería admite la posibilidad de agregar mensajes de validación a cada uno de los controles de
la página.
Si se analizan las pantallas donde se introducen datos, el código que se escribe para validar los
datos introducidos no llega a representar el 10% de las líneas de código de las mismas, por lo
que el ahorro en cuanto a número de líneas no es significativo. Sin embargo, el ahorro en
tiempo es mucho más significativo, puesto que al mismo tiempo que se agregan los controles a
la página, se puede configurar las validaciones que han de aplicarse sobre los datos que se van
a agregar.
Además el uso de esta librería garantiza que las validaciones funcionen correctamente,
reduciendo de forma considerable el tiempo a invertir en las pruebas que hay que hacer sobre
la pantalla.
Otra característica importante, es que los mensajes de validación se almacenan en ficheros de
recursos, lo que facilita su mantenimiento y su posible traducción a otros idiomas si la
aplicación necesita ser multiidioma.
125
10.6 Conclusión final Si recopilamos todos los ahorros en tiempo del uso de todas las herramientas y librerías
desarrolladas en este proyecto, se puede hablar que el ahorro medio estará cercano al 25% del
tiempo que se requiere para crear una aplicación. Además del ahorro en futuras
modificaciones, ya que al estar los proyectos muy estructurados, cualquier modificación se
realizará de manera rápida y sencilla.
Por otra parte la estimación inicial en horas de este proyecto era de unas 630, aunque han sido
algunas más ya que conforme he ido analizando y desarrollando las herramientas y librerías, se
me han ido ocurriendo nuevas herramientas y mejoras a desarrollar, que en algunos casos no
he podido realizar por falta de tiempo. No obstante el número de horas que se corresponden
con el análisis y desarrollo de las librerías y herramientas rondan las 500 horas, ya que hay que
restar todo el tiempo dedicado a crear la documentación del proyecto.
Para poder amortizar estas horas de dedicadas al desarrollo de estas herramientas y librerías
se necesitan alrededor de 2000 horas de trabajo, algo más de 13 meses de trabajo. Hay que
tener en cuenta que este ahorro conseguido se puede aplicar a todos los proyectos futuros
que se organicen de esta manera.
Como conclusión se puede determinar que merece la pena el esfuerzo dedicado a la
generación de código por medio de librerías y herramientas. El desarrollo de estas librerías y
herramientas en este proyecto es sólo el primer paso, puesto que visto lo resultados
obtenidos, en el futuro se buscará la manera de aumentar sus funcionalidades.