tesis-persistencia-maestria
TRANSCRIPT
UNIVERSIDAD FRANCISCO GAVIDIA UNIDAD DE POSTGRADOS
“Desarrollo de un Motor de Persistencia para
la Plataforma Microsoft .Net”
TRABAJO DE GRADUACION PREPARADO PARA LA
UNIDAD DE POSTGRADOS
PARA OPTAR AL GRADO DE:
MASTER EN INFORMATICA APLICADA A REDES
PRESENTADO POR:
Francisco José Fernández Escobar Ernesto Armando Zavaleta William Alexie Rebolone
DICIEMBRE – 2006
SAN SALVADOR – EL SALVADOR – CENTROAMERICA
Maestría en Informática Aplicada a Redes
Página 2 de 159
Tabla de Contenidos
I. INTRODUCCIÓN .................................................................................................................................. 4
1.1. OBJETIVOS. ...................................................................................................................................... 5 1.2. ALCANCES ....................................................................................................................................... 6 1.3. LIMITACIONES.................................................................................................................................. 6 1.4. SUPOSICIONES Y DEPENDENCIAS ..................................................................................................... 7 1.5. A QUIEN ESTA DIRIGIDO ESTE DOCUMENTO...................................................................................... 7 1.6. ORGANIZACIÓN DEL DOCUMENTO. .................................................................................................. 8
II. JUSTIFICACIÓN DEL TEMA............................................................................................................. 9
2.1 ANTECEDENTES ............................................................................................................................... 9 2.2 MOTORES DE PERSISTENCIA Y EL FRAMEWORK .NET.................................................................... 11 2.3 EL PORQUE DE LA CREACIÓN DE UN MOTOR DE PERSISTENCIA PARA .NET. .................................... 12
III. FUNDAMENTOS TEORICOS ...................................................................................................... 13
3.1 PROGRAMACIÓN ORIENTADA A OBJETOS....................................................................................... 13 3.1.1 Historia y Evolución................................................................................................................. 13 3.1.2 Ventajas de la OO..................................................................................................................... 14 3.1.3 Características de los Objetos.................................................................................................. 15
3.2 PATRONES DE DISEÑO .................................................................................................................... 21 3.2.1 Historia..................................................................................................................................... 22 3.2.2 Conceptos Clave ....................................................................................................................... 23 3.2.3 Tipos de Patrones ..................................................................................................................... 23 3.2.4 Patrones de Acceso a Datos ..................................................................................................... 25 3.2.5 El patrón Singleton................................................................................................................... 27 3.2.6 El Patrón Factory..................................................................................................................... 28 3.2.7 El Patrón Abstract Factory ...................................................................................................... 32 3.2.8 El Patron Data Accessors......................................................................................................... 34 3.2.9 Patron DAO (Data Access Object)........................................................................................... 34
3.3 BASES DE DATOS ORIENTADAS A OBJETOS.................................................................................... 38 3.3.1 El Concepto de Orientación a Objetos ..................................................................................... 40 3.3.2 El Modelo de Datos Orientado a Objetos ................................................................................ 41 3.3.3 El modelo Estándar ODMG ..................................................................................................... 46
3.4 SISTEMAS OBJETOS-RELACIONALES .............................................................................................. 49 3.4.1 Diferencia entre los tres sistemas (RDBMS, ODBMS, ORDBMS)........................................... 50
3.5 MOTORES DE PERSISTENCIA........................................................................................................... 53 3.5.1 Opciones para motores de persistencia.................................................................................... 55
3.6 PROCESO DE DISEÑO Y DESARROLLO DE UN PROYECTO DE SOFTWARE ........................................ 56 3.6.1 CMM......................................................................................................................................... 56 3.6.2 El RUP y el Proceso Unificado ................................................................................................ 65 3.6.3 Microsoft Solution Framework................................................................................................. 67
3.7 MICROSOFT .NET FRAMEWORK ..................................................................................................... 69 3.7.1 Características ......................................................................................................................... 71 3.7.2 Arquitectura.............................................................................................................................. 75 3.7.3 ADO .Net 2.0 ............................................................................................................................ 83
IV. SOLUCIÓN PROPUESTA ............................................................................................................. 90
4.1 MODELADO DE LA SOLUCIÓN ........................................................................................................ 90 4.1.1 Consideraciones Iniciales......................................................................................................... 90 4.1.2 Namespaces y Assemblies......................................................................................................... 92
4.2 SINCRONIZACIÓN ESTRUCTURA ER Y MODELO DE DOMINIO ........................................................ 93 4.2.1 Planteamiento del Requerimiento............................................................................................. 93 4.2.2 Diseño de la Solución ............................................................................................................... 93
Maestría en Informática Aplicada a Redes
Página 3 de 159
4.2.3 Construcción de la Solución..................................................................................................... 98 4.3 GENERACIÓN DE OPERACIONES TRANSACCIONALES ...................................................................... 99
4.3.1 Planteamiento del Requerimiento............................................................................................. 99 4.3.2 Diseño de la Solución ............................................................................................................... 99 4.3.3 Construcción de la Solución................................................................................................... 103
4.4 CONSTRUCCIÓN Y CARGAS DE LOS OBJETOS ............................................................................... 108 4.4.1 Planteamiento del Requerimiento........................................................................................... 108 4.4.2 Diseño de la Solución ............................................................................................................. 108 4.4.3 Construcción de la Solución................................................................................................... 109
4.5 ACCESO INDEPENDIENTE DEL SISTEMA RDBMS ......................................................................... 112 4.5.1 Planteamiento del Requerimiento........................................................................................... 112 4.5.2 Diseño de la Solución ............................................................................................................. 113 4.5.3 Construcción de la Solución................................................................................................... 115
4.6 CONFIGURACIÓN Y PARAMETRIZACIÓN ....................................................................................... 117 4.6.1 Planteamiento del Requerimiento........................................................................................... 117 4.6.2 Diseño de la Solución ............................................................................................................. 118 4.6.3 Construcción de la Solución................................................................................................... 118
V. RESULTADOS Y VERIFICACION EXPERIMENTAL ............................................................... 120
5.1 OBJETIVO DE LAS PRUEBAS.......................................................................................................... 120 5.2 DEFINICIÓN DEL REQUERIMIENTO................................................................................................ 120 5.3 MODELADO Y DISEÑO DE LA SOLUCIÓN ...................................................................................... 121
5.3.1 Modelo de Dominio. ............................................................................................................... 121 5.3.2 Modelo de Acceso a Datos ..................................................................................................... 125 5.3.3 Modelo de Reglas del Negocio. .............................................................................................. 126
5.4 CONSTRUCCIÓN DE LA APLICACIÓN ............................................................................................. 128 5.4.1 Creación de la Estructura de Datos. ...................................................................................... 128 5.4.2 Creación del Proyecto Visual C# Win32................................................................................ 129
5.5 EJECUCIÓN Y RESULTADOS .......................................................................................................... 138 5.5.1 Operación de Adición............................................................................................................. 139 5.5.2 Operación de Actualización: .................................................................................................. 140 5.5.3 Operación de Eliminación...................................................................................................... 141
5.6 CONCLUSIONES SOBRE LAS PRUEBAS........................................................................................... 141
VI. CONCLUSIONES Y FUTURAS LINEAS DE INVESTIGACION .......................................... 142
6.1 CONCLUSIONES GENERALES ........................................................................................................ 142 6.2 FUTURAS LÍNEAS DE INVESTIGACIÓN........................................................................................... 143
6.2.1 Manejo de Herencia y Composición....................................................................................... 143 6.2.2 Eficiencia y Rendimiento. ....................................................................................................... 144 6.2.3 Ejecución sobre plataformas no Windows.............................................................................. 144
VII. BIBLIOGRAFÍA Y REFERENCIAS ESTUDIADAS................................................................ 145
VIII. ANEXO A: CÓDIGO FUENTE DEL MOTOR DE PERSISTENCIA .................................... 147
Maestría en Informática Aplicada a Redes
Página 4 de 159
I. Introducción
A medida que evoluciona la tecnología y los procesos de negocios de las empresas privadas
y gubernamentales se vuelven mas dependientes de las ciencias de la información, se
demanda a su vez, una mayor calidad en los procesos de desarrollo de software con el fin
de obtener productos de una mayor calidad, es decir con una mejor estabilidad, eficiencia
robustez y reusabilidad de los dichos elementos. Esto significa que lo productos de software
no deben ser diseñados y creados únicamente para solucionar un requerimiento especifico
de usuario como un caso de uso, un user story o un escenario, sino deben de ser diseñados
de tal forma que estén totalmente documentados, que su arquitectura sea robusta y permita
la reutilización de sus componentes, que sea sencillo el cambio o extensión de una
funcionalidad o comportamiento, que su ejecución sea estable, etc. Estos requerimientos
son totalmente soportados por la orientación a objetos la cual con la ayuda de algunos
metodologías de desarrollo y herramientas de software logran cumplir los requerimientos
antes mencionados.
En el ciclo de desarrollo de los proyectos de software, las etapas de conceptualización y
diseño de sistemas requieren abstraer los comportamientos de los elementos que se desean
mecanizar, de tal forma que sean imitados tanto en sus propiedades como en su
comportamiento, esto nos lleva a la definición de tipos de datos o clases los cuales serán la
implementación de los elementos surgidos de la etapa de conceptualización, estos tipos de
datos con estado y comportamiento, darán vida a lo que denominaremos ya en la ejecución
de sistema “objetos”.
Dado que la tecnologías favoritas actuales de persistencia de datos aun son las bases de
relacionales, existe un divorcio entre los modelos de clases que forman la
conceptualización del sistema con sus propias características OO (Object Oriented) como la
herencia, la encapsulación y el polimorfismo y los modelos relacionales los cuales siguen
otro conjunto de reglas como las reglas de normalización. Este problema es solventado por
los motores de persistencia, quienes se encargan de convertir objetos a registros en un
sistema relacional y viceversa.
Maestría en Informática Aplicada a Redes
Página 5 de 159
Los motores de persistencia vienen entonces a ser el enlace entre ambas tecnologías
permitiendo al diseñador llegar a abstraer completamente un sistema en un modelo de
clases con sus características innatas OO, sin tener que preocuparse por como serán
persistidos los datos en la base relacional.
Este documento muestra como utilizando recursos sin costo alguno puede ser construido un
motor de persistencia para la plataforma .Net de Microsoft que implemente las
características principales de esta tecnología de persistencia de un modelo conceptual
completamente Object Oriented o modelo de dominio en una base de datos relacional
1.1. Objetivos.
• Fomentar el diseño orientado a objetos utilizando la plataforma .Net, al facilitar una
herramienta que implemente la funcionalidad necesaria para persistir objetos que a
su ves sean capaces de conceptualizar los distintos elementos que componen un
sistema de información como objetos que modelen la realidad del sistema y posean
responsabilidades únicas.
• Diseñar y desarrollar una librería que implemente la funcionalidad para realizar un
mapeo automático entre un modelo de clases o modelo de Dominio y un modelo
ER.
• Diseñar una librería que implemente la funcionalidad necesaria para crear de forma
automática las operaciones transaccionales contra un sistemas RDBMS.
• Aplicar conceptos avanzados de Ingeniería de Software, como el uso de patrones de
diseño, para garantizar la reusabilidad del código desarrollado, así como su
confiabilidad y robustez.
• Fomentar el uso de técnicas de ingeniería de software avanzadas en los programas
educativos de las universidades, al utilizar este documento como una referencia de
trabajo y ejemplo de la aplicación de patrones de diseño y otras temas relacionados.
Maestría en Informática Aplicada a Redes
Página 6 de 159
1.2. Alcances
• Se desarrollará un prototipo que implementará la funcionalidad principal del motor
de persistencia, es decir maneje automáticamente las operaciones de Object /
Relational Mapping O/R M.
• La arquitectura del producto es un diseño 100% creado por el grupo de trabajo y no
se ha copiado, basado o inspirado en la arquitectura de productos existentes por lo
que no existe un elemento de investigación de las arquitecturas de los motores
actuales, sino solamente sobre su funcionalidad.
• El proyecto esta orientado a la plataforma .Net de Microsoft, específicamente al
Framework 2.0.
• Todas las herramientas a emplear en el desarrollo del proyecto a excepción de la
herramienta CASE 1de diseño y modelado son de libre distribución, por lo que no se
estiman costos para la adquisición de software.
• El producto será desarrollado utilizando el lenguaje C# de Microsoft y la
herramienta de desarrollo Visual C# 2005 Express edition.
• Para realizar las operaciones de mapeo O/RM, ya que esto se hará de forma
automática y transparente para el desarrollador, el producto se basará en un modelo
de clases el cual debe de coincidir perfectamente con un modelo relacional por lo
que será altamente recomendable la utilización de una Herramienta Case que
mantenga la sincronía entre el modelo de clases y el ER.
1.3. Limitaciones.
La limitación principal que afecta el proyecto en si, es el tiempo asignado y ya que de
las 10 semanas totales se utilizaron más de dos en la formulación del proyecto, algunas
limitaciones especificas son las siguientes:
• Para el prototipo a implementar, no se contempla el soporte para la Composición y
la herencia.
1 Se deja a criterio del lector el uso de la herramienta CASE de su preferencia. Para este proyecto se utiliza PowerDesigner 12
Maestría en Informática Aplicada a Redes
Página 7 de 159
• Se construirá el prototipo con librerías de acceso a datos o dialectos que permitan
conectarse a los sistemas Oracle, Mysql y Microsoft SQL Server 2000/2005. Estas
podrán ser extendidos posteriormente gracias a la utilización de los patrones de
diseño como el Abstract Factory.
• Se han utilizado patrones de diseño fundamentales como el Singleton y el Abstract
Factory y otros específicos de acceso a datos como DAO, Data Accesors, etc. Sin
embargo es posible que alguna de la funcionalidad creada en este prototipo pudiera
haber sido implementada también utilizando otros patrones que por el corto tiempo
no pudieron ser considerados.
• Se enfoco el esfuerzo del grupo de trabajo en la eficacia de la funcionalidad a
implementar, esto debido a la limitante de tiempo. Se propone entonces un estudio
aparte a este proyecto donde se plantee la implemente la funcionalidad propuesta de
una forma mas eficiente.
1.4. Suposiciones y Dependencias
• Se supone que el lector tiene conocimientos medios en la utilización del lenguaje
C# y de las técnicas de orientación a objetos.
• Se supone que el lector tiene claro las ventajas de la utilización de un enfoque
orientado a objetos sobre uno tradicional.
• Se supone que el lector tiene conocimientos básicos de los patrones de diseño y de
las ventajas que estos representan en la construcción de software.
• Se supone que el diseñador modelador posee conocimientos sobre modelado UML
y uso de la herramienta CASE.
1.5. A quien esta dirigido este documento. Este documento en general esta dirigido a todo aquel desarrollador que desee ampliar sus
conocimientos en el uso de la tecnología de motores de persistencia u O/R Mapping,
aplicadas a la plataforma Microsoft .Net.
El documento sin embargo ha sido elaborado para que pueda ser utilizado como una guía a
educadores del área de desarrollo de nivel intermedio que puedan al implementar la
Maestría en Informática Aplicada a Redes
Página 8 de 159
propuesta aquí planteada, repasar una serie de conocimientos, técnicas y principios
relacionados a la Ingeniería del Software. Sin embargo debe de recordarse que no esta
orientada a desarrolladores principiantes, sino con un conocimiento intermedio de
programación orientada a objetos y desarrollo bajo e framework .Net.
1.6. Organización del Documento.
El documento ha sido organizado de la siguiente manera:
En el primer capitulo “Introducción” encontrará todo lo referente a la definición del
proyecto, sus objetivos, alcances y limitantes, así como las suposiciones sobre las que se
trabajo dicho proyecto y la descripción de a quien esta dirigido este documento.
El segundo capitulo “Justificación del Tema”, describe la importancia del tema de motores
de persistencia en el contexto de un mejor ciclo de vida de proyectos de desarrollo de
software y del beneficio académico que supone este proyecto
El tercer capitulo “Fundamentos Teóricos” contiene una referencia documental rapida de
distintas, tecnologías, disciplinas y estándares relacionados con el tema principal, con el fin
de que sirvan de guía o refuerzo si desconoce algún tema en particular.
El cuarto capitulo “Solución Propuesta”, se describe el ciclo completo de construcción de la
solución, desde la definición de sus requerimientos, el diseño de cada funcionalidad
requerida y su implementación con el lenguaje C
El quinto capitulo “Resultados y Verificación Experimental”, documenta los resultados de
las pruebas realizadas luego de construida la solución, demostrando que el producto es
operable de acuerdo a los alcances definidos.
El capitulo sexto “Conclusiones y Futuras Lineas de Investigación” presenta las
conclusiones generales después de construir el producto, así como se propone una serie de
temas que por motivos de tiempo no se han incluido en este documento, pero que se
estiman pueden ser desarrollados extendiendo la funcionalidad del prototipo planteado.
El capitulo séptimo “Bibliografía y Referencias Estudiadas”, lista la bibliografía utilizada
como fuente para este proyecto.
Maestría en Informática Aplicada a Redes
Página 9 de 159
II. Justificación del Tema
2.1 Antecedentes Los procesos de desarrollo de software, han evolucionado en los últimos años. Esto debido
en gran medida a la cantidad alarmante de proyectos de este tipo que no se desarrollan de
acuerdo a lo planeado, o, finalizan en fracasos. Una muestra de esto se puede apreciar en la
siguiente gráfica la cual es resultado de una investigación del Standish Group en los estados
unidos, donde se recolecto información de mas de 30,000 proyectos de pequeña, mediana y
grandes empresas.
Se puede observar en la gráfica que se presentan para los años 1994, 1995, 1998 y 2000 los
porcentajes de proyectos los cuales han sido clasificados de la siguiente manera:
• Failed: Estos son proyectos que fueron abortados, suspendidos o finalizaron en un
fracaso de acuerdo a los objetivos planteados.
• Challenged: Estos son proyectos que si bien finalizaron , consumieron mas de los
recursos planeados originalmente , excediendose principalmente en tiempo o
presupuesto.
• Succeeded: Estos son los proyectos que finalizaron existomente utilizando los
recursos planeados originalmente.
2000
1998
1995
1994
28% 23% 49%
26% 28% 46%
27% 40% 33%
16% 31% 53%
Succeeded Challenged Failed
Maestría en Informática Aplicada a Redes
Página 10 de 159
Esta situación origino el estudio, documentación, estandarización y difusión de las
conocidas buenas practicas para el desarrollo de software. Tomando como base las
investigaciones realizadas por el Instituto de Ingeniería del Software SIE solicitado por el
Departamento de Defensa de los Estados Unidos que dieron origen al modelo de capacidad
de madures CMM2 y sus sucesores SW-CMM y el actual CMMI que sirve como base a
metodologías de desarrollo como el Rational Unified Process y el Microsoft Solution
Framework.
Estas nuevas metodologías al igual que el CMMI sugieren llevar en el proceso de desarrollo
de software una administración de requerimientos, control de cambios y otras
características que garantizan un estricto control del proyecto para llevarlo a ser exitoso. El
RUP y el MSF son las metodologías disponibles en nuestro medio y que lentamente son
adoptadas por las instituciones y empresas, ambas sugieren la creación de una serie de
roles con responsabilidades bien definidas, en estos se aprecia que el rol del desarrollador
sin bien y obviamente es necesario no tiene tanta importancia como los roles de Arquitectos
de la solución, ingenieros de requerimientos o Diseñadores, ya que son ellos los que
conciben la solución la conceptualizan y modelan, dejando al final prácticamente un
completo manual de que es lo que se debe de construir, donde se han evaluado ya los
aspectos de arquitectura, seguridad etc. Entonces el desarrollador viene solo a seguir las
indicaciones de que lo que se construirá y como se hará .(Debe de tenerse en cuenta que en
proyectos pequeños o con pocos recursos, ambos roles diseñador y desarrollador los podría
ejecutar la misma persona). Dadas las necesidades de robustez, reusabilidad, etc. al
momento de diseñar y construir la solución se utiliza un enfoque orientado a objetos
aunque este posteriormente pueda evolucionar a una orientación a Aspectos o Servicios.
El diseñador o arquitecto de la solución, podría entonces concebir un modelo de la solución
completamente orientado a objetos, utilizando herencias, polimorfismos, encapsulamiento,
etc. Sin embargo al intentar persistir dichos objetos para hacerlo de forma transparente se
requeriría la utilización de una Base de Datos Orientada a Objetos, lo cual es poco usual ya
2 Para mayor información sobre CMM remitirse a la sección 3.5.1
Maestría en Informática Aplicada a Redes
Página 11 de 159
que la tecnología de almacenamiento mas utilizada son las bases relacionales como Oracle,
SQL Server, Sybase, MySQl, etc. Así que con un diseño orientada a objetos al momento
realizar la persistencia el Desarrollador deberá ver como se las arregla para realizar el
mapeo entre clases y tablas y generar las operaciones transaccionales necesarias.
Naturalmente esta operación le consumirá una considerable cantidad de tiempo.
Los motores de persistencia o también denominados O/R Mapping implementan una capa
que realiza las transformaciones entre clases y tablas de forma tal que los desarrolladores ya
no deben de invertir tanto tiempo en estas actividades, siendo al final una valiosa
herramienta a utilizar cuando se tiene un diseño orientado a objeto y se desea persistir en
una base de datos relacional.
2.2 Motores de Persistencia y el Framework .Net
Los motores de persistencia han sido utilizados ampliamente en la plataforma Java, donde
productos como Hibernate, TopLink, CocoBase, JRelay son algunos representantes de estos
productos, de hecho Java tiene el estándar JDO que pretende normalizar las operaciones de
persistencia bajo esta plataforma.
En el caso de la plataforma Microsoft, es mas reciente la utilización de este tipo de
tecnologías, sin embargo existen en el mercado opciones comerciales como ORM, Gentle
.Net, etc. Además existe ahora una versión del motor de persistencia de código abierto mas
difundido en el mundo Java “Hibérnate”, que en su versión para el framework .Net es
denominado NHibernate.
Antes de la aparición del Framework 2.0 se hablaba también del producto ObjectSpaces el
cual es un motor de persistencia desarrollado por Microsoft para trabajar únicamente sobre
SQL Server, sin embargo se planeaba que fuera liberado junto con la nueva versión del
framework. A la fecha el framework ya fue liberado pero no se tiene información sobre
ObjectSpaces.
Maestría en Informática Aplicada a Redes
Página 12 de 159
2.3 El porque de la creación de un motor de persistencia para .Net.
Cuando las necesidades de un motor de persistencia son inminentes, las dos opciones son o
construirlo o comprar u adquirir un producto existente. El uso de un producto existente
naturalmente conlleva adaptarse a la forma de trabajo planteada por dicho producto. Por
otro lado la construcción de un motor de este tipo, requiere la inversión de tiempo, el
conocimiento avanzado de técnicas de orientación a objetos, aplicación de patrones de
diseño, etc.
Dado que bajo la plataforma .Net el uso de este tipo de aplicativos no es muy difundida,
siendo sus beneficios muy amplios. La creación y puesta a disposición de una herramienta
de este tipo se espera potencie su uso y promueva el diseño de sistemas completamente
orientados a objetos, además el hecho de dejar documentado el proceso de diseño y
construcción en este documento, se espera pueda servir como un ejercicio académico que
pueda ser utilizado por educadores y desarrolladores para profundizar en el tema y elevar su
nivel.
Finalmente la sola utilización de la herramienta construida por la comunidad de
desarrolladores .Net, se espera tengo un impacto positivo permitiendo la reducción de los
tiempos de desarrollo, la abstracción de modelos de dominio y de acceso a datos
independientes del tipo de base de datos utilizado y en si todas las características que
conlleva el uso de este tipo de herramientas.
Maestría en Informática Aplicada a Redes
Página 13 de 159
III. FUNDAMENTOS TEORICOS
Los fundamentos teóricos plasmados en esta sección describen aquellas técnicas y
disciplinas que están estrechamente relacionadas al tema de los Motores de Persistencia,
iniciando desde la programación orientada a objetos y los patrones de diseño, pasando al
tema de Bases de Datos Orientadas a Objetos, generalidades sobre los motores de
persistencia e introduciendo al tema de Metodologías Iterativas de Desarrollo de Software
donde se habla del CMMI, el RUP y el MSF. Finalmente se termina el capitulo
describiendo algunas características de la plataforma sobre la cuales se implementan los
conceptos antes descritos, es decir la plataforma del Microsoft .Net Framework.
Esta información esta documentada en este capitulo de tal forma que pueda servir como
base al lector para ampliar sobre algunos fundamentos sobre los cuales se ha desarrollado el
presente proyecto.
3.1 Programación Orientada a Objetos
3.1.1 Historia y Evolución.
El modelo orientado a objetos es el modelo teórico que usan la mayoría de los programas
actuales. La programación orientada a objetos comienza en los años sesenta (en los que
aparecieron los primeros lenguajes de este tipo, llamados “Simula I” y “Simula 67”,
desarrollados en el Centro Noruego de Computación, en Oslo). En los primeros 70, aparece
“Smalltalk”, un lenguaje fundamental en la historia de la orientación a objetos.
Sin embargo, es hasta la segunda mitad de los años 80 que la orientación de objetos se
generaliza, convirtiéndose en el estándar predominante en los años 90, con lenguajes tales
como C++ y Java. Su éxito ha sido impulsado por la difusión de otras tecnologías (como la
interfaz gráfica o las arquitecturas distribuidas) que son más fáciles de implementar
mediante este tipo de desarrollo que mediante una programación tradicional.
En la actualidad, la práctica totalidad de los lenguajes de programación que surgen son
orientados a objetos y esta tecnología se ha convertido en el estándar actual de
Maestría en Informática Aplicada a Redes
Página 14 de 159
programación que, a su vez, está generando nuevos desarrollos muy prometedores para el
futuro como, por ejemplo, la programación orientada a aspectos.
La idea de la orientación a objetos es modelar los programas de una forma parecida a cómo
percibimos la realidad. Para la mente humana, el universo está compuesto por una serie de
“objetos” (en el sentido más amplio de la palabra, incluyendo seres vivos, ideas, etc.). Cada
objeto tiene unas características que lo diferencian de los demás y, con cada objeto, se
pueden realizar unas acciones que son propias y específicas del mismo. Así, por ejemplo,
un determinado auto tiene unas características (color rojo, caja de cambios automática,
diesel, etc.) y puede realizar unas determinadas acciones (acelerar, frenar, etc.).
La programación orientada a objetos intenta modelar estos objetos reales con estructuras de
programa, llamadas “objetos de software” o, simplemente, “objetos”. Cada uno de estos
objetos de software, está compuesto por una serie de características (llamadas “atributos”) y
una serie de acciones (llamadas “métodos”), al igual que un objeto de la vida real.
La OO aporta un enfoque nuevo, convirtiendo la estructura de datos en el centro sobre el
que pivotan las operaciones. De esta forma, cualquier modificación de la estructura de
datos tiene efecto inmediato sobre las acciones a realizar sobre ella, siendo esta una de las
diferencias radicales respecto a la programación estructurada.
En esta forma de diseño se descomponen los requerimientos del programa paso a paso,
hasta llegar a un nivel que permite expresarlos mediante procedimientos y funciones. La
OO estructura los datos en objetos que pueden almacenar, manipular y combinar
información.
3.1.2 Ventajas de la OO
La OO proporciona las siguientes ventajas sobre otros lenguajes de programación
• Uniformidad. Ya que la representación de los objetos lleva implica tanto el análisis
como el diseño y la codificación de los mismos.
Maestría en Informática Aplicada a Redes
Página 15 de 159
• Comprensión. Tanto los datos que componen los objetos, como los procedimientos
que los manipulan, están agrupados en clases, que se corresponden con las
estructuras de información que el programa trata.
• Flexibilidad. Al tener relacionados los procedimientos que manipulan los datos con
los datos a tratar, cualquier cambio que se realice sobre ellos quedará reflejado
automáticamente en cualquier lugar donde estos datos aparezcan.
• Estabilidad. Dado que permite un tratamiento diferenciado de aquellos objetos que
permanecen constantes en el tiempo sobre aquellos que cambian con frecuencia
permite aislar las partes del programa que permanecen inalterables en el tiempo.
• Reusabilidad. La noción de objeto permite que programas que traten las mismas
estructuras de información reutilicen las definiciones de objetos empleadas en otros
programas e incluso los procedimientos que los manipulan. De esta forma, el
desarrollo de un programa puede llegar a ser una simple combinación de objetos ya
definidos donde estos están relacionados de una manera particular.
Uno de los puntos clave a remarcar es que la programación orientada a objetos no sustituye
a ninguna metodología ni lenguaje de programación anterior. Todos los programas que se
realizan según OOD se pueden realizar igualmente mediante programación estructurada. Su
uso en la actualidad se justifica porque el desarrollo de todas las nuevas herramientas
basadas en un interfase de usuario gráfico como Windows, OS/2, x-Windows, etc. Es
mucho más sencillo
3.1.3 Características de los Objetos
3.1.3.1 Identidad del Objeto La identidad expresa que aunque dos objetos sean exactamente iguales en sus atributos, son
distintos entre sí. De esta forma incluso una serie de Objetos vehiculo, recién fabricados
son distintos los unos de los otros.
La afirmación anterior, aunque parece obvia, tiene importancia cuando descendemos al
nivel de programación. En este ámbito cada uno de los objetos tiene un controlador pro el
Maestría en Informática Aplicada a Redes
Página 16 de 159
cual se identifica. Este puede ser una variable, una estructura de datos, una cadena de
caracteres, etc. El controlador será distinto para cada uno de los objetos, aunque las
referencias a éstos sean uniformes e independientes del contenido, permitiendo crear
agrupaciones de objetos con el mismo tratamiento.
3.1.3.2 Abstracción Cada objeto en el sistema sirve como modelo de un "agente" abstracto que puede realizar
trabajo, informar y cambiar su estado, y "comunicarse" con otros objetos en el sistema sin
revelar cómo se implementan estas características. Los procesos, las funciones o los
métodos pueden también ser abstraídos y cuando lo están, una variedad de técnicas son
requeridas para ampliar una abstracción
3.1.3.3 Clasificación Con la clasificación comienza la verdadera programación orientada a objetos. Ellos nos
obliga a una abstracción del concepto de objeto denominada clase.
Las clases permiten la agrupación de objetos que comparten las mismas propiedades y
comportamiento.
El esfuerzo del programador ante una aplicación orientada a objetos se centra en la
identificación de las clases, sus atributos y operaciones asociadas y que son estas realmente
las que modelan la realidad de la aplicación a construir.
Las propiedades de cada clase deben cumplir una serie de premisas
• Las propiedades deber ser significativas dentro del entorno de la aplicación es decir,
deben servir para identificar claramente y de una manera única (y univoca) a cada
uno de los objetos
• El número de propiedades de un objeto debe ser el mínimo para realizar todas las
operaciones que requiera la aplicación.
Maestría en Informática Aplicada a Redes
Página 17 de 159
3.1.3.4 Encapsulación y ocultación de datos
La capacidad de presentación de información dentro de un objeto se divide en dos partes
bien diferenciadas:
• Interna: La información que necesita el objeto para operar y que es innecesaria para
los demás objetos de la aplicación. Estos atributos se denominada privados y tienen
como marco de aplicación únicamente a las operaciones asociadas al objeto.
• Externa La que necesitan el resto de los objetos para interactuar con el objeto que
definimos . Estas propiedades se denominan públicas y corresponde a la
información que necesitan conocer los restantes objetos de la aplicación respecto
del objeto definido para poder operar.
Podemos imaginarla encapsulación como introducir el objeto dentro de una caja negra
donde existen dos ranuras denominadas entrada y salida. Si introducimos datos por la
entrada automáticamente obtendrá un resultado en la salida. No necesita conocer ningún
detalle del funcionamiento interno de la caja.
El término encapsulación indica la capacidad que tienen los objetos de construir una
cápsula a su alrededor, ocultando la información que contienen (aquélla que es necesaria
para su funcionamiento interno, pero innecesaria para los demás objetos) a las otras clases
que componen la aplicación.
Aunque a primera vista la encapsulación puede parecer superflua, tengamos en cuenta que
existen muchas variables utilizadas de forma temporal: contadores y variables que
contienen resultados intermedios, etc. De no ser por la encapsulación estas variables
ocuparían memoria y podrían interferir en el funcionamiento del resto de los objetos.
La encapsulación no es exclusiva de los lenguajes de programación orientados a objetos.
Aparece en los lenguajes basados en procedimientos (PASCAL, C, COBOL, ETC) como
una forma de proteger los datos que se manipulan dentro de las funciones.
Maestría en Informática Aplicada a Redes
Página 18 de 159
Los lenguajes OOP incorporan la posibilidad de encapsular también las estructuras de datos
que sirven como base a las funciones. Aportan por tanto un nivel superior en cuanto a
protección de información.
La encapsulación nos permite el uso de librerías de objetos para el desarrollo de nuestros
programas. Recordemos que las librerías son definiciones de objetos de propósito general
que se incorporan a los programas. Al ser el objeto parcialmente independiente en su
funcionamiento del programa en donde está definido, ya que contiene y define todo lo que
necesita para poder funcionar, es fácil utilizarlo en los mas variados tipos de aplicaciones.
Si aseguramos , depurando las propiedades y las operaciones dentro de la clase que el
objeto función bien dentro de una aplicación, con una correcta encapsulación el objeto
podrá funcionar en cualquier otra.
Otra de las ventajas de la encapsulación, es que al definir el objeto como una caja negra
con entradas y salida asociadas, en cualquier momento podemos cambiar el contenido de
las operaciones del objeto, de manera que no afecte al funcionamiento general del
programa.
La encapsulación está en el núcleo de dos grandes pilares de la construcción de sistemas;
mantenibilidad y reusabilidad
3.1.3.5 Mantenibilidad
Cualidad que indica que un programa o sistema debe ser fácilmente modificable. Es decir
que los cambios en las condiciones externas (como la definición de una nueva variable)
implicarán modificaciones pequeñas en el programa / sistema. El concepto de
mantenibilidad implica que un programa, al igual que un ser vivo debe ser capaz de
adaptarse a un medio ambiente siempre cambiante.
Maestría en Informática Aplicada a Redes
Página 19 de 159
3.1.3.6 Reusabilidad
Cualidad que nos indica que partes del programa ( en este caso objetos) pueden ser
reutilizados en la confección de otros programas. Ello implica que los objetos definidos en
un programa pueden ser extraídos del mismo e implantados en otro sin tener que realizar
modificaciones importantes en el código del objeto.
3.1.3.7 Poliformismo
El polimorfismo es una nueva característica aportada por la OOP. Esta propiedad indica la
posibilidad de definir varias operaciones con el mismo nombre, diferenciándolas
únicamente en los parámetros de entrada. Dependiendo del objeto que se introduzca como
parámetro de entrada, se elegirá automáticamente cual de las operaciones se va a realizar.
Ya está habituado al operador <<suma>> que está presente en todos los lenguajes de
programación. Sin embargo, los operadores <<suma de fracciones>> y <<suma de números
complejos>> no existen en casi ningún lenguaje de programación.
Los lenguajes OOP permiten definir un operador <<suma>> tal que reconozca que tipo de
objeto se le está aplicando, a través de operaciones de objetos. Previamente deberá definir
la fracción y el número complejo como una clase y la operación suma como una operación
de una clase.
Definiendo adecuadamente las operaciones suma de fracciones y suma de números
imaginarios, el operador suma devolverá, en el caso que los operandos sean fracciones, una
fracción y , en el caso de los números imaginarios, otros número imaginario.
Es posible extender el concepto e incluso definir operaciones como suma de bases de datos
3.1.3.8 Herencia
Maestría en Informática Aplicada a Redes
Página 20 de 159
La herencia es la última de las propiedades relativas a la OOP, Consiste en la propagación
de los atributos y las operaciones a través de distintas sub-clases definidas a partir de una
clase común.
Introduce, por tanto, una posibilidad de refinamiento sucesivo del concepto de clase. Nos
permite definir una clase principal y , a través de sucesivas aproximaciones, cualquier
característica de los objetos. A partir de ahora definiremos como sub-clases todas aquellas
clases obtenidas mediante refinamiento de una (o varias) clases principales.
La herencia nos permite crear estructuras jerárquicas de clases donde es posible la creación
de sub-clases que incluyan nuevas propiedades y atributos. Estas sub-clases admiten la
definición de nuevos atributos, así como crear, modificar o inhabilitar propiedades.
Posibles modelos.
Además, es posible que una sub-clase herede atributos y propiedades de más de una clase.
Este proceso se denomina herencia múltiple
La herencia es, sin duda alguna, una de las propiedades más importantes de la OOP, ya que
permite, a través de la definición de una clase básica, ir añadiendo propiedades a medida
que sean necesarias y, además, en el sub-conjunto de objetos que sea preciso.
La herencia permite que los objetos puedan compartir datos y comportamientos a través de
las diferentes sub-clases, sin incurrir en redundancia. Más importante que el ahorro de
código, es la claridad que aporta al identificar que las distintas operaciones sobre los
objetos son en realidad una misma cosa.
3.1.3.9 Conclusión. Identidad, clasificación, polimorfismo y herencia caracterizan a los lenguajes orientados a
objetos. Cada uno de estos conceptos puede utilizarse aisladamente, incluso aparecen en
otras metodologías de programación, pero juntos se complementan en una relación
sinérgica. Los beneficios de la programación orientada a objetos son más que los que
pueden verse a simple vista. El énfasis en las propiedades esenciales de un objeto, fuerza al
Maestría en Informática Aplicada a Redes
Página 21 de 159
desarrollador a pensar cuidadosamente que es un objeto y que es lo que hace con el
resultado de que el sistema es normalmente más preciso, general y robusto que si
pusiéramos el énfasis en los procedimientos y los datos por separado.
3.2 Patrones de Diseño
Un patrón de diseño es una solución a un problema de diseño no trivial que es efectiva (ya
se resolvió el problema satisfactoriamente en ocasiones anteriores) y reusable (se puede
aplicar a diferentes problemas de diseño en distintas circunstancias).
Los patrones son soluciones de sentido común que deberían formar parte del conocimiento
de un diseñador experto. Además facilitan la comunicación entre diseñadores, pues
establecen un marco de referencia (terminología, justificación). Los patrones son una
manera de resolver problemas del desarrollo del software, fruto de la experiencia
acumulada de muchos desarrolladores. Esto garantiza que el patrón no es simplemente una
abstracción teórica, sino que realmente soluciona el problema planteado y ha sido probado
miles y miles de veces por lo que es altamente fiable y estable para la solución del
problema especifico.
En la programación orientada a objetos resulta complicado descomponer el sistema en
objetos (encapsulación, granularidad, dependencias, flexibilidad, reusabilidad, etc.), los
patrones de diseño nos permitirán identificar a los objetos apropiados de una manera mucho
más sencilla. También nos permitirán determinar la granularidad de los objetos.
Los patrones permiten
• Ante un problema reiterado ofrece una solución contrastada que lo resuelve.
• Describe el problema en forma sencilla.
• Describe el contexto en que ocurre.
• Describe los pasos a seguir.
Maestría en Informática Aplicada a Redes
Página 22 de 159
• Describe los puntos fuertes y débiles de la solución.
• Describe otros patrones asociados
En general un patrón tiene cuatro elementos fundamentales:
• El Nombre del Patrón, describe la forma en que podemos manejar un problema sus
soluciones y consecuencias descritas en una o dos palabras
• El problema describe cuando aplicar dicho patrón. Explica el problema y su
contexto. Puede exponer problemas específicos de diseño tales como representar
algoritmos como objetos. En algunas ocasiones se incluyen también listas de
condiciones que deben de ser conocidas antes de decidir aplicar este diseño
• La solución, describe los elementos que componen el diseño, sus relaciones,
responsabilidades y colaboración. La solución no describe un diseño concreto
particular o su implementación, esto es debido a que un patrón es mas como una
plantilla que puede ser aplicada en muchas situaciones. En ves de eso, el patrón
provee una descripción abstracta del diseño de un problema
• Las consecuencias, estas son el resultado de la aplicación del patrón. Las
consecuencias, son elementos críticos al momento de evaluar las alternativas de
diseño
3.2.1 Historia
El reciente interés del mundo del software por los patrones tiene su origen, a partir de 1995,
tras la aparición y el éxito del libro "Design Patterns: Elements of Reusable Object-
Oriented Software" de la banda de los cuatro. Ellos, Erich Gamma, Richar Helm, Ralph
Johnson y John Vlissides, se dedicaron a recopilar una serie de patrones (23) aplicados
habitualmente por expertos diseñadores de software orientado a objetos, y al hacerlos
públicos.
Podemos mencionar otros autores que han contribuido a este tema como Craig Larman,
quien ha definido de los patrones GRASP (patrones generales de software para asignar
responsabilidades
Maestría en Informática Aplicada a Redes
Página 23 de 159
3.2.2 Conceptos Clave
Resulta difícil hablar de patrones de diseño, sin retomar dos términos que son un objetivo
permanente del diseño orientado a objetos, como son la cohesión y el acoplamiento.
Podríamos definir la cohesión de una clase (o de un paquete, etc.) como la relación entre
los distintos elementos de la clase, normalmente sus métodos. Es decir, que todos los
elementos de una clase tienen que trabajar en la misma dirección, es decir, hacia un mismo
fin. Por ejemplo, una clase "Coche" debería ocuparse de cosas relacionadas con el coche en
si, como acelerar y frenar, pero no de cosas ajenas a él como manipular información
referente a su seguro. La cohesión es una medida relativa, en el sentido de que depende de
lo que cada uno piense que es la función de la clase, pero lo importante es mantener una
cohesión lo mas alta posible. Existen diferentes tipos de cohesión (funcional, secuencial,
etc.),
Respecto al acoplamiento, podemos decir que es la interdependencia existente entre dos
clases, paquetes, etc. Esto ocurre normalmente cuando una clase (o paquete) necesita saber
demasiados detalles internos de otra para su funcionamiento, es decir, rompe el
encapsulamiento del que tanto se habla en la programación orientada a objetos. También
existen diversos tipos de acoplamiento (funcional, de datos, etc.), lo que nos lleva a la
conclusión que para tener un diseño correcto, fácil de mantener y modular, cuanto más
bajo acoplamiento haya entre las clases (o paquetes), pues mejor.
3.2.3 Tipos de Patrones
La banda de los cuatro (GoF) definió tres tipos distintos de patrones fundamentales:
• patrones de creación.
• patrones estructurales.
• patrones de comportamiento
Maestría en Informática Aplicada a Redes
Página 24 de 159
3.2.3.1 Patrones Creacionales
Los patrones de creación son las soluciones aceptadas como "buenas" a los problemas de
creación de instancias de objetos. Los programas orientados a objetos crean decenas,
cientos o incluso miles de instancias de objetos, es por ello, que esta no es una tarea que se
puede realizar a la ligera.
Nuestros programas no deben depender de la forma en que se crean y organizan los objetos.
Por supuesto que podemos utilizar el operador new cada vez que necesitemos, pero en
ocasiones eso puede hacer nuestro software realmente difícil de mantener.
Además, en muchos casos, puede ocurrir que el objeto concreto que necesitemos en un
momento concreto dependa del estado de nuestra aplicación en tiempo de ejecución. Por
ejemplo, puede ocurrir que en un momento tengamos que dibujar un círculo o un cuadrado,
pero no por ello tenemos que llenar nuestro software de sentencias if. El crear clases
especiales que abstraen el proceso de creación de instancias hace que nuestro software sea
más flexible y general.
Ejemplos de estos patrones son:
• Patrón Factoría
• Patrón Factoría Abstracta
• Patrón Singleton (Instancia Única)
• Patrón Prototipo
3.2.3.2 Patrones Estructurales
Los patrones estructurales se ocupan de la combinación de objetos para crear estructuras
complejas. Esto no es del todo exacto, ya que hay patrones estructurales que se encargan de
las relaciones entre clases (mayoritariamente el uso de la herencia), mientras que otros se
encargan de los objetos, las instancias de las clases (normalmente composición).
Destacan entre este tipo de patrones, el patrón adaptador (adapter pattern, GoF), el patrón
fachada (facade pattern, GoF), el patrón proxy (proxy pattern, GoF) y el patrón puente
(bridge pattern, GoF).
Maestría en Informática Aplicada a Redes
Página 25 de 159
3.2.3.3 Patrones de Comportamiento
Los patrones de comportamiento estudian las relaciones entre llamadas entre los diferentes
objetos, normalmente ligados con la dimensión temporal
Entre este tipo de patrones, tenemos:
• Patrón Cadena de Responsabilidad
• Patrón Comando
• Patrón Intérprete
• Patrón Iterador
• Patrón Mediador
• Patrón Recuerdo (Memento)
• Patrón Observador
• Patrón Estado
• Patrón Estrategia
• Patrón Plantilla
• Patrón Visitante
3.2.4 Patrones de Acceso a Datos Asi como los patrones de diseño, implementan soluciones a problemas comunes, los
patrones de acceso a datos tienen un rol similar en el campo del acceso a datos. Estos
patrones, describen una abstracción común a problemas a soluciones que pueden ser
aplicadas directamente a problemas relacionados con la obtención y persistencia de la
información. Algunos de estos patrones son aplicados o utilizados ampliamente en una
variedad de productos comerciales como en los casos de los patrones Resource pool y
Object/Relational Map. Otros de estos patrones, son menos utilizados o conocidos, de igual
forma ofrecen una amplia gama de soluciones a problemas relacionados con los datos.
Muchos de estos patrones, son adaptaciones de los patrones fundamentales a problemas
específicos del área de acceso a datos. De este tipo de patrones también existe una
categorización la cual se muestra a continuación:
Maestría en Informática Aplicada a Redes
Página 26 de 159
• Decoupling Patterns: describen estrategias para separar el acceso a datos de otras
responsabilidades de la aplicación. Esta acción de separación brinda flexibilidad
cuando se selecciona un modelo subyacente de datos o cuando se realizan cambios a
la estrategia completa de acceso a datos. Algunos de estos patrones son:
o Data Accesor
o Active Domain Object
o Object/Relational Map
o Layer
• Resource Patterns: describen estrategias para administrar los objetos envueltos en
relaciones de acceso a datos. Entre estos patrones tenemos:
o Resource Decorador
o Resource Pool
o Resource Timer
o Resource Descriptor
o Retraer
• Input/output patterns: Describen patrones que simplifican las operaciones de
entrada y salida, usando una tranlación consistente en información relacional y la
representación de los Domain objects. Entre estos patrones tenemos:
o Selection Factory
o Domain Object Factory
o Update Factory
o Domain Object Assembler
o Paging Iterator
• Cache Patterns: brindan soluciones que reducen la frecuencia de las operaciones
de acceso a datos, almacenado informacion comun en cache. Estos patrones
generalmente almacenan Domain object mas que información relacional. Entre
estos patrones tenemos:
o Cache Accessor
o Demand Cache
o Primed Cache
Maestría en Informática Aplicada a Redes
Página 27 de 159
o Cache Search Sequence
o Cache Collector
o Cache Replicator
o Cache Statistics
• Concurrency Patterns: ofrecen soluciones para el acceso multiple o concurrente a
información comun en una base datos. La mayoria de base de datos ofrecen
operaciones de locking para permitir y ayudar con este problema, sin embargo la
utilización de código que maneje este problema desde la aplicación, puede ser
tuneado para necesidades especificas. Algunos patrones representantivos de este
grupo son:
o Transaction
o Optimistic Lock
o Pessimistic Lock
o Compensating
3.2.5 El patrón Singleton Este patrón asegura que sólo una instancia de la clase es creada. Todos los objetos que usan
una instancia de esa clase, usan la misma instancia.
Algunas clases deben tener exactamente una instancia. Estas clases usualmente involucran
la administración centralizada de algún recurso. Por ejemplo, si se necesita escribir una
clase que un applet pueda usar para asegurar que no más de un clip de audio sea ejecutado
al mismo tiempo. Para evitar que dos clips de audio sean ejecutados al mismo tiempo, la
clase que usted escribe debe dejar de ejecutar un clip de audio antes de empezar a ejecutar
el siguiente. Una forma de lograr esto, es asegurar que solamente exista una instancia de la
clase, compartida por todos los objetos que usan la clase. La siguiente figura muestra el
diagrama de clases.
Maestría en Informática Aplicada a Redes
Página 28 de 159
Se debe de recordar que "+" significa que la característica es pública, y "-" significa que la
característica es privada. Una característica subrayada indica que es estática.
El constructor de la clase es privado. Esto previene que otras clases creen directamente una
instancia de la clase. En lugar de eso, para acceder a una instancia de la clase deben usar el
método getInstance. Este método es estático, y siempre regresa la misma instancia de la
clase. La siguiente figura muestra el diagrama de clases general de este patrón.
3.2.6 El Patrón Factory
Si consideramos el problema de crear un framework para el desarrollo de aplicaciones para
PC (tipo MSOffice). Estas aplicaciones están generalmente organizadas de una forma
"centradas en documentos" (o "centradas en archivos"). Las operaciones usualmente
empiezan con un comando para crear o editar un documento (del procesador de texto, la
planilla electrónica, etc.). En el caso de un editor de texto, además el editor puede
reconocer diferentes tipos de archivos. Un framework que apoye este tipo de aplicaciones
Maestría en Informática Aplicada a Redes
Página 29 de 159
debe incluir operaciones comunes de alto nivel, como crear, abrir o guardar documentos.
Supongamos que queremos crear los métodos de la clase Application. La mayoría de los
métodos de esta clase varían según el tipo de documento. Debido a esto, la clase
Application usualmente delega la mayoría de los comandos a algún tipo de objeto
documento. Además, la lógica de las operaciones del objeto documento puede variar según
el tipo de documento. Sin embargo, hay operaciones, como por ejemplo desplegar el string
con el título del documento o desplegar una imagen .gif, que son comunes para todos los
objetos documento. Esto sugiere una organización que incluya una clase abstracta
Document independiente de la aplicación, para especificar los tipos de documentos.
Esta organización es mostrada en la siguiente figura.
Lo que no queda claro aun, es cómo un objeto Application puede crear instancias de clases
de documentos específicos para esa aplicación, sin ser ella misma una aplicación específica.
Para lograr esto, se puede encapsular la lógica e instanciar subclases de la clase Document
específicas a la aplicación en una interfaz. La siguiente figura muestra esta nueva
organización.
Maestría en Informática Aplicada a Redes
Página 30 de 159
Usando la organización de la figura anterior, un objeto Application llama al método
createDocument de un objeto que implementa la interfaz DocumentFactoryIF. Éste le pasa
un string al método createDocument que le dice al método cuál subclase de la clase
Document debe instanciar.
El patrón Fáctory provee un objeto independiente de la aplicación con un objeto específico
a la aplicación, al cual delega la creación de otros objetos específicos a la aplicación. La
siguiente figura muestra el diagrama general de este patrón.
Maestría en Informática Aplicada a Redes
Página 31 de 159
Los roles que las clases e interfaz de la figura anterior juegan son los siguientes:
Product. Una clase en este rol es la superclase abstracta de objetos producidos por
el patrón Factory.
Concrete Product. Cualquier clase concreta instanciada por los objetos que
participan en este patrón.
Creation Requestor. El objeto que requiere la creación, es una clase independiente
de la aplicación que necesita crear clases específicas a la aplicación. Esto lo hace
indirectamente a través de una instancia de la clase Factory.
Factory IF. Es una interfaz independiente de la aplicación. Los objetos que crean
productos usando CreationRequestor deben implementar esta interfaz. Las
interfaces de este tipo declaran un método que es llamado por un objeto
CreationRequestor para crear productos concretos.
Factory Class. Es una clase específica a la aplicación que implementa la interfaz de
fábrica adecuada, y tiene un método para crear productos concretos.
Maestría en Informática Aplicada a Redes
Página 32 de 159
3.2.7 El Patrón Abstract Factory
Este patrón es también conocido como Kit o Toolkit. Dado un conjunto de clases
relacionadas, el patrón Fábrica Abstracta provee una forma de crear instancias de estas
clases desde un conjunto acoplado de subclases concretas.
Supongamos que tenemos que construir un framework para crear interfaces de usuario, que
trabajen sobre múltiples plataformas gráficas (MS-Windows, Motif, MacOS, etc.). Cada
plataforma tiene una forma nativa de desplegar cada componente (look and feel). Para
construir el framework, se puede crear una clase abstracta para cada tipo de objeto (texto,
botones, listas, etc.) y luego reescribir una subclase concreta de cada clase de objeto para
cada plataforma. Para hacerlo robusto, hay que asegurarse además que todos los objetos
creados son de la plataforma deseada. En esta situación, una clase fábrica abstracta define
métodos para crear una instancia de cada clase abstracta que representa un objeto de la
interfaz de usuario. Fábricas concretas son subclases concretas de una fábrica abstracta que
implementa sus métodos para crear instancias de clases de objetos concretos para una
misma plataforma.
En un contexto más general, una clase de fábrica abstracta y sus subclases concretas,
organizan conjuntos de clases concretas que trabajan con productos diferentes, pero
relacionados entre sí. La siguiente figura muestra el diagrama general de este patrón.
Maestría en Informática Aplicada a Redes
Página 33 de 159
Los roles del la imagen anterior son los siguientes:
Client. Las clases en el rol del cliente (Client) usan varias clases de objetos (widgets) para
solicitar servicios del producto con el que el cliente está trabajando. Las clases cliente
solamente conocen las clases de objetos (widgets) abstractos, y no necesitan conocer las
clases concretas.
AbstractFactory. Las clases AbstractFactory definen métodos abstractos para crear
instancias de clases de objetos concretas. Tienen un método estático getFactory el cual es
llamado por los objetos Client para tener una instancia de una fábrica concreta, apropiada
para crear widgets que trabajan con un producto particular.
ConcreteFactory1, ConcreteFactory2. Estas clases implementan los métodos definidos
por la superclase de la fábrica abstracta, para crear instancias de widgets concretos. Las
clases cliente que llaman estos métodos no necesitan tener conocimiento directo de estas
clases de fábrica concretas. En lugar de esto, accesan instancias de estas clases como
instancias de la superclase fábrica abstracta.
Maestría en Informática Aplicada a Redes
Página 34 de 159
WidgetA, WidgetB. Son clases abstractas que corresponden a características de un
producto con el que trabaja la subclase concreta. Se conocen como widgets abstractos.
Product1WidgetA, Product2WidgetA. Son clases concretas que corresponden a
características de un producto con el que trabajan. Se conocen como widgets concretos
3.2.8 El Patron Data Accessors
El patrón Data Accessor encapsula los detalles del acceso físico a datos en una componente
simple, exponiendo únicamente las operaciones lógicas vitales. El código de la aplicación
debe mantener el conocimiento del modelo de datos pero, es separado a traves del uso de
este patron, de cualquier responsabilidad de acceso a datos. La estructura estática de este
patrón, es mostrada en la siguiente figura:
3.2.9 Patron DAO (Data Access Object)
3.2.9.1 Origenes de DAO Este patrón ha sido tomado de las especificaciones J2EE de la plataforma Java, su utilidad
y beneficios son altos por lo que será aplicado en la construcción de nuestro prototipo.
Maestría en Informática Aplicada a Redes
Página 35 de 159
3.2.9.2 Contexto y Aplicación.
Muchas aplicaciones en el mundo real necesitan utilizar datos persistentes en algún
momento. Para muchas de ellas, este almacenamiento persistente se implementa utilizando
diferentes mecanismos, y hay marcadas diferencias en los APIS utilizados para acceder a
esos mecanismos de almacenamiento diferentes. Otras aplicaciones podrían necesitar
acceder a datos que residen en sistemas diferentes. Por ejemplo, los datos podrían residir en
sitemas mainframe, repositorios LDAP, etc. Otro ejemplo es donde los datos los
proporcionan servicios a través de sistemas externos como los sistemas de integración
negocio-a-negocio (B2B), servicios de tarjetas de crédito, etc.
Normalmente, las aplicaciones utilizan componentes distribuidos y compartidos como los
beans de entidad para representar los datos persistentes en la plataforma Java. Se considera
que una aplicación emplea consistencia manejada por el bean (BMP) cuando sus beans de
entidad acceden explícitamente al almacenamiento persistente -- el bean de entidad incluye
código para hacer esto. Una aplicación con requerimientos sencillos podría por lo tanto
utilizar beans de entidad en lugar de beans de sesión o servlets para acceder al
almacenamiento persistente y recuperar o modificar los datos. O, la aplicación podría usar
beans de entidad con persistencia manejada por el contenedor, y así dejar que el contenedor
maneje los detalles de las transacciones y de la persistencia.
Utilizar un Data Access Object (DAO) para abstraer y encapsular todos los accesos a la
fuente de datos. El DAO maneja la conexión con la fuente de datos para obtener y
almacenar datos.
El DAO implementa el mecanismo de acceso requerido para trabajar con la fuente de datos.
Esta fuente de datos puede ser un almacenamiento persistente como una RDMBS, un
servicio externo como un intercambio B2B, un repositorio LDAP, o un servicio de
negocios al que se accede mediante CORBA Internet Inter-ORB Protocol (IIOP) o sockets
de bajo nivel. Los componentes de negocio que tratan con el DAO utilizan un interface
simple expuesto por el DAO para sus clientes. El DAO oculta completamente los detalles
de implementación de la fuente de datos a sus clientes.
Maestría en Informática Aplicada a Redes
Página 36 de 159
Como el interface expuesto por el DAO no cambia cuando cambia la implementación de la
fuente de datos subyacente, este patrón permite al DAO adaptarse a diferentes esquemas de
almacenamiento sin que esto afecte a sus clientes o componentes de engocio.
Esencialmente, el DAO actúa como un adaptador entre el componente y la fuente de datos.
La siguiente figura muestra el diagrama de clases que representa las relaciones para el
patrón DAO:
La siguiente figura muestra el diagrama de secuencia de la interacción entre los distintos
participantes en este patrón:
Maestría en Informática Aplicada a Redes
Página 37 de 159
• BusinessObject :Representa los datos del cliente. Es el objeto que requiere el acceso a
la fuente de datos para obtener y almacenar datos. Podríamos implementar un
businessObject como un bean de sesión, un bean de entidad o cualquier otro objeto
Java, además de como un Servlet o como un bean de apoyo.
• DataAccessObject: es el objeto principal de este patrón. DataAccessObject abstrae la
implementación del acceso a datos subyacente al BusinessObject para permitirle un
acceso transparente a la fuente de datos. El BusinessObject también delega las
operaciones de carga y almacenamiento en el DataAccessObject.
• DataSource: Representa la implementación de la fuente de datos. Una fuente de datos
podría ser una base de datos como un RDBMS, un OODBMS, un repositorio XML, un
fichero plano, etc. También lo pueden ser otros sitemas (mainframes/legales), servicios
(servicio B2B u oficina de tarjetas de crédito), o algún tipo de repositorio (LDAP).
3.2.9.3 Generación Automática de DAO Como cada BusinessObject corresponde a un DAO específico, es posible establecer
relaciones entre el BusinessObject, el DAO, y las implementaciones subyacentes (como en
las tablas de una RDBMS). Una vez que se han establecido las relaciones, es posible
escribir una utilidad de generación-de-código-específica-de-aplicación que genere el código
para todos los DAOs que necesita la aplicación. Los meta datos para generar el DAO
pueden venir de un fichero descriptor definido por el desarrollador. Como alternativa, el
generador de código puede inspeccionar la base de datos y proporcionar los DAOs
necesarios para acceder a ella.
Si los requerimientos de los DAOs son lo suficientemente complejos, debemos considerar
la utilización de herramientas de terceras partes que proporcionan un mapeo de objeto-a-
relacional para bases de datos RDBMS. Estas herramientas normalmente incluyen
utilidades GUI para mapear los objetos de negocio a objetos de almacenamiento persistente
y además definir los DAOs intermedios. Estas herramientas generan el código
automáticamente una vez que se termina el mapeo, y podrían proporcionar otras
características valiosas como el caché de resultados y de consultas, integración con
servidores de aplicaciones, integración con otros productos de terceras partes, etc.
Maestría en Informática Aplicada a Redes
Página 38 de 159
3.2.9.4 Ventajas de DAO Algunas ventajas en la utilización de DAO son las siguientes:
• Permite la Transpariencia Los objetos de negocio puede utilizar la fuente de datos
sin conocer los detalles específicos de su implementación. El acceso es transparente
porque los detalles de la implementación se ocultan dentro del DAO.
• Permite una Migración más Fácil :Una capa de DAOs hace más fácil que una
aplicación pueda migrar a una implementación de base de datos diferente. Los
objetos de negocio no conocen la implementación de datos subyacente, la migración
implica cambios sólo en la capa DAO. Además, si se emplea la estrategia de
factorías, es posible proporcionar una implementación de factorías concretas por
cada implementación del almacenamiento subyacente. En este caso, la migración a
un almacenamiento diferente significa proporcionar a la aplicación una nueva
implementación de la factoría.
• Reduce la Complejidad del Código de los Objetos de Negocio : Como los DAOs
manejan todas las complejidades del acceso a los datos, se simplifica el código de
los objetos de negocio y de otros clientes que utilizan los DAOs. Todo el código
relacionado con la implementación (como las sentencias SQL) están dentro del
DAO y no en el objeto de negocio. Esto mejora la lectura del código y la
productividad del desarrollo.
• Centraliza Todos los Accesos a Datos en un Capa Independiente :Como todas las
operaciones de acceso a los datos se ha delegado en los DAOs, esto se puede ver
como una capa que aísla el resto de la aplicación de la implementación de acceso a
los datos. Esta centralización hace que la aplicación sea más sencilla de mantener y
de manejar.
3.3 Bases de Datos Orientadas a Objetos
Los modelos de bases de datos tradicionales (relacional, red y jerárquico) han sido capaces
de satisfacer con éxito las necesidades, en cuanto a bases de datos, de las aplicaciones de
gestión tradicionales. Sin embargo, presentan algunas deficiencias cuando se trata de
aplicaciones más complejas o sofisticadas como, por ejemplo, el diseño y fabricación en
ingeniería (CAD/CAM, CIM), los experimentos científicos, los sistemas de información
Maestría en Informática Aplicada a Redes
Página 39 de 159
geográfica o los sistemas multimedia. Los requerimientos y las características de estas
nuevas aplicaciones difieren en gran medida de las típicas aplicaciones de gestión la
estructura de los objetos es más compleja, las transacciones son de larga duración, se
necesitan nuevos tipos de datos para almacenar imágenes y textos, y hace falta definir
operaciones no estándar, específicas para cada aplicación.
Las bases de datos orientadas a objetos se crearon para tratar de satisfacer las necesidades
de estas nuevas aplicaciones. La orientación a objetos ofrece flexibilidad para manejar
algunos de estos requisitos y no está limitada por los tipos de datos y los lenguajes de
consulta de los sistemas de bases de datos tradicionales. Una característica clave de las
bases de datos orientadas a objetos es la potencia que proporcionan al diseñador al
permitirle especificar tanto la estructura de objetos complejos, como las operaciones que se
pueden aplicar sobre dichos objetos.
Otro motivo para la creación de las bases de datos orientadas a objetos es el creciente uso
de los lenguajes orientados a objetos para desarrollar aplicaciones. Las bases de datos se
han convertido en piezas fundamentales de muchos sistemas de información y las bases de
datos tradicionales son difíciles de utilizar cuando las aplicaciones que acceden a ellas está
escritas en un lenguaje de programación orientado a objetos como C++, Smalltalk o Java.
Las bases de datos orientadas a objetos se han diseñado para que se puedan integrar
directamente con aplicaciones desarrolladas con lenguajes orientados a objetos, habiendo
adoptado muchos de los conceptos de estos lenguajes.
Los fabricantes de los Sistemas gestores de Base de Datos (SGBD) relacionales también se
han dado cuenta de las nuevas necesidades en el modelado de datos, por lo que las nuevas
versiones de sus sistemas incorporan muchos de los rasgos propuestos para las bases de
datos orientadas a objetos, como ha ocurrido con Informix y Oracle. Esto ha dado lugar al
modelo relacional extendido y a los sistemas que lo implementan se les denomina sistemas
objeto–relacionales. La nueva versión de SQL, SQL:19993, incluye algunas de las
características de la orientación a objetos.
3 Este es el nombre que recibe el estándar. En ocasiones se cita como SQL3 porque así se llamaba el proyecto que lo desarrolló. También se cita como SQL99, por ser un nombre similar al de la versión anterior,
Maestría en Informática Aplicada a Redes
Página 40 de 159
Durante los últimos años se han creado muchos prototipos experimentales de sistemas de
bases de datos orientadas a objetos y también muchos sistemas comerciales. Conforme
éstos fueron apareciendo, surgió la necesidad de establecer un modelo estándar y un
lenguaje.
Para ello, los fabricantes de los SGBD orientadas a objetos formaron un grupo denominado
ODMG (Object Database Management Group), que propuso el estándar ODMG–93 y que
ha ido evolucionando hasta el ODMG 3.0, su última versión. El uso de estándares
proporciona portabilidad, permitiendo que una aplicación se pueda ejecutar sobre sistemas
distintos con mínimas modificaciones. Los estándares también proporcionan
interoperabilidad, permitiendo que una aplicación pueda acceder a varios sistemas
diferentes. Y una tercera ventaja de los estándares es que permiten que los usuarios puedan
comparar entre distintos sistemas comerciales, dependiendo de qué partes del estándar
proporcionan.
3.3.1 El Concepto de Orientación a Objetos
El desarrollo del paradigma orientado a objetos aporta un gran cambio en el modo en que se
ven los datos y los procedimientos que actúan sobre ellos. Tradicionalmente, los datos y los
procedimientos se han almacenado separadamente: los datos y sus relaciones en la base de
datos y los procedimientos en los programas de aplicación. La orientación a objetos, sin
embargo, combina los procedimientos de una entidad con sus datos.
Esta combinación se considera como un paso adelante en la gestión de datos. Las entidades
son unidades auto contenidas que se pueden reutilizar con relativa facilidad. En lugar de
ligar el comportamiento de una entidad a un programa de aplicación, el comportamiento es
parte de la entidad en sí, por lo en cualquier lugar en el que se utilice la entidad, se
comporta de un modo predecible y conocido.
SQL92; sin embargo, este último nombre no se ha utilizado en esta ocasión porque se quiere evitar el efecto 2000 en el nombre de futuras versiones.
Maestría en Informática Aplicada a Redes
Página 41 de 159
El modelo orientado a objetos también soporta relaciones de muchos a muchos, siendo el
primer modelo que lo permite. Aún así se debe ser muy cuidadoso cuando se diseñan estas
relaciones para evitar pérdidas de información.
Por otra parte, las bases de datos orientadas a objetos son navegacionales: el acceso a los
datos es a través de las relaciones, que se almacenan con los mismos datos. Esto se
considera un paso atrás. Las bases de datos orientadas a objetos no son apropiadas para
realizar consultas ad hoc, al contrario que las bases de datos relacionales, aunque
normalmente las soportan. La naturaleza navegacional de las bases de datos orientadas a
objetos implica que las consultas deben seguir relaciones predefinidas y que no pueden
insertarse nuevas relaciones “al vuelo”.
No parece que las bases de datos orientadas a objetos vayan a reemplazar a las bases de
datos relacionales en todas las aplicaciones del mismo modo en que éstas reemplazaron a
sus predecesoras.
Los objetos han entrado en el mundo de las bases de datos de formas:
• SGBD orientados a objetos puros: son SGBD basados completamente en el modelo
orientado a objetos.
• SGBD híbridos u objeto–relacionales: son SGBD relacionales que permiten
almacenar objetos en sus relaciones (tablas).
3.3.2 El Modelo de Datos Orientado a Objetos
El modelo de datos orientado a objetos es una extensión del paradigma de programación
orientado a objetos. Los objetos entidad que se utilizan en los programas orientados a
objetos son análogos a las entidades que se utilizan en las bases de datos orientadas a
objetos puros, pero con una gran diferencia: los objetos del programa desaparecen cuando
el programa termina su ejecución, mientras que los objetos de la base de datos permanecen.
A esto se le denomina persistencia.
Maestría en Informática Aplicada a Redes
Página 42 de 159
En una base de datos orientada a objetos, cualquier cosa es un objeto y se manipula como
tal. Un objeto es una instancia que responde a mensajes activando un método. Los objetos
soportan una serie de características de los mismos :
• Se agrupan en tipos denominados clases
• Contienen datos internos que definen su estado actual
• Soportan ocultación de datos
• Pueden heredar propiedades de otros objetos
• Pueden comunicarse con otros objetos enviando o pasando mensajes
• Tienen métodos que definen su comportamiento
3.3.2.1 Relaciones Las bases de datos relacionales representan las relaciones mediante las claves ajenas.
No tienen estructuras de datos que formen parte de la base de datos y que representen estos
enlaces entre tablas. Las relaciones se utilizan para hacer concatenaciones (join) de tablas.
Por el contrario, las bases de datos orientadas a objetos implementan sus relaciones
incluyendo en cada objeto los identificadores de los objetos con los que se relaciona.
Un identificador de objeto es un atributo interno que posee cada objeto. Ni los
programadores, ni los usuarios que realizan consultas de forma interactiva, ven o manipulan
estos identificadores directamente. Los identificadores de los objetos los asigna el SGBD y
es él el único que los utiliza.
El identificador puede ser un valor arbitrario o puede incluir la información necesaria para
localizar el objeto en el fichero donde se almacena la base de datos. Por ejemplo, el
identificador puede contener el número de la página del fichero donde se encuentra
almacenado el objeto, junto con el desplazamiento desde el principio de la página.
Hay dos aspectos importantes a destacar sobre este método de representar las relaciones
entre datos:
Maestría en Informática Aplicada a Redes
Página 43 de 159
• Para que el mecanismo funcione, el identificador del objeto no debe cambiar
mientras este forme parte de la base de datos.
• Las únicas relaciones que se pueden utilizar para consultar la base de datos son
aquellas que se han predefinido almacenando en atributos los identificadores de los
objetos relacionados. Por lo tanto, una base de datos orientada a objetos pura es
navegacional, como los modelos prerrelaciónales (el modelo jerárquico y el modelo
de red). De este modo se limita la flexibilidad del programador/usuario a aquellas
relaciones predefinidas, pero los accesos que siguen estas relaciones presentan
mejores prestaciones que en las bases de datos relacionales porque es más rápido
seguir los identificadores de los objetos que hacer operaciones de concatenación
(join).
El modelo orientado a objetos permite los atributos multivaluados, agregaciones a las que
se denomina conjuntos (sets) o bolsas (bags). Para crear una relación de uno a muchos, se
define un atributo en la parte del uno que será de la clase del objeto con el que se relaciona.
Este atributo contendrá el identificador de objeto del padre. La clase del objeto padre
contendrá un atributo que almacenará un conjunto de valores: los identificadores de los
objetos hijo con los que se relaciona. Cuando el SGBD ve que un atributo tiene como tipo
de datos una clase, ya sabe que el atributo contendrá un identificador de objeto.
Las relaciones de muchos a muchos se pueden representar directamente en las bases de
datos orientadas a objetos, sin necesidad de crear entidades intermedias. Para representar la
relación, cada clase que participa en ella define un atributo que contendrá un conjunto de
valores de la otra clase con la que se relacionará. Aunque el hecho de poder representar
relaciones de muchos a muchos parece aportar muchas ventajas, hay que tener mucho
cuidado cuando se utilizan. En primer lugar, si la relación tiene datos, será necesario crear
una entidad intermedia que contenga estos datos. Por ejemplo, en la relación de los
artículos con los proveedores, en donde cada proveedor puede tener un precio distinto para
un mismo artículo. En este caso, la relación de muchos a muchos se sustituye por dos
relaciones de uno a muchos, como se haría en una base de datos relacional. En segundo
lugar, se puede diseñar una base de datos que contiene relaciones de muchos a muchos en
Maestría en Informática Aplicada a Redes
Página 44 de 159
donde o bien se pierde información, o bien se hace imposible determinar las relaciones con
precisión. También en estos casos la solución es incluir una entidad intermedia que
represente la relación.
Ya que el paradigma orientado a objetos soporta la herencia, una base de datos orientada
a objetos también puede utilizar la relación “es un” entre objetos. Por ejemplo, en una base
de datos para un departamento de recursos humanos habrá una clase genérica Empleado
con diversos atributos: nombre, dirección, número de la seguridad social, fecha de contrato
y departamento en el que trabaja. Sin embargo, para registrar el modo de pago de cada
empleado hay un dilema. No a todos los empleados se les paga del mismo modo: a algunos
se les paga por horas, mientras que otros tienen un salario mensual. La clase de los
empleados que trabajan por horas necesita unos atributos distintos que la clase de los otros
empleados.
En una base de datos orientada a objetos se deben crear las dos subclases de empleados.
Aunque el SGBD nunca creará objetos de la clase Empleado, su presencia en el diseño
clarifica el diseño lógico de la base de datos y ayuda a los programadores de aplicaciones
permitiéndoles escribir sólo una vez los métodos que tienen en común las dos subclases
(serán los métodos que se sitúan en la clase Empleado).
En teoría, una base de datos orientada a objetos debe soportar dos tipos de herencia: la
relación “es un” y la relación “extiende”. La relación “es un”, que también se conoce como
generalización–especialización, crea una jerarquía donde las subclases son tipos
específicos de las súperclases. Con la relación “extiende”, sin embargo, una clase expande
su súperclase en lugar de estrecharla en un tipo más específico. Por ejemplo, en la jerarquía
de la clase Empleado, al igual que son necesarias clases para los empleados que realizan
cada trabajo específico, hace falta guardar información adicional sobre los directores, que
son empleados pero que también tienen unas características específicas. La base de datos
incluirá una clase Director con un atributo para los empleados a los que dirige. En este
sentido un director no es un empleado más específico sino un empleado con información
adicional.
Maestría en Informática Aplicada a Redes
Página 45 de 159
Una de las cosas que es difícil de manejar en las bases de datos relacionales es la idea de las
partes de un todo, como en una base de datos de fabricación, en la que hace falta saber qué
piezas y qué componentes se utilizan para fabricar un determinado producto. Sin embargo,
una base de datos orientada a objetos puede aprovechar la relación denominada “todo–
parte” en la que los objetos de una clase se relacionan con objetos de otras clases que
forman parte de él. En el caso de la base de datos de fabricación, la clase Producto se
relacionará con las clases Pieza y Componente utilizando una relación “todo–parte”. Este
tipo de relación es una relación de muchos a muchos con un significado especial. Un
producto puede estar hecho de muchas piezas y muchos componentes. Además, una misma
pieza o un mismo componente se puede utilizar para fabricar distintos productos. El
identificar esta relación como “todo–parte” permite que el diseño sea más fácil de entender.
3.3.2.2 Integridad de las Relaciones Para que las relaciones funcionen en una base de datos orientada a objetos pura, los
identificadores de los objetos deben corresponderse en ambos extremos de la relación. Por
ejemplo, si los aparejadores de una empresa de control de calidad se deben relacionar con
las obras de construcción que supervisan, debe haber algún modo de garantizar que, cuando
un identificador de un objeto Obra se incluye en un objeto Aparejador, el identificador de
este mismo objeto Aparejador se debe incluir en el objeto Obra anterior. Este tipo de
integridad de relaciones, que es de algún modo análogo a la integridad referencial en las
bases de datos relacionales, se gestiona especificando relaciones inversas.
La clase Aparejador tiene un atributo de tipo conjunto llamado supervisa. Del mismo
modo, la clase Obra tiene un atributo llamado es_supervisada. Para garantizar la
integridad de esta relación, un SGBD orientado a objetos puro deberá permitir que el
diseñador de la base de datos pueda especificar dónde debe aparecer el identificador del
objeto inverso, como por ejemplo:
relationship set<Obra> supervisa
inverse Obra::es supervisada
Maestría en Informática Aplicada a Redes
Página 46 de 159
en la clase Aparejador y:
relationship Aparejador es supervisada
inverse Aparejador::supervisa
en la clase Obra.
Siempre que un usuario o un programa de aplicación inserta o elimina un identificador de
objeto de la relación supervisa en un objeto Aparejador, el SGBD actualizará
automáticamente la relación es_supervisada en el objeto Obra relacionado. Cuando se
hace una modificación en el objeto Obra, el SGBD lo propagará automáticamente al objeto
Aparejador.
Del mismo modo que en las bases de datos relacionales es el diseñador de la base de datos
el que debe especificar las reglas de integridad referencial, en las bases de datos orientadas
a objetos es también el diseñador el que debe especificar las relaciones inversas cuando
crea el esquema de la base de datos.
3.3.3 El modelo Estándar ODMG
Un grupo de representantes de la industria de las bases de datos formaron el ODMG
(Object Database Management Group) con el propósito de definir estándares para los
SGBD orientados a objetos. Este grupo propuso un modelo estándar para la semántica de
los objetos de una base de datos. Los principales componentes de la arquitectura ODMG
para un SGBD orientado a objetos son los siguientes:
• Modelo de objetos.
• Lenguaje de definición de objetos (ODL).
• Lenguaje de consulta de objetos (OQL).
• Conexión con los lenguajes C++, Smalltalk y Java.
Maestría en Informática Aplicada a Redes
Página 47 de 159
3.3.3.1 Modelo de Objetos El modelo de objetos ODMG permite que tanto los diseños, como las implementaciones,
sean portables entre los sistemas que lo soportan. Dispone de las siguientes primitivas de
modelado:
• Los componentes básicos de una base de datos orientada a objetos son los objetos y
los literales. Un objeto es una instancia auto contenida de una entidad de interés del
mundo real. Los objetos tienen algún tipo de identificador único. Un literal es un
valor específico, como “Amparo” o 36. Los literales no tienen identificadores. Un
literal no tiene que ser necesariamente un solo valor, puede ser una estructura o un
conjunto de valores relacionados que se guardan bajo un solo nombre.
• Los objetos y los literales se categorizan en tipos. Cada tipo tiene un dominio
específico compartido por todos los objetos y literales de ese tipo. Los tipos también
pueden tener comportamientos. Cuando un tipo tiene comportamientos, todos los
objetos de ese tipo comparten los mismos comportamientos. En el sentido práctico,
un tipo puede ser una clase de la que se crea un objeto, una interfase o un tipo de
datos para un literal (por ejemplo, integer). Un objeto se puede pensar como una
instancia de un tipo.
• Lo que un objeto sabe hacer son sus operaciones. Cada operación puede requerir
datos de entrada (parámetros de entrada) y puede devolver algún valor de un tipo
conocido.
• Los objetos tienen propiedades, que incluyen sus atributos y las relaciones que
tienen con otros objetos. El estado actual de un objeto viene dado por los valores
actuales de sus propiedades.
• Una base de datos es un conjunto de objetos almacenados que se gestionan de modo
que puedan ser accedidos por múltiples usuarios y aplicaciones.
Maestría en Informática Aplicada a Redes
Página 48 de 159
• La definición de una base de datos está contenida en un esquema que se ha creado
mediante el lenguaje de definición de objetos ODL (Object Definition Language)
que es el lenguaje de manejo de datos que se ha definido como parte del estándar
propuesto para las bases de datos orientadas a objetos
Lenguaje de Definición de Objetos ODL es un lenguaje de especificación para definir tipos de objetos para sistemas
compatibles con ODMG. ODL es el equivalente del DDL (lenguaje de definición de datos)
de los SGBD tradicionales. Define los atributos y las relaciones entre tipos, y especifica la
signatura de las operaciones. La sintaxis de ODL extiende el lenguaje de definición de
interfaces (IDL) de la arquitectura CORBA (Common Object Request Broker Architecture).
Lenguaje de Consulta de Objetos.
OQL es un lenguaje declarativo del tipo de SQL que permite realizar consultas de modo
eficiente sobre bases de datos orientadas a objetos, incluyendo primitivas de alto nivel para
conjuntos de objetos y estructuras. Está basado en SQL-92, proporcionando un súper
conjunto de la sintaxis de la sentencia SELECT.
OQL no posee primitivas para modificar el estado de los objetos ya que las modificaciones
se pueden realizar mediante los métodos que estos poseen.
La sintaxis básica de OQL es una estructura SELECT...FROM...WHERE..., como en SQL.
Por ejemplo, la siguiente expresión obtiene los nombres de los departamentos de la escuela
de ‘Ingeniería’:
SELECT d.nombre
FROM d in departamentos
WHERE d.escuela = `Ingeniería';
En las consultas se necesita un punto de entrada, que suele ser el nombre de un objeto
persistente. Para muchas consultas, el punto de entrada es la extensión de una clase. En el
ejemplo anterior, el punto de entrada es la extensión departamentos, que es un objeto
Maestría en Informática Aplicada a Redes
Página 49 de 159
colección de tipo set<Departamento>. Cuando se utiliza una extensión como punto de
entrada es necesario utilizar una variable iteradora que vaya tomando valores en los objetos
de la colección. Para cada objeto de la colección (sólo la forman objetos persistentes) que
cumple la condición (que es de la escuela de ‘Ingeniería’), se muestra el valor del atributo
nombre.
El resultado es de tipo bag<string>. Cuando se utiliza SELECT DISTINCT … el
resultado es de tipo set ya que se eliminan los duplicados.
OQL tiene además otras características que no se van a presentar aquí:
• Especificación de vistas dando nombres a consultas.
• Obtención como resultado de un solo elemento (hasta ahora hemos visto que se
devuelven colecciones: set, bag, list).
• Uso de operadores de colecciones: funciones de agregados (max, min, count, sum,
avg) y cuantificadores (for all, exists).
• Uso de group by.
3.4 Sistemas Objetos-Relacionales
El modo en que los objetos han entrado en el mundo de las bases de datos relacionales es en
forma de dominios, actuando como el tipo de datos de una columna. Hay dos implicaciones
muy importantes por el hecho de utilizar una clase como un dominio:
• Es posible almacenar múltiples valores en una columna de una misma fila ya que un
objeto suele contener múltiples valores. Sin embargo, si se utiliza una clase como
dominio de una columna, en cada fila esa columna sólo puede contener un objeto de
la clase (se sigue manteniendo la restricción del modelo relacional de contener
valores atómicos en la intersección de cada fila con cada columna).
• Es posible almacenar procedimientos en las relaciones porque un objeto está
enlazado con el código de los procesos que sabe realizar (los métodos de su clase).
Maestría en Informática Aplicada a Redes
Página 50 de 159
Otro modo de incorporar objetos en las bases de datos relacionales es construyendo tablas
de objetos, donde cada fila es un objeto.
Ya que un sistema objeto–relacional es un sistema relacional que permite almacenar objetos
en sus tablas, la base de datos sigue sujeta a las restricciones que se aplican a todas las
bases de datos relacionales y conserva la capacidad de utilizar operaciones de
concatenación (join) para implementar las relaciones “al vuelo”.
Toda la información de la base de datos esta guardado en los tablas pero algunas
operaciones tabulares pueden tener una estructura de datos abstract data types(ADTs). Las
extensiones son necesarias porque los ORBDMSs debe de soportar ADT's. El ORDBMS
tiene un modelo relacionado porque los datos están guardados en forma de tablas con
renglones y columnas. SQL es usado como el lenguaje de búsqueda de información. Pero el
modelo relacionado tiene que ser modificado para soportar las características clásicas de
programación orientada a objeto. Las características de ORDBMSs son:
• extensión, de base de datos
• Soporte de objetos complejos,
• Herencia, y
• Reglas del Sistema.
Los ORDBMSs permiten que los usuarios puedan definir los tipos de datos, funciones y
operadores. Como resultado, los ORDBMSs tiene más funcionalidad y un mejor
desempeño
3.4.1 Diferencia entre los tres sistemas (RDBMS, ODBMS, ORDBMS)
Tabla 1: Una comparación de sistemas de Administración de Base de Datos
Criterio RDBMS ODBMS ORDBMS
Standard para definir SQL2 ODMG-2.0 SQL3 (in proceso)
Apoyo de
características
No lo apoya; Es
difícil mapear un
apoyo extensivo apoyo limitado;
mayormente con
Maestría en Informática Aplicada a Redes
Página 51 de 159
orientadas-objetos programa entre el
objeto y la base de
datos
datatypes
Uso Fácil de usar Bueno para
programadores;
Algún acceso de
SQL para usuarios
finales
Fácil de usar excepto
por algunas
extensiones
Apoyo para relaciones
complejas
No apoya datatypes
abstractos
Apoya una gran
variedad de
datatypes e inter-
relaciones de datos
complejos
Apoya datatypes
abstractos y
relaciones complejas
Desempeño Buen desempeño Relativamente menor
desempeño
Se espera que el
desempeño sea
mejor
Madurez del producto Relativamente viejo
y muy maduro
Este concepto tiene
un par de años y es
relativamente
maduro
Todavía está en el
proceso de
desarrollo
El uso de SQL Apoyo extensivo de
SQL
OQL es similar a
SQL, pero con
características
adicionales como
Objetos complejos y
características
orientadas a objetos
SQL3 está siendo
desarrollado con
características OO
incorporadas
Ventajas Su dependencia de
SQL, y su
optimización de
consultas es
Puede manejar todo
tipo de aplicaciones
complejas, puede
reutilizar el código
Habilidad de
consultas para
aplicaciones
complejas y la
Maestría en Informática Aplicada a Redes
Página 52 de 159
relativamente
sencilla
habilidad a manejar
aplicaciones grandes
y complejas
Desventajas Inhabilidad de
manejar aplicaciones
complejas
Desempeño pobre
por la optimización
de consultas
complejas, la
inhabilidad de
soportar sistemas de
gran escala
Desempeño pobre en
aplicaciones web.
Tiene apoyo de los
vendedores
Tiene un extenso
mercado y muchos
vendedores
En el presente, falta
apoyo de los
vendedores por el
tamaño del mercado
de RDBMS
Tiene un buen
futuro. Parece que
todo los vendedores
de RDBMS quieren
este producto
En el artículo "Object-Relational DBMS: The Next Wave," del Dr. Michael Stonebraker,
gerente de Tecnología de la Informix Software, ha clasificado cuatro tipos de aplicaciones
de DBMS:
Tabla 2: Categorías de DBMSs
File Systems RDBMSs OODBMSs ORDBMSs
Datos simples sin
queries
Datos simples con
queries
Datos complejos sin
queries
Datos complejos con
queries
Esos cuatro tipos describen sistemas de archivos, DBMS relacionales, DBMS orientados a
objetos, y DBMS objeto-relacional. Universal Server, creado por Informix pertenece a la
cuarta categoría. Los otros ORDBMS incluyen Oracle8 y superiores, de Oracle Corporation
y Universal DB (UDB) de IBM. También, Stonebraker predice que muy pronto todas las
aplicaciones de DBMSs (datos sencillos con queries) relacionales van a imitar los DBMS
objeto-relacional (datos complejos con query).
Maestría en Informática Aplicada a Redes
Página 53 de 159
Las cinco opciones de arquitectura por Dr. Stonebraker, están enlistadas en orden de
practicidad y desempeño:
• Proveen plug-in code para hacer llamadas funcionales a otras aplicaciones.
• Proveen API's esperando subsistemas del servidor para apoyar la funcionalidad de
objeto
• Simulan funcionalidad relacional-objeto en una capa de middleware
• Un motor de base de datos completamente rediseñado.
• Provee una nueva capa orientada a objetos para soportar tipos de datos
enriquecidos.
La ventaja principal del ORDBMSs es la gran escalabilidad que tienen, están diseñados
para manejar una gran cantidad de información. Pero aunque tengan muchas ventajas,
los ORDBMSs también tienen desventajas. La arquitectura de un modelo objeto
relacionado no es el mejor modelo para aplicaciones de alta velocidad en el web. Sin
embargo, los ORDBMS hacen la promesa de conquistar el mercado del mundo porque
tienen ventajas como la capacidad de guardar cantidades grandes de información y
acceso de alta velocidad. También tienen el apoyo de los vendedores principales.
3.5 Motores de Persistencia
Las opciones que se basan en imponer un único modelo teórico (un único formato de datos)
a toda la aplicación padecen de graves inconvenientes. En el caso de que toda la aplicación
siga el modelo relacional, se pierden las ventajas de la orientación a objetos. En el caso de
que toda la aplicación siga el modelo orientado a objetos, las bases de datos están
inmaduras y tienen un bajo nivel de estandarización.
Otra opción es aquella en la que el programa sea orientado a objetos y la base de datos sea
relacional, lo que, en principio, constituye la opción más natural. Sin embargo, plantea el
problema de hacer que dos componentes con formatos de datos muy diferentes puedan
comunicarse y trabajar conjuntamente.
Maestría en Informática Aplicada a Redes
Página 54 de 159
Se debe encontrar un traductor que sepa traducir de cada idioma al otro. Este traductor no
es más que un componente de software (concretamente, una capa de programación), al que
se le dan los nombres de “capa de persistencia”, “capa de datos”, “correspondencia O/R”
(“OR mapping”) o “motor de persistencia”.
El motor de persistencia traduce entre los dos formatos de datos: de registros a objetos y de
objetos a registros. La situación se ejemplifica en la figura 9. Cuando el programa quiere
grabar un objeto llama al motor de persistencia, que traduce el objeto a registros y llama a
la base de datos para que guarde estos registros. De la misma manera, cuando el programa
quiere recuperar un objeto, la base de datos recupera los registros correspondientes, los
cuales son traducidos en formato de objeto por el motor de persistencia.
El programa sabe que puede guardar y recuperar objetos, como si estuviera programado
para una base de datos orientada a objetos. La base de datos sabe que guarda y recupera
registros, como si el programa estuviera dirigiéndose a ella de forma relacional. Es decir,
cada uno de los dos componentes trabaja con el formato de datos (el “idioma”) que le
resulta más natural y es el motor de persistencia el que actúa de traductor entre los dos
modelos, permitiendo que los dos componentes se comuniquen y trabajen conjuntamente.
Esta solución goza de las mejores ventajas de los dos modelos.
• Por una parte, es posible programar con orientación a objetos, aprovechando las
ventajas de flexibilidad, mantenimiento y reusabilidad.
Maestría en Informática Aplicada a Redes
Página 55 de 159
• Por otra parte, se puede usar una base de datos relacional, aprovechando su
madurez y su estandarización así como las herramientas relacionales que existen
para ella.
Un motor de persistencia puede reducir el código de una aplicación en un cuarenta por
ciento, haciéndola menos costosa de desarrollar. Además, el código es más limpio y
sencillo y, por lo tanto, más fácil de mantener y más robusto, de tal manera que el motor de
persistencia no sólo simplifica la programación, sino que permite hacer ciertas
optimizaciones de rendimiento que serían difíciles de programar de otra manera.
En conclusión, ésta es la mejor opción en la actualidad para implementar una aplicación de
software.
3.5.1 Opciones para motores de persistencia
El motor de persistencia tiene la ventaja de que es el mismo para todas las aplicaciones. De
esta forma sólo debe programarse una vez y puede usarse para todas las demás aplicaciones
que se desarrollen en una empresa. Sin embargo, un motor de persistencia es difícil de
programar y de mantener, por lo que necesita un gran esfuerzo en costo y tiempo de
desarrollo.
Es por ello que hay dos opciones a la hora de usar un motor de persistencia:
• Programarlo, lo cual no es lo más recomendable, por la complejidad y costo que
introduce esta opción.
• Utilizar un motor que ya esté programado, comprándolo a un vendedor o bien
usando un motor gratuito de código abierto.
La segunda opción es la más recomendada, debido a que es la menos costosa y la menos
propensa a fallos. Se debe escoger un motor de persistencia de los que están programados,
estudiarlo y aplicarlo a todas las aplicaciones de una misma empresa.
En cuanto a la plataforma Java, los servidores de aplicaciones basados en la especificación
EJB (“Enterprise JavaBeans”), incorporan un motor de persistencia a través del mecanismo
conocido como “entity beans”. Sin embargo, los “entity beans” no son un mecanismo de
Maestría en Informática Aplicada a Redes
Página 56 de 159
persistencia totalmente recomendable, pues no permiten implementar algunas
características de la programación orientada a objetos (por ejemplo, herencia) y además,
obligan a una forma de programar diferente a los objetos normales de Java (o POJOs, por
“Plain Old Java Objects”).
Hay motores de persistencia más completos que no tienen este tipo de inconvenientes, entre
los de código abierto podemos destacar: Hibernate, Castor, Torque, OJB y Cayenne. Entre
los comerciales, podemos destacar TopLink, Cocobase y FastObjects. En los últimos años
se ha creado una especificación llamada JDO, para estandarizar la forma de programar en
Java con esos motores de persistencia. Ejemplos de motores de persistencia que cumplen el
estándar JDO son Kodo, JDO Genie, LiDo, Exadel JDO, IntelliBO, JRelay JDO (todos
ellos comerciales), TJDO y XORM (de código abierto).
La plataforma .NET, por su relativa novedad, está más inmadura que la plataforma Java.
Además, al ser una plataforma propietaria, cuesta más encontrar proyectos de código
abierto para ella. Por esto no existe tanta variedad de motores de persistencia en esta
plataforma. Microsoft anunció un motor de persistencia llamado Objectspaces para .NET
2004, sin embargo a la fecha y con el lanzamiento de .NET 2005, el producto no ha sido
liberado. Mientras tanto, se puede usar ORM.NET, que es un motor de persistencia
comercial para .NET.
3.6 Proceso de Diseño y Desarrollo de un Proyecto de Software
3.6.1 CMM El Modelo de Capacidad y Madurez o CMM (Capability Maturity Model), es un modelo de
evaluación de los procesos de una organización. Fue desarrollado inicialmente para los
procesos relativos al software por la Universidad Carnegie-Mellon para el SEI (Software
Engineering Institute).
El SEI es un centro de investigación y desarrollo patrocinado por el Departamento de
Defensa de los Estados Unidos de América y gestionado por la Universidad Carnegie-
Mellon. "CMM" es una marca registrada del SEI
Maestría en Informática Aplicada a Redes
Página 57 de 159
A partir de noviembre de 1986 el SEI, a requerimiento del Gobierno Federal de los Estados
Unidos de América, desarrolló una primera definición de un modelo de madurez de
procesos en el desarrollo de software, que se publicó en septiembre de 1987. Este trabajo
evolucionó al modelo CMM o SW-CMM (CMM for Software), cuya última versión (v1.1)
se publicó en febrero de 1993.
Este modelo establece un conjunto de prácticas o procesos clave agrupados en Áreas Clave
de Proceso (KPA - Key Process Area). Para cada área de proceso define un conjunto de
buenas prácticas que habrán de ser:
• Definidas en un procedimiento documentado
• Provistas (la organización) de los medios y formación necesarios
• Ejecutadas de un modo sistemático, universal y uniforme (institucionalizadas)
• Medidas
• Verificadas
• A su vez estas Áreas de Proceso se agrupan en cinco "niveles de madurez", de modo
que una organización que tenga institucionalizadas todas las prácticas incluidas en
un nivel y sus inferiores, se considera que ha alcanzado ese nivel de madurez.
Los niveles son:
1. Inicial. Las organizaciones en este nivel no disponen de un ambiente estable para el
desarrollo y mantenimiento de software. Aunque se utilicen técnicas correctas de
ingeniería, los esfuerzos se ven minados por falta de planificación. El éxito de los
proyectos se basa la mayoría de las veces en el esfuerzo personal, aunque a menudo se
producen fracasos y casi siempre retrasos y altos costos. El resultado de los proyectos
es impredecible.
2. Repetible. En este nivel las organizaciones disponen de unas prácticas
institucionalizadas de gestión de proyectos, existen unas métricas básicas y un
razonable seguimiento de la calidad. La relación con subcontratistas y clientes está
gestionada sistemáticamente.
Maestría en Informática Aplicada a Redes
Página 58 de 159
3 Definido. Además de una buena gestión de proyectos, a este nivel las organizaciones
disponen de correctos procedimientos de coordinación entre grupos, formación del
personal, técnicas de ingeniería más detalladas y un nivel más avanzado de métricas en
los procesos. Se implementan técnicas de revisión por pares (peer reviews).
4 Gestionado. Se caracteriza porque las organizaciones disponen de un conjunto de
métricas significativas de calidad y productividad, que se usan de modo sistemático
para la toma de decisiones y la gestión de riesgos. El software resultante es de alta
calidad.
5 Optimizado. La organización completa está volcada en la mejora continua de los
procesos. Se hace uso intensivo de las métricas y se gestiona el proceso de innovación.
Así es como el modelo CMM establece una medida del progreso conforme avanza, en
niveles de madurez. Cada nivel a su vez cuenta con un número de áreas de proceso que
deben lograrse. El alcanzar estas áreas o estadios se detecta mediante la satisfacción o
insatisfacción de varias metas claras y cuantificables. Con la excepción del primer Nivel,
cada uno de los restantes Niveles de Madurez está compuesto por un cierto número de
Áreas Claves de Proceso, conocidas a través de la documentación del CMM por su sigla
inglesa: KPA.
Cada KPA identifica un conjunto de actividades y prácticas interrelacionadas, las cuales
cuando son realizadas en forma colectiva permiten alcanzar las metas fundamentales del
proceso. Las KPAs pueden clasificarse en 3 tipos de proceso: Gestión, Organizacional e
Ingeniería.
Las prácticas que deben ser realizadas por cada Area Clave de Proceso están organizadas en
5 Características Comunes, las cuales constituyen propiedades que indican si la
implementatción y la institucionalización de un proceso clave es efectivo, repetible y
duradero.
Estas 5 características son: i)Compromiso de la realización, ii) La capacidad de realización,
iii) Las actividades realizadas, iv) Las mediciones y el análisis, v) La verificación de la
implementación.
Maestría en Informática Aplicada a Redes
Página 59 de 159
Las organizaciones que utilizan CMM para mejorar sus procesos disponen de una guía útil
para orientar sus esfuerzos. Además, el SEI proporciona formación a evaluadores
certificados (Lead Assesors) capacitados para evaluar y certificar el nivel CMM en el que
se encuentra una organización. Esta certificación es requerida por el Departamento de
Defensa de los Estados Unidos, pero también es utilizada por multitud de organizaciones de
todo el mundo para valorar a sus subcontratistas de software.
Se considera típico que una organización dedique unos 18 meses para progresar un nivel,
aunque algunas consiguen mejorarlo. En cualquier caso requiere un amplio esfuerzo y un
compromiso intenso de la dirección.
Como consecuencia, muchas organizaciones que realizan funciones de factoría de software
o, en general, outsourcing de procesos de software, adoptan el modelo CMM y se certifican
en alguno de sus niveles. Esto explica que uno de los países en el que más organizaciones
certificadas exista sea India, donde han florecido las factorías de software que trabajan para
clientes estadounidenses y europeos.
A partir de 2001, en que se presentó el modelo CMMI, el SEI ha dejado de desarrollar el
SW-CMM, cesando la formación de los evaluadores en diciembre de 2003, quienes
dispondrán hasta fin de 2005 para reciclarse al CMMI. Las organizaciones que sigan el
modelo SW-CMM podrán continuar haciéndolo, pero ya no podrán ser certificadas a partir
de fin de 2005.
3.6.1.1 SW-CMM Vs CMMI El objetivo de esta sección es presentar un panorama general y un comparativo sobre los
dos modelos de madurez del SEI (Software Engineering Institute) que han tenido más
aceptación para las organizaciones y áreas que se dedican al desarrollo del software y que
últimamente han generado gran controversia en la comunidad mundial: SW-CMM y
Maestría en Informática Aplicada a Redes
Página 60 de 159
CMMI. Esto con la finalidad de que el lector se forme una idea de la razón de ser de los
mismos, la audiencia hacia la cual están enfocados y los aspectos que cubren.
Antes de iniciar con nuestra revisión es importante mencionar que la aplicabilidad de los
modelos para la mejora de procesos depende de la situación y del tipo de cada
organización, ya que los programas de mejora deben estar basados en la misión y los
objetivos del negocio que tenga cada organización.
SW-CMM (Software Capability Maturity Model)
Es el modelo más utilizado en la industria de software, no sólo en los Estados Unidos
(EE.UU.), sino en el mundo entero, por lo que representa el estándar de facto de la
industria de software.
Mide la capacidad de proceso para desarrollar software con calidad, incrementando la
predectibilidad para terminar los proyectos en costo, tiempo y con la calidad que el cliente
espera. El modelo fue creado a solicitud de la DoD (Department of Defense) de EE.UU. y
rápidamente fue adoptado por la industria para evaluar a los proveedores de software de
manera estándar y objetiva.
Actualmente el SW-CMM, en su versión 1.1, está organizado en 5 niveles de madurez, con
18 áreas clave (KPAs), con 52 metas que requieren de 316 prácticas comunes (tales como
habilidades a desarrollar, compromisos de la gerencia, métricas y revisiones para verificar
la implantación de las actividades requeridas). Su enfoque está orientado en generar,
implantar y mejorar las prácticas de ingeniería de software, considerando al desarrollo de
software como producto principal.
El SW-CMM ha demostrado ser un diferenciador importante de nivel comercial, pues
además de permitir mejorar internamente los procesos de las organizaciones, representa una
manera estándar e internacional de comparar (hacer benchmarking) objetivamente a
diferentes proveedores. De hecho, el Departamento de Defensa de EE.UU. requiere que
todos sus proveedores de software sean nivel 3 o superior. Este requerimiento se ha
extendido en la mayoría de las grandes empresas de EE.UU. que subcontratan empresas
para el desarrollo de sus sistemas de software y por lo mismo la industria de desarrollo de
Maestría en Informática Aplicada a Redes
Página 61 de 159
software en la India ha tenido un gran auge. Si bien es un modelo general, debido a que nos
presenta un marco de referencia para generar nuevas capacidades de desarrollar software,
su fortaleza radica en la flexibilidad que proporciona para que las organizaciones adapten el
modelo a su forma de trabajo, sin forzarlos a utilizar determinadas herramientas o
metodologías. Es un modelo totalmente orientado a la industria de software, lo cual implica
que puede ser aplicado tanto a empresas que se dediquen exclusivamente al desarrollo de
sistemas de software, o a aquellas que necesitan hacer integración de hardware y software.
Las industrias que son usuarias del modelo SW-CMM, numéricamente, tienen el siguiente
perfil: 689 de 1018 empresas evaluadas formalmente por el SEI son industrias comerciales
(67.7%), mientras que sólo 329 (32.3%) pertenecen a la industria militar, o son contratistas
de los mismos. De las primeras, el 40% de las empresas tienen 100 o menos empleados y
el 60% tienen 200 empleados o menos, lo cual indica que la mayoría de las empresas
usuarias del modelo son empresas medianas o pequeñas.
En una entrevista al Dr. Pankaj Jalote, Ex-Vicepresidente de Calidad de Infosys, una de las
pocas empresas que han obtenido el nivel 5 de SW-CMM, comentó textualmente, que la
razón por la cual en la India se había adoptado el SW-CMM, era muy sencilla y lógica ya
que la industria de software de la India ha estado y está orientada a la exportación de
software a diversos países, principalmente a EE.UU. y Europa, países que han determinado
el desarrollo de software bajo estándares internacionales. Debido a que sus principales
compradores están esparcidos por todo el mundo, la industria de desarrollo de software de
la India necesitaba seguir un marco de referencia globalmente aceptado y alineado a los
estándares internacionalmente reconocidos. Esto generó la necesidad de adoptar (C)
modelos como ISO 9000 y SW-CMM. El Dr. Jalote se remontó a la historia de la industria
de la India y nos comentó que al inicio, sus principales clientes eran empresas europeas y
por lo tanto el primer estándar que adoptaron fue ISO 9000, ya que era el requerimiento del
mercado para poder adquirir el software desarrollado por la India. De esta manera, las
empresas exportadoras de software de la India, entre 1993 y 1996, se certificaron en ISO
9000. Más adelante tuvieron que evolucionar a un nuevo estándar ya que el mercado y sus
principales compradores, en este caso EE.UU., cambiaron el requerimiento hacia SW-
CMM, y por lo tanto las empresas de la India para seguir en el negocio de desarrollo y
exportación de software, dejaron atrás la certificación ISO 9000 y cambiaron al modelo de
SW-CMM. Actualmente existen 64 empresas que están en nivel 5 y 51 de éstas son
Maestría en Informática Aplicada a Redes
Página 62 de 159
empresas de la India. Resumiendo lo anterior y citando las palabras Dr. Jalote la razón
principal es " market-driven", o como dice un conocido refrán mexicano “Dale al cliente lo
que pida”.
CMMI (Capability Maturity Model Integrated) Es un nuevo modelo del SEI que fue creado a solicitud del DoD para las organizaciones
con iniciativas de ingeniería de software, ingeniería de sistemas o industrias que requieran
integración (software + hardware). La intención de este nuevo modelo es consolidar y
agrupar una familia de modelos que ya estaban siendo utilizados y reconciliar estos
modelos con los estándares y metodologías (como ISO/IEC/TR 15504).
La base del CMMI está constituida por los modelos SW-CMM, SA-CMM (Software
Acquisition Capability Maturity Model), IPD-CMM (Integrated Product Development
Capability Maturity Model) y SE-CMM(Systems Engineering Capability Maturity Model).
El CMMI es un modelo nuevo y aunque se han liberado varias versiones, todavía no son
estables debido a las modificaciones y sugerencias de cambio que se están realizando sobre
la versión aprobada. La última versión liberada es la 1.02, y está en vías de liberación la
1.1.
Existen dos versiones de este modelo, la escalonada (staged) y la continua (continuos).
Aunque los expertos y algunos opositores a este modelo opinan que no existe una clara
diferencia entre el modelo escalonado y el continuo, ya que el escalonado es más continuo
de lo que aparenta.
La versión escalonada del modelo tiene 5 niveles, como el SW-CMM versión 1.1, que
contienen 24 áreas de proceso (PAs), con 78 metas que se alcanzan al implantar las 618
prácticas comunes. Para la versión continua del modelo existen 6 niveles de madurez, que
contienen 24 áreas de proceso (PAs), con 174 metas que se deben alcanzar y 455 prácticas
comunes.
El modelo del CMMI tiene el propósito de proporcionar una guía unificada para la mejora
de múltiples disciplinas tales como ingeniería de sistemas, ingeniería de software, etc. Sin
embargo, mucho se ha escrito y discutido sobre el tema de que las empresas que en realidad
Maestría en Informática Aplicada a Redes
Página 63 de 159
necesitan una guía de este tipo, son las grandes organizaciones (proveedores del
Departamento de Defensa, principalmente) cuyos proyectos involucran múltiples
disciplinas; mientras que la gran mayoría de los usuarios actuales del modelo SW-CMM
son pequeñas organizaciones y/o áreas de desarrollo de software, que no utilizan o no
necesitan otras disciplinas mas que la de ingeniería de software y ésta es el foco principal
del SW-CMM.
La situación actual del CMMI en el mercado norteamericano, es incierta ya que a pesar de
tener la presión del Departamento de Defensa por adaptar este nuevo modelo, muchas
empresas han comentado que el CMMI no se adapta a sus necesidades, debido a que hay
muchos elementos que resultan sobrados para empresas pequeñas-medianas cuyo negocio
principal es el desarrollo de software, y no la integración de tecnología o hardware, que es
el enfoque principal del nuevo modelo. Adicionalmente al esfuerzo requerido para la
implantación de las nuevas prácticas del CMMI, es necesario considerar el esfuerzo
necesario para la capacitación y para la evaluación formal. El método de evaluación para el
nuevo modelo se denomina SCAMPI (Standard CMMI Assessment Method for Process
Improvement) y para realizar una evaluación se requieren considerar varios meses debido a
la visión global que refleja el modelo.
La percepción en la industria internacional, es que este modelo se adapta más a empresas
grandes, que requieren de diversas disciplinas. La transición del SW-CMM al CMMI
requiere una inversión fuerte, incluso para las organizaciones que son maduras en el
modelo SW-CMM (niveles 3, 4), ya que se requiere realizar un esfuerzo extra para cubrir
las nuevas áreas de proceso (en niveles inferiores y superiores), lograr un nuevo cambio de
cultura y capacitar a la organización en el nuevo modelo de referencia.
En la conferencia del SEPG que se realizó el pasado febrero en Phoenix, se presentaron
diversas conferencias y paneles de discusión sobre este tema y principalmente nos interesó
una conferencia que presentó el tema "CMMI not for the little guy?", impartida por
Margaret Kulpa de Agile Dim Inc. El tema de la conferencia se enfocó al cuestionamiento
de si el modelo CMMI se adapta a las organizaciones pequeñas, dónde el término
“pequeñas” se utilizaba en el contexto de 20 o menos empleados, con 2 o 3 empleados por
Maestría en Informática Aplicada a Redes
Página 64 de 159
proyecto, donde el personal asignado al proyecto desempeña varios roles y los proyectos
tienen una duración de 3 a 6 semanas. A continuación se resumen algunos puntos de esta
presentación con la finalidad de formar al lector con ideas más concretas de las
implicaciones de este modelo en empresas pequeñas, como es el caso de muchas empresas
mexicanas.
El modelo del CMMI no provee guías de ajuste para adaptar el modelo a las organizaciones
pequeñas. Esta guía es necesaria, debido a que la estructura del modelo (diseñada para
muchos recursos asignados a proyectos, con muchos roles, proyectos muy largos que
pueden durar años y cuestan millones de dólares). CMMI se basa en prácticas de
organizaciones grandes, y está enfocado para organizaciones del departamento de defensa o
aeronáutica.
CMMI es demasiado grande para que pueda ser manejado en organizaciones pequeñas. El
CMM ha sido criticado por tener muchas áreas clave, pero CMMI tiene muchas mas. Esto
implica que la documentación de procesos que cubra las prácticas del modelo puede ser
agobiante para las organizaciones pequeñas, y por lo tanto, el tiempo, costo y recursos para
la documentación pueden crecer exponencialmente.
El retorno de inversión (ROI) del CMMI no ha sido validado (especialmente en
organizaciones pequeñas). El retorno de inversión, suele ser uno de los principales
justificaciones para invertir en programas de mejora. Este punto es especialmente
importante para las organizaciones pequeñas donde, la mayoría de las veces no se cuenta
con un gran presupuesto e indudablemente el pago de la nómina cada dos semanas es una
preocupación mayor. Actualmente no se tienen estudios que ayuden a calcular el ROI para
el CMMI.
Las organizaciones pequeñas se administran de manera diferente a las grandes y enfrentan
retos diferentes. El principal móvil de negocio para las empresas pequeñas es el tiempo de
salida al mercado (time-to-market) de sus productos, por lo que la entrega rápida de
productos es muy importante para éstas, y para el CMMI ese "time-to-market" no parece
ser una fuerza impulsora.
CMMI fue escrito para organizaciones maduras. El material introductorio de las primeras
versiones del modelo escalonado (CMMI staged), decía que las organizaciones evaluadas
Maestría en Informática Aplicada a Redes
Página 65 de 159
en niveles superiores del SW-CMM deberían utilizar el CMMI. La mayoría de este tipo de
organizaciones son grandes, y por lo general ya han trabajado en programas de mejora o
han alcanzado un buen entendimiento de lo que significa la mejora de procesos. El
requerimiento de CMMI para el programa de métricas es complicado y sofisticado desde el
nivel 2, y aunque la definición de métricas es importante para cualquier programa de
mejora esto puede ser difícil de implantar en una organización principiante.
Podríamos seguir listando una serie de elementos que han sido criticados en el nuevo
modelo de CMMI y las inquietudes que existen, incluso en la industria estadounidense y en
el propio SEI, en cuanto a la aceptación por el modelo. Esto nos hace reflexionar sobre la
dificultad que representa para las empresas mexicanas la adopción de este nuevo modelo.
Sobre todo para aquellas que no tienen experiencia anterior con un programa de mejora
basado en el SW-CMM.
Actualmente no hay muchas organizaciones que hayan adoptado o estén haciendo la
transición hacia el nuevo modelo. Incluso los grandes corporativos norteamericanos tienen
que realizar una fuerte inversión para hacer la transición.
Lo que la comunidad internacional está pidiendo es que se mantengan los dos modelos, se
libere la versión 2 del SW-CMM que actualmente está en versión borrador y permitir que el
mercado decida cual de los dos modelos debe utilizar con base en sus necesidades y
objetivos de negocio (SW-CMM vs. CMMI).
Finalmente, nos gustaría comentar que el éxito del proyecto no está en la selección de un
modelo en particular, sino en establecer un programa de mejora que establezca nuevas
prácticas y disciplinas de trabajo para el desarrollo de software utilizando un modelo como
un marco de referencia que ayude a las organizaciones a lograr sus objetivos de negocio. Lo
recomendable es que éste sea reconocido mundialmente con el objetivo de ser comparable
con otros proveedores en mercados internacionales.
3.6.2 El RUP y el Proceso Unificado Los orígenes de RUP se remontan al modelo espiral original de Barry Boehm. Ken
Hartman, uno de los contribuidores claves de RUP colaboró con Boehm en la
investigación. En 1995 Rational Software es comprada por una compañia sueca llamada
Maestría en Informática Aplicada a Redes
Página 66 de 159
Objectory AB. El Rational Unified Process fue el resultado de una convergencia de
Rational Approach y Objectory, proceso desarrollado por el fundador de Objectory Ivan
Jacobson. El primer resultado de esta fusión fue el Rational Objectory Process, la primera
versión de RUP, fue puesta en el mercado en 1998, siendo el arquitecto en jefe Philippe
Kruchten.
El Proceso Racional Unificado o RUP (Rational Unified Process), es un proceso de
desarrollo de software y junto con el Lenguaje Unificado de Modelado UML, constituye la
metodología estándar más utilizada para el análisis, implementación y documentación de
sistemas orientados a objetos. RUP es en realidad un refinamiento realizado por Rational
Software del más genérico Proceso Unificado.
Sus principales características son:
• Forma disciplinada de asignar tareas y responsabilidades (quién hace qué, cuándo y
cómo)
• Pretende implementar las mejores prácticas en Ingeniería de Software
• Desarrollo interactivo
• Administración de requisitos
• Uso de arquitectura basada en componentes
• Control de cambios
• Modelado visual del software
• Verificación de la calidad del software
El RUP es un producto de Rational (IBM). Se caracteriza por ser interactivo e incremental,
estar centrado en la arquitectura y guiado por los casos de uso. Incluye artefactos (que son
los productos tangibles del proceso como por ejemplo, el modelo de casos de uso, el código
fuente, etc.) y roles (papel que desempeña una persona en un determinado momento, una
persona puede desempeñar distintos roles a lo largo del proceso).
Maestría en Informática Aplicada a Redes
Página 67 de 159
3.6.2.1 Fases del RUP
El RUP divide el proceso de desarrollo en ciclos, teniendo un producto final al final de cada
ciclo, cada ciclo se divide en fases que finalizan con un hito donde se debe tomar una
decisión importante:
1. Inicio (Inception): se hace un plan de fases, se identifican los principales casos de uso
y se identifican los riesgos
2. Elaboración (Elaboration): se hace un plan de proyecto, se completan los casos de uso
y se eliminan los riesgos
3. Construcción (Construction): se concentra en la elaboración de un producto
totalmente operativo y eficiente y el manual de usuario
4. Transición (Transition): se implementa el producto en el cliente y se entrena a los
usuarios. Como consecuencia de esto suelen surgir nuevos requisitos a ser analizados.
3.6.2.2 El RUP y la orientación a Objetos.
Aunque RUP es un proceso de desarrollo de software genérico, se concibió en gran medida
para el desarrollo de sistemas basados en P.O.O. Por ejemplo se suele emplear RUP en
proyectos de programación en Lenguajes como Java o .NET, etc. Al ser genérico, tiene
muchas aplicaciones y se pueden realizar las adecuaciones necesarias al proceso, según la
naturaleza del proyecto que se desea afrontar.
3.6.3 Microsoft Solution Framework Microsoft Solutions Framework (MSF) es un proceso de desarrollo de software altamente
customizable, escalable e integrado. Actualmente junto al producto Visual Studio 2005
Team system ofrece una serie de herramientas con las cuales puede ser aplicado a proyectos
pequeños denominados MSF for Agile Software Development y a proyectos de gran
envergadura denominado MSF for CMMI® Process Improvement
Maestría en Informática Aplicada a Redes
Página 68 de 159
Microsoft Solutions Framework (MSF) es una flexible e interrelacionada serie de
conceptos, modelos y prácticas de uso que controlan la planificación, el desarrollo y la
gestión de proyectos tecnológicos. MSF se centra en los modelos de proceso y de equipo
dejando en un segundo plano las elecciones tecnológicas. Originalmente creado en 1994
para conseguir resolver los problemas a los que se enfrentaban las empresas en sus
respectivos proyectos, se ha convertido posteriormente en un modelo práctico que facilita el
éxito de los proyectos tecnológico
MSF se compone de varios modelos encargados de planificar las diferentes partes
implicadas en el desarrollo de un proyecto: Modelo de Arquitectura del Proyecto, Modelo
de Equipo, Modelo de Proceso, Modelo de Gestión del Riesgo, Modelo de Diseño de
Proceso y finalmente el modelo de Aplicación.
• Modelo de Equipo: Este modelo ha sido diseñado para mejorar el rendimiento del
equipo de desarrollo. Proporciona una estructura flexible para organizar los equipos
de un proyecto. Puede ser escalado dependiendo del tamaño del proyecto y del
equipo de personas disponibles. Para obtener más información puedes consultar el
Documento del Modelo de Equipo
• Modelo de Proceso: Diseñado para mejorar el control del proyecto, minimizando el
riesgo, y aumentar la calidad acortando el tiempo de entrega. Proporciona una
estructura de pautas a seguir en el ciclo de vida del proyecto, describiendo las fases,
las actividades, la liberación de versiones y explicando su relación con el Modelo de
equipo. Puedes encontrar su descripción en el Documento del Modelo de Proceso
• Disciplina de Gestión de Riesgos: Diseñada para ayudar al equipo a identificar las
prioridades, tomar las decisiones estratégicas correctas y controlar las emergencias
que puedan surgir. Este modelo proporciona un entorno estructurado para la toma
de decisiones y acciones valorando los riesgos que puedan provocar. Consulta la
base del modelo en el Documento de la Disciplina de Gestión de Riesgos
Maestría en Informática Aplicada a Redes
Página 69 de 159
• Disciplina de Gestión de Proyectos: Es una disciplina que describe el rol de la
gestión del proyecto dentro del modelo de equipo de MSF, y como permite mayor
escalabilidad, desde proyectos pequeños a proyectos largos y complejos. Puedes
encontrar la descripción de esta disciplina el el Documento de la Disciplina de
Gestión de Proyectos
• Disciplina de Gestión de la Preparación (Readiness): Esta disciplina describe
aquellos conocimientos, aptitudes y habilidades que son necesarias para planificar,
desarrollar y gestionar soluciones satisfactorias. Se puede consultar en el
Documento de la Disciplina de Gestión de la Preparación
Para una mayor información sobre el MSF puede visitar la página http://www.microsoft.com/msf
3.7 Microsoft .Net Framework
Microsoft .NET es una plataforma de desarrollo y ejecución de aplicaciones. que brinda las
herramientas y servicios que se necesitan para desarrollar modernas aplicaciones
empresariales y de misión crítica, y que también provee mecanismos robustos, seguros y
eficientes para asegurar que la ejecución de las mismas sea óptima. Los componentes
principales de la plataforma .NET son:
• Un entorno de ejecución de aplicaciones, también llamado “Runtime”, que es un
componente de software cuya función es la de ejecutar las aplicaciones .NET e
interactuar con el sistema operativo ofreciendo sus servicios y recursos.
• Un conjunto de bibliotecas de funcionalidades y controles reutilizables, con una
enorme cantidad de componentes ya programados listos para ser consumidos por
otras aplicaciones.
Maestría en Informática Aplicada a Redes
Página 70 de 159
• Un conjunto de lenguajes de programación de alto nivel, junto con sus compiladores
y linkers, que permitirán el desarrollo de aplicaciones sobre la plataforma .NET.
• Un conjunto de utilitarios y herramientas de desarrollo para simplificar las tareas
más comunes del proceso de desarrollo de aplicaciones.
• Documentación y guías de arquitectura, que describen las mejores prácticas de
diseño, organización, desarrollo, prueba e instalación de aplicaciones .NET
Por otra parte, .NET representa la evolución COM (Component Object Model), la
plataforma de desarrollo de Microsoft anterior a .NET y sobre la cual se basaba el
desarrollo de aplicaciones Visual Basic 6.
Entre los factores que motivaron el desarrollo e introducción al mercado de la plataforma
Microsoft .NET. se pueden mencionar:
- La amplia disponibilidad de conexiones a Internet de alta velocidad, e incluso
inalámbricas
- La proliferación de nuevos tipos de dispositivos de hardware que son usados en la
vida diaria (teléfonos inteligentes, Pocket PC’s, HandHelds, Media Centers, etc.)
- El creciente poder de cómputo de las computadoras personales y servidores basados
en arquitecturas x86.
- El surgimiento de estándares de Internet para permitir la comunicación e integración
entre diversas plataformas de software
.NET no es un sistema operativo, como lo es Microsoft Windows en sus distintas
versiones.
.NET no es un Lenguaje de Programación: si bien la plataforma Microsoft .NET
incluye lenguajes de programación de aplicaciones, su concepto es más amplio y va
más allá de éstos.
Maestría en Informática Aplicada a Redes
Página 71 de 159
.NET no es un Entorno de Desarrollo: si bien la plataforma Microsoft .NET incluye
entornos de desarrollo integrados (IDEs), su concepto es más amplio y va más allá de
éstos.
.NET no es un servidor de aplicaciones (Application Server)
.NET no es un producto empaquetado que se pueda comprar como tal, sino que es una
plataforma que engloba distintas aplicaciones, servicios y conceptos y que en conjunto
permiten el desarrollo y la ejecución de aplicaciones.
3.7.1 Características Algunas de las características principales de la plataforma Microsoft .NET son:
• Se dice que es una plataforma de ejecución intermedia, ya que las aplicaciones
.NET no son ejecutadas directamente por el sistema operativo, como ocurre en el
modelo tradicional de desarrollo. En su lugar, las aplicaciones .NET están diseñadas
para ser ejecutadas contra un componente de software llamado Entorno de
Ejecución (muchas veces también conocido como “Runtime”, o , “Máquina
Virtual”). Este componente es el encargado de manejar el ciclo de vida de cualquier
aplicación .NET, iniciándola, deteniéndola, interactuando con el Sistema Operativo
y proveyéndole servicios y recursos en tiempo de ejecución.
• La plataforma Microsoft .NET está completamente basada en el paradigma de
Orientación a Objetos.
• .NET es multi-lenguaje: esto quiere decir que para poder codificar aplicaciones
sobre esta plataforma no es necesario aprender un único lenguaje específico de
programación de alto nivel, sino que se puede elegir de varias opciones.
• .NET es una plataforma que permite el desarrollo de aplicaciones empresariales de
misión crítica, entendiéndose por esto que permite la creación y ejecución de
aplicaciones de porte corporativo que sean críticas para la operación de tipos
variados de organizaciones. Puede soportar aplicaciones grandes y complejas.
• .Net fue diseñado de manera tal de poder proveer un único modelo de
programación, uniforme y consistente, para todo tipo de aplicaciones (ya sean de
formularios Windows, de consola, aplicaciones Web, aplicaciones móviles, etc.) y
Maestría en Informática Aplicada a Redes
Página 72 de 159
para cualquier dispositivo de hardware (PC’s, Pocket PC’s, Teléfonos Celulares
Inteligentes, también llamados “SmartPhones”, Tablet PC’s, etc.). Esto representa
un gran cambio con respecto a las plataformas anteriores a .NET, las cuales tenían
modelos de programación, bibliotecas, lenguajes y herramientas distintas según el
tipo de aplicación y el dispositivo de hardware.
• Uno de los objetivos de diseño de .NET fue que tenga la posibilidad de interactuar e
integrarse fácilmente con aplicaciones desarrolladas en plataformas anteriores,
particularmente en COM, ya que aún hoy existen una gran cantidad de aplicaciones
desarrolladas sobre esa base.
• .NET no sólo se integra fácilmente con aplicaciones desarrolladas en otras
plataformas Microsoft, sino también con aquellas desarrolladas en otras plataformas
de software, sistemas operativos o lenguajes de programación. Para esto hace un uso
extensivo de numerosos estándares globales que son de uso extensivo en la
industria, algunos ejemplos de estos estándares son XML, HTTP, SOAP, WSDL y
UDDI.
El .NET Framework es el componente fundamental de la plataforma Microsoft .NET,
necesario tanto para poder desarrollar aplicaciones como para poder ejecutarlas luego en
entornos de prueba o producción.
El .NET framework tiene tres variantes principales, todas descargables gratuitamente desde
Internet
• .NET Framework Redistributable Package: mínimo componente de la plataforma
.NET que se necesita para poder ejecutar aplicaciones. Normalmente ésta es la
variante que se instala en los entornos productivos, una vez que el desarrollo y las
pruebas de la aplicación han finalizado.
Está compuesto por:
• El entorno de ejecución de la plataforma .NET
• Las bibliotecas de funcionalidad reutilizable
• .NET Framework SDK: esta versión contiene herramientas de desarrollo de línea de
comandos (compiladores, depuradores, etc.), documentación de referencia, ejemplos
Maestría en Informática Aplicada a Redes
Página 73 de 159
y manuales para desarrolladores de aplicaciones. Normalmente ésta variante se
instala en los entornos de desarrollo de aplicaciones, y es más útil a los
programadores que a los usuarios finales. Para poder instalar la versión SDK
(Software Development Kit) es necesario instalar previamente el Redistributable
Package.
• NET Compact Framework: esta es una versión reducida del .NET Framework
Redistributable, especialmente pensada para ser instalada en dispositivos móviles
como Pocket PC’s y SmartPhones.
El .NET Framework puede ser instalado en cualquier sistema operativo de la familia
Windows superior a Windows 98, actualmente, Windows 2003 Server y Windows XP SP2
traen el .NET Framework preinstalado.
El .NET Framework debe estar instalado en cualquier dispositivo de hardware para que la
ejecución de una aplicación .NET sea posible. En el caso de las aplicaciones de escritorio
(también llamadas “De Formularios Windows”) y las aplicaciones de consola (aplicaciones
cuya interfaz de usuario es una consola de comandos), el Framework debe estar presente
del lado del cliente (computadora donde se ejecuta la parte de la aplicación que interactúa
con el usuario), y en el servidor sólo en caso de que la aplicación sea distribuida y tenga
parte de su funcionalidad centralizada en una única computadora.
En el caso de las aplicaciones Web, el único requisito del lado del cliente es tener un
navegador y una conexión de red al servidor, el cual debe tener instalado el .NET
Framework.
Para las aplicaciones móviles, que se ejecutan sobre Windows Mobile en algún dispositivo
tipo Pocket PC o SmartPhone, es necesario tener instalado el .NET Compact Framework en
el dispositivo.
Maestría en Informática Aplicada a Redes
Página 74 de 159
Actualmente hay 3 versiones de la plataforma Microsoft .NET:
• La versión 1.0: fue liberada a principios del año 2002, e incluía la versión 1.0 del
.NET Framework, la versión 2002 de Visual Studio y varios lenguajes de
programación nuevos compatibles con la plataforma (como C#.NET y Visual
Basic.NET)
• La versión 1.1: fue liberada en 2003, aproximadamente un año después que su
predecesora. Esta versión introdujo el .NET Framework 1.1 junto con Visual Studio
.NET 2003, la primer versión del .NET Compact Framework y un nuevo lenguaje
de programación llamado J#.NET.
• La versión 2.0: fue liberada a finales del año 2005, esta versión trajo consigo las
versiones 2.0 del .NET Framework y el .NET Compact Framework, así como
también una nueva versión de Visual Studio.
La próxima generación de la plataforma .NET, tendrá por nombre código “Orcas”.
.NET Compact Framework
����* ����
����
����* ����
Aplicación
Móvil
Aplicación de
Consola
Aplicación Web
Aplicación de
Escritorio
¿¿DDóónnddee iinnssttaallaarr eell ..NNEETT FFrraammeewwoorrkk??
ServidorServidorServidorServidor ClienteClienteClienteCliente
** SSóólloo ssii llaa aapplliiccaacciióónn eess ddiissttrriibbuuiiddaa
Maestría en Informática Aplicada a Redes
Página 75 de 159
3.7.2 Arquitectura
Windows COM+ Services
Common Language Runtime
Base Class Library
ADO.NET y XML
ASP.NET Windows Forms
Common Language Specification
VB C++ C# J# …
AArrqquuiitteeccttuurraa ddeell ..NNEETT FFrraammeewwoorrkk
.NE
T F
ram
ew
ork
R
edis
trib
uta
ble
.NE
T F
ram
ew
ork
SD
K
.NE
T F
ram
ew
ork
C
lass L
ibra
ry
CCrroonnoollooggííaa ddee ..NNEETT
Visual Studio 6.0 Visual Basic VBA Visual FoxPro VBScript C++ J++ JScript ASP
Visual Studio .NET 2003 .NET Framework 1.1 .NET Compact Framework J#
Visual Studio “Orcas” .NET Framework “Orcas” .NET Compact Framework “Orcas”
2000 2001 2002 2003 2004 2005 2006 y más
Visual Studio 2005 (“Whidbey”) .NET Framework 2.0 (“Whidbey”) .NET Compact Framework 2.0 (“Whidbey”)
Visual Studio .NET 2002 .NET Framework 1.0 Visual Basic .NET C#
Maestría en Informática Aplicada a Redes
Página 76 de 159
En la figura se pueden apreciar las distintas partes que componen al .NET Framework,
incluidas el entorno de ejecución de aplicaciones (CLR, en verde), el conjunto de
bibliotecas de funcionalidad reutilizable (.NET Framework Class Library, en azul) y los
compiladores y herramientas de desarrollo para los lenguajes .NET (en rojo). Todos estos
componentes se motan por encima de la familia de sistemas operativos Windows.
Dentro del conjunto de la .NET Framework Class Library se distinguen 4 sub-componentes
principales:
• La Base Class Library (BCL - Biblioteca de Clases Base), que contiene la
funcionalidad más comúnmente utilizada para el desarrollo de todo tipo de
aplicaciones. Algunos ejemplos de la funcionalidad provista por la BCL son el
manejo de colecciones, cadenas de texto, entrada/salida, threading, operaciones
matemáticas y dibujos 2D.
• ADO.NET, que contiene un conjunto de clases que permiten interactuar con bases
de datos relacionales y documentos XML como repositorios de información
persistente.
• ASP.NET, que constituye la tecnología dentro del .NET Framework para construir
aplicaciones con interfaz de usuario Web (es decir, aplicaciones cuya lógica se
encuentra centralizada en uno o varios servidores y que los clientes pueden acceder
usando un browser o navegador mediante una serie de protocolos y estándares como
HTTP y HTML).
• Windows Forms (o simplemente WinForms), que constituye la tecnología dentro
del .NET Framewok que permite crear aplicaciones con interfaz de usuario basada
en formularios y ventanas Windows que se ejecutan directamente en los clientes.
El modelo de ejecución que propone la plataforma .NET se suele definir como “virtual”, o
“de máquina virtual”, ya que las aplicaciones no son desarrolladas directamente contra las
APIs de programación expuestas por el sistema operativo, ni es éste el que se encarga de su
ejecución y ciclo de vida, sino que .NET provee un entorno de ejecución (el CLR) que
corre por sobre el sistema operativo y que es el encargado de ejecutar las aplicaciones y
proveerles servicios en tiempo de ejecución. A los componentes de software que se
Maestría en Informática Aplicada a Redes
Página 77 de 159
ejecutan de esta manera se los conoce comúnmente como “componentes manejados”, ya
que su ejecución es controlada por un entorno intermedio.
Una de las principales ventajas de contar con una plataforma virtual es que no están
“atadas” de ninguna forma con el sistema operativo y la plataforma de hardware
subyacente. Es sabido que una aplicación compilada para que utilice directamente las APIs
y servicios expuestos por un sistema operativo “x” muy difícilmente pueda ser ejecutada
en otro sistema operativo distinto sin ser recompilada. Las aplicaciones manejadas, en
cambio, descansan la tarea de su compilación a un código de máquina específico en el
entorno de ejecución. De esta manera, si existen distintos entornos de ejecución intermedia
para diferentes Sistemas Operativos, la misma aplicación puede ejecutarse en todos ellos si
necesidad de recompilarse.
El desarrollo de una aplicación .NET comienza con la escritura de su código fuente en
alguno de los lenguajes de alto nivel soportados por la plataforma. El mismo luego es
compilado obteniéndose un ejecutable (que en Windows normalmente llevan la extensión
.exe) o una biblioteca (que en Windows normalmente llevan la extensión .dll). A estos
componentes .NET resultantes del proceso de compilación se los denomina genéricamente
Assemblies, o Ensamblados.
Ahora bien, en lugar de contener código de máquina específico para el sistema operativo y
el hardware en el cual fueron compilados (nativo), los assemblies contienen un código
denominado MSIL (Microsoft Intermediate Language). EL MSIL es un set de instrucciones
independientes de cualquier CPU existente y que puede ser convertido a código nativo muy
eficientemente. MSIL incluye instrucciones para cargar, almacenar, inicializar e interactuar
con objetos y sus atributos y métodos, así como también instrucciones aritméticas y lógicas,
control de flujo, acceso directo a memoria, manejador de errores y otras operaciones. Antes
de que el código MSIL pueda ser ejecutado debe convertirse a código nativo específico
para un CPU y Sistema Operativo, tarea a cargo de los compiladores JIT incluidos en el
CLR.
Un Assembly es la menor unidad de ejecución y distribución de una aplicación .NET.
Maestría en Informática Aplicada a Redes
Página 78 de 159
Los assemblies son reutilizables, versionables y autodescriptivos, ya que no sólo contienen
el código MSIL que representa la lógica de la aplicación, sino que también incluyen
información sobre si mismos y sobre todos los recursos externos de los que dependen para
funcionar correctamente. A esta información se la denomina “Meta data” y forma una
parte integral de un assembly junto con el código MSIL ya que ambos no pueden estar
separados. La Meta data se ubica en una sección especial del Assembly denominada
“Manifest”, o “Manifiesto”, y es utilizada por el CLR a la hora de cargar y ejecutar el
Assembly.
La herramienta ildasm.exe (Intermediate Languaje Dissasembler, incluida en el .NET
Framework SDK) puede utilizarse para inspeccionar la meta data de un assembly.
Una aplicación .NET se compone, entonces, de uno o más assemblies. Otra de las
características de los Assemblies es que no necesitan estar registrados en la Registry de
Windows, como sus predecesores COM. De esta forma, instalar una aplicación .NET puede
ser tan simple como copiar todos los assemblies necesarios a la computadora de destino, y
basta con borrarlos a todos para tener una desinstalación limpia y completa.
Dado que .NET no depende de la Registry, y que cada assembly contiene información
acerca de su versión y las versiones de los componentes de que depende, múltiples
versiones de assemblies pueden coexistir sin ningún problema en la misma computadora.
Existen dos formas de que una aplicación pueda encontrar en tiempo de ejecución los
assemblies de los que depende:
1) Ubicarlos en el mismo directorio. Esta es la opción preferida si esos assemblies
sólo serán utilizados por esa única aplicación.
2) Ubicarlos en un repositorio centralizado de assemblies denominado Global
Assembly Cache, en el cual se instalan todos los assemblies que serán utilizados por
múltiples aplicaciones en la misma computadora. Para registrar un assembly en el
GAC es necesario utilizar otra herramienta incluida en el SDK llamada gacutil.exe.
Maestría en Informática Aplicada a Redes
Página 79 de 159
Uno de los objetivos de diseño de la plataforma .NET fue el ser independiente del lenguaje
de programación elegido para el desarrollo de aplicaciones. Para lograr esto es que se creó
la Especificación de Lenguaje Común (o CLS, por sus siglas en inglés), que define y
estandariza un subconjunto de todas las características soportadas por el CLR y que son
necesarias en la mayoría de las aplicaciones. Todos los componentes desarrollados y
compilados de acuerdo con la especificación CLS pueden interactuar entre si,
independientemente del lenguaje de programación de alto nivel en el que fueron escritos.
Junto con el .NET Framework, Microsoft provee implementaciones de 4 lenguajes
compatibles con CLS, junto con sus compiladores:
• Microsoft Visual Basic .NET
• Microsoft Visual C# .NET
• Microsoft Visual J#.NET
• Microsoft Visual C++.NET
Esto quiere decir que una aplicación escrita, por ejemplo, en Visual Basic.NET, puede
incorporar sin problemas nuevas partes escritas en C# o C++ .NET.
La infraestructura de lenguaje común (Common Language Infrastructure, CLI) es una
especificación estandarizada que describe un entorno virtual para la ejecución de
aplicaciones, cuya principal característica es la de permitir que aplicaciones escritas en
distintos lenguajes de alto nivel puedan luego ejecutarse en múltiples plataformas tanto de
hardware como de software sin necesidad de reescribir o recompilar su código fuente.
Si bien el CLI tuvo sus orígenes en Microsoft (en principio se pensaba desarrollar un
entorno de ejecución compartido para COM con el nombre de Common Object Runtime,
que luego de extendió y generalizó para dar lugar a CLI), sus especificaciones fueron
llevadas ante ECMA (European Computer Manufacturers Association), una organización
europea de estándares, para su estandarización en el año 2000.
Luego de un año de trabajo conjunto entre ECMA, Microsoft y otras empresas que co-
patrocinaron el proceso (Intel, HP, IBM y Fujitsu entre otras), el estándar ECMA-335 que
Maestría en Informática Aplicada a Redes
Página 80 de 159
define el entorno CLI finalmente vio la luz en diciembre de 2001. En abril del año 2003
ISO ratificó este estándar con el denominación ISO/IEC 23271:2003 .
Para comprender mejor la inclusión de cada una de las partes principales de la arquitectura
de CLI es interesante analizar los objetivos de diseño que se plantearon desde su
concepción. Según su especificación, la arquitectura de CLI debe:
• Permitir escribir componentes ínter operables independientemente de la plataforma
subyacente y del lenguaje de programación utilizado.
• Exponer todas las entidades programáticas a través de un único sistema unificado de
tipos (en la especificación, este sistema es conocido como CTS, o Common Type
System).
• Empaquetar todos los tipos en unidades completamente auto descriptivas y
portables.
• Cargar los tipos de forma tal que se encuentren aislados unos de otros en tiempo de
ejecución, pero que puedan a su vez compartir recursos.
• Resolver dependencias entre tipos en tiempo de ejecución usando una política
flexible que pueda tener en cuenta la versión, atributos de localización y políticas
administrativas.
• Ejecutar aplicaciones bajo la supervisión de un entorno privilegiado que permita
controlar y hacer cumplir políticas en tiempo de ejecución.
• Diseñar toda la infraestructura y servicios basándose en meta datos extensibles, de
manera tal que toda la arquitectura pueda acomodarse con poco impacto a nuevas
incorporaciones y cambios.
• Poder realizar tareas de bajo nivel, como carga de tipos en memoria, linkeo con
librerías y compilación a código nativo sólo cuando sea necesario (este enfoque se
conoce típicamente como “on demand”, o “just in time”).
• Proveer una serie de funcionalidades comunes mediante un grupo de librerías de
programación que los desarrolladores puedan utilizar para construir sus
aplicaciones.
Maestría en Informática Aplicada a Redes
Página 81 de 159
Microsoft .NET de hecho es un súper conjunto de esta especificación, es decir, provee todo
lo necesario para cumplir con la misma y además agrega una serie de herramientas,
librerías y funcionalidades no contempladas por ella originalmente y que proveen una
enorme utilidad y flexibilidad a los desarrolladores (por ejemplo, librerías para la creación
de aplicaciones y servicios web, acceso a motores de bases de datos, controles gráficos,
herramientas para desensamblar assemblies, debuggers, etc.). Si bien es gratuito, su código
fuente no es abierto, y es distribuido por Microsoft en versiones para sistemas operativos
Windows 98 y sus sucesores únicamente.
SSuubb--EEssppeecciiffiiccaacciioonneess ddee CCLLII
Lenguajes de Alto NivelLenguajes de Alto NivelLenguajes de Alto NivelLenguajes de Alto Nivel
BCL (Base Class Library)BCL (Base Class Library)BCL (Base Class Library)BCL (Base Class Library)
CLR (Common Language Runtime)CLR (Common Language Runtime)CLR (Common Language Runtime)CLR (Common Language Runtime)
Sistema OperativoSistema OperativoSistema OperativoSistema Operativo
CLS (Common Language Specification)CLS (Common Language Specification)CLS (Common Language Specification)CLS (Common Language Specification)
CTS (Common Type System)CTS (Common Type System)CTS (Common Type System)CTS (Common Type System)
se ajustan a las reglas de la…
y utilizan las clases de la…
cuyos tipos básicos forman el…
y se ejecutan bajo el control de y usan los servicios del…
que está acoplado al y utiliza los servicios del …
Maestría en Informática Aplicada a Redes
Página 82 de 159
La figura representa el modelo de compilación y ejecución de aplicaciones .NET, al cual
muchas veces se denomina “de compilación diferida”, o “de compilación en dos etapas”.
Esto es asi ya que el primer paso para poder ejecutar una aplicación dentro del CLR es
compilar su código fuente para obtener un assembly con código MSIL. Este paso es
realizado por cada uno de los compiladores de los distintos lenguajes de alto nivel
soportados por .NET.
Luego, el CLR se encarga de compilar el código MSIL a código nativo que hace uso
específico de los servicios del sistema operativo y la plataforma de hardware subyacente.
Todos los compiladores de los nuevos lenguajes .NET de Microsoft siguen este modelo de
ejecución, con excepción de C++ .NET, que es el único lenguaje al que se le ha dejado la
capacidad de emitir también código “no manejado”. Esto se debe a que ciertas aplicaciones,
como los drivers de dispositivos, necesitan tener acceso a los recursos del sistema operativo
a muy bajo nivel para lograr un rendimiento óptimo y mayor performance.
VVBB..NNEETT
CCóóddiiggoo FFuueennttee
CCoommppiillaaddoorr VVBB..NNEETT
CC++++..NNEETT CC##
AAsssseemmbbllyy CCóóddiiggoo MMSSIILL
SSiisstteemmaa OOppeerraattiivvoo ((WWiinnddoowwss))
CCoommmmoonn LLaanngguuaaggee RRuunnttiimmee
CCoommppiillaaddoorr JJIITT
CCóóddiiggoo NNaattiivvoo
CCóóddiiggoo MMaanneejjaaddoo
CCoommppoonneennttee NNoo MMaanneejjaaddoo
MMooddeelloo ddee EEjjeeccuucciióónn ddeell CCLLRR
CCoommppiillaaddoorr CC##
CCoommppiillaaddoorr CC++++ ..NNEETT
AAsssseemmbbllyy CCóóddiiggoo MMSSIILL
AAsssseemmbbllyy CCóóddiiggoo MMSSIILL
Maestría en Informática Aplicada a Redes
Página 83 de 159
3.7.3 ADO .Net 2.0
ADO.NET es un subconjunto de la .NET Framework Class Library, que contiene todas las
funcionalidades necesarias para conectarse e interactuar con dos tipos de repositorios
permamentes de información:
1) Bases de Datos, como Microsoft SQL Server (clases del namespace System.Data,
que se encuentran compiladas en System.data.dll)
2) Archivos XML (clases del namespace System.XML, que se encuentran compiladas
en System.Xml.dll)
La siguiente figura muestra el subconjunto.
La arquitectura de ADO.NET está basada en el concepto de proveedores de acceso a datos,
siendo un proveedor un conjunto de clases que permiten conectarse a una base de datos,
AAcccceessoo aa DDaattooss:: AADDOO..NNEETT
System.Data
OleDb
SqlClient
OracleClient
Common
Odbc SqlTypes
System.Xml
Serialization
XPath
XSLT
Schema
Maestría en Informática Aplicada a Redes
Página 84 de 159
ejecutar un comando sobre ella y tener acceso a los resultados de su ejecución, tanto de
forma conectada como desconectada.
Los proveedores de acceso a datos ADO.NET (conocidos como “Managed Data
Providers”) representan conjuntos específicos de clases que permiten conectarse e
interactuar con una base de datos, cada uno utilizando un protocolo particular. El .NET
Framework incluye cuatro proveedores de acceso a datos, que en conjunto le permiten
conectarse e interactuar virtualmente con cualquier base de datos existente en la actualidad:
• Data Provider For SQL Server: es el proveedor de acceso nativo a servidores de
bases de datos Microsoft SQL Server 7.0 o superior, y Microsoft Access. Al
conectarse vía protocolos nativos de bajo nivel, provee la alternativa más
performante para conexiones contra estos motores de bases de datos. Sus clases se
encuentran en el namespace System.Data.SqlClient.
• Data Provider For OLE DB: es el proveedor de acceso a datos que permite
interactuar vía el protocolo estándar OLE DB con cualquier repositorio de datos que
lo soporte. Sus clases se encuentran en el namespace System.Data.OleDb.
• Data Provider For ODBC: es el proveedor de acceso a datos que permite interactuar
vía el protocolo estándar ODBC con cualquier repositorio de datos que lo soporte.
Sus clases se encuentran en el namespace System.Data.Odbc.
• Data Porvider For Oracle: es el proveedor de acceso nativo a bases de datos Oracle,
desarrollado por Microsoft utilizando las herramientas de conectividad de Oracle.
De esta forma puede lograrse un acceso más performante a bases de datos Oracle
desde aplicaciones .NET que utilizando ODBC u OLE DB. Sus clases se encuentran
en el namespace System.Data.OracleClient, y están compiladas en un assembly
diferente al resto: System.Data.OracleClient.dll.
Maestría en Informática Aplicada a Redes
Página 85 de 159
En la figura se pueden apreciar las clases más comunes que componen a todos los
proveedores de acceso a datos de ADO.NET. Nótese que algunos nombres empiezan con
las letras “Xxx”: esto se debe a que los nombres de esas clases varían según el proveedor
específico que se esté utilizando. Por ejemplo, la clase que representa una conexión con la
base de datos usando el Data Provider For Sql Server es “SqlConnection”, mientras que si
usamos el Data Provider For Oracle podemos obtener la misma funcionalidad de la clase
“OracleConnection”.
● XxxConnection: representa una conexión. Almacena, entre otras cosas, el string de
conexión (connection string), y permite conectarse y desconectarse con una base de
datos.
● XxxCommand: permite almacenar y ejecutar una instrucción SQL contra una base
de datos, enviando parámetros de entrada y recibiendo parámetros de salida.
Estas dos clases se utilizan tanto en escenarios conectados como desconectados.
Base de Datos
XxxConnection
XxxCommand
DataSet XxxDataReader
XxxDataAdapter
Maneja la conección a una base de datos
Ejecuta comandos contra una base de datos
Copia local de datos relacionales
Provee acceso a datos read-only, Forward-only
Intercambia datos entre un dataset y una base de datos
AADDOO..NNEETT-- CCllaasseess mmááss ccoommuunneess
Maestría en Informática Aplicada a Redes
Página 86 de 159
● XxxDataReader: permite acceder a los resultados de la ejecución de un comando
contra la base de datos de manera read-only (sólo lectura), forward-only (sólo hacia
adelante). Esta clase se utiliza en escenarios conectados, ya que no es posible operar
sobre los registros de un DataReader estando desconectado de la fuente de datos.
● XxxDataAdapter y DataSet: en conjunto, estas clases constituyen el corazón del
soporte a escenarios desconectados de ADO.NET. El DataSet es una representación
en memoria de una base de datos relacional, que permite almacenar un conjunto de
datos obtenidos mediante un DataAdapter. El DataAdapter actúa como
intermediario entre la base de datos y el DataSet local desconectado. Una vez que el
DataSet se encuentra lleno con los datos que se necesitan para trabajar, la conexión
con la base de datos puede cerrarse sin problemas y los datos pueden ser
modificados localmente. Por último, el DataAdapter provee un mecanismo para
sincronizar los cambios locales contra el servidor de base de datos. Nótese que la
clase System.Data.DataSet no tiene el prefijo Xxx, ya que es independiente del
proveedor de acceso a datos utilizado.
ADO.NET provee una arquitectura extensible, posibilitando que terceras partes creen sus
propios proveedores de acceso nativo para aplicaciones .NET. Algunos ejemplos de esto
son:
• Data Provider For DB2, desarrollado por IBM
• Oracle Data Provider For .NET, desarrollado por Oracle
• Providers de acceso nativo a bases de datos OpenSource, como MySQL y
PostgreSQL
Maestría en Informática Aplicada a Redes
Página 87 de 159
ADO.NET es el sucesor de ADO (ActiveX Data Objects), la biblioteca de acceso a datos de
la plataforma COM. Si bien ADO soporta sólo escenarios conectados, puede resultar útil
hacer una analogía de las clases más comunes utilizadas en ADO con respecto a sus nuevas
versiones en ADO.NET:
• La clase Connection de ADO tiene su paralelo en las clases XxxConnection de los
distintos proveedores de ADO.NET
• La clase Command de ADO tiene su paralelo en las clases XxxCommand de los
distintos proveedores de ADO.NET
• La clase Recordset de ADO dejó de existir como tal en ADO.NET. En su lugar
existen en ADO.NET las clases XxxDataReader (es lo más parecido a un Recordset
read-only forward-only de ADO), y las nuevas clases DataSet y XxxDataAdapter
para escenarios desconectados.
AADDOO..NNEETT vvss.. AADDOO
Maestría en Informática Aplicada a Redes
Página 88 de 159
La figura ilustra una parte del soporte a XML provisto por el .NET Framework, que va
desde la simple lectura de un documento XML a su navegación, búsqueda y
transformaciones complejas.
• XmlReader – clase abstracta cuyo propósito es proveer un mecanismo de lectura
forward-only de un documento XML. Tiene tres clases derivadas:
• XmlTextReader – utilizada para leer datos de un documento XML o un
stream. Se utiliza normalmente cuando la performance de lectura es un
factor clave y todo el sobreprocesamiento de DOM debe evitarse.
• XmlValidatingReader – similar a XmlTextReader, pero pensada para
validaciones DOM.
• XmlNodeReader – permite leer datos de un nodo XML.
• XmlTextWriter – permite que datos XML puedan ser escritos a un archivo XML o
a un stream, y puede además proveer mecanismos de validación para asegurar que
sólo datos XML válidos y bien formados sean escritos.
XXmmllTTeexxttWWrriitteerr
XXmmllTTeexxttRReeaaddeerr
<<XXMMLL>>
XXmmllDDooccuummeenntt
DDooccuummeennttNNaavviiggaattoorr
XXmmllRReeaaddeerr
XXmmllVVaalliiddaattiinnggRReeaaddeerr XXmmllNNooddeeRReeaaddeerr
AADDOO..NNEETT -- SSooppoorrttee aa XXMMLL
Maestría en Informática Aplicada a Redes
Página 89 de 159
• XmlDocument – esta es una clase compleja que actúa como un contenedor de datos
XML, representando en un modelo de objetos en memoria toda la estructura de un
documento XML. Esto permite tener facilidades de navegación y edición, pero a un
cierto costo de performance y consumo de recursos.
• DocumentNavigator – permite navegar libremente la estructura de un documento
XML una vez que ha sido cargado dentro de una instancia de la clase
XmlDocument.
Maestría en Informática Aplicada a Redes
Página 90 de 159
IV. Solución Propuesta
El presente capitulo, describe la conceptualización, elaboración y construcción de la
solución propuesta. De esta forma que se detallan los requerimientos base con los que se
inicio la conceptualización y diseño de la solución, los criterios y estimaciones de diseño y
finalmente se muestra la implementación del diseño utilizando código C#.
La propuesta se plantea, presentando inicialmente el modelado general de la solución
describiendo elementos de arquitectura considerados y las características generales
propuestas. Posteriormente se presenta la funcionalidad básica que debe de implementar
aislando en secciones cada funcionalidad con sus requerimientos, sus criterios de diseño y
su implementación, con el fin de que sea mas sencillo detallar la construcción de cada
sección especifica de la solución propuesta.
4.1 Modelado de la solución
4.1.1 Consideraciones Iniciales
Dado que nuestra solución pretende reforzar y promover el uso de un diseño y construcción
completamente orientado a objetos, esto requiere la utilización de una arquitectura
multicapas como las mostrada en el siguiente diagrama.
<<Usa>>
<<Usa>><<Crea>>
<<Usa>>Presentación Negocio Acceso a Datos
Dominio
Para el diseño del core del sistema se construirá un modelo de dominio basados en el patrón
Domain Value Object, donde en ves de diseñar tablas o un modelo ER, se diseñaran clases
Maestría en Informática Aplicada a Redes
Página 91 de 159
que encapsulen datos y comportamiento siguiendo las características de la orientación a
objetos.
El motor de persistencia a construir implementará funcionalidad de la capa de Acceso a
Datos, por lo que es en este nivel donde definirá el ambiente, estándares y características
bajo los cuales trabajara la propuesta.
Debido que existen una serie de patrones de diseño disponibles para el Acceso a Datos, se
ha decido tomar el patrón utilizado en la plataforma J2EE denominado DAO (Data Access
Object)4. Este patrón proporcionara los siguientes beneficios a nuestro diseño.
• DAO define una relación uno a uno entre clases de dominio y de acceso a datos
• Cada clase de dominio tendrá asociada una clase de DAO de acceso a datos lo que
permitirá no mezclar operaciones entre clases e identificar rápidamente la clase
responsable de cada entidad.
• El uso de DAO proporciona una alta cohesión ya que todos los métodos
transaccionales de una clase están relacionados a una sola clase de dominio y el
acoplamiento entre clases DAO es bastante bajo.5
• El uso de DAO permitirá una alta reusabilidad de las clases implementadas.
Dado que por cada clase de
dominio tendremos una clase
de acceso a datos, podemos
considerar el diseño de una
clase maestra que contenga la
funcionalidad genérica del
motor de persistencia y sea
heredado a cada una de las
clases DAO de la aplicación.
Esto se muestra en el diagrama
adjunto.
4 Para mas información sobre el patrón DAO consultar la sección 3.2.9 5 Para mas información sobre Acoplamiento y Cohesión remitirse a la sección 3.2.2
<<Crea>> <<Crea>> <<Crea>> <<Crea>>
DAOMaster
DAOCliente DAOFactura DAOProductoDAOItem
Cliente Factura ProductoItem
Maestría en Informática Aplicada a Redes
Página 92 de 159
4.1.2 Namespaces y Assemblies.
La funcionalidad principal del motor de persistencia será encapsulada en una clase a la que
se denominará DAOMaster la cual deberá ser heredada, por lo que se definirá de tipo
abstracta. Adicionalmente esta clase dependerá de los servicios de otras clases encargadas
de crear conexiones y otros tipos de objetos. Toda esta funcionalidad se definirá y agrupará
dentro de un solo namespace el cual será denominado DAOMasterLibrary con el fin de
que solo sea incorporado en la lógica de las capa de acceso datos de las aplicaciones que
utilicen esta herramienta.
Así a la hora de diseñar la arquitectura de una aplicación la lógica de acceso a datos será
heredada de este namespace, esto como se muestra en el siguiente diagrama:
<<Usa>><<Crea>>
<<Usa>>
DAOMasterLibrary
Negocio Acceso a Datos
Dominio
Finalmente la implementación del motor de persistencia, estará contenida en un solo
Assembly o librería de clases DLL la cual será denominada DAOMasterLibrary.dll . Este
podrá ser incorporado en cualquier proyecto de desarrollo, simplemente al agregar una
referencia a esta librería y seguir el esquema propuesto.
Finalmente el motor de persistencia debe de implementar ciertas características como la
Sincronización de la Estructura del Modelo de Dominio con el modelo ER donde se
persistirán los datos, generación automática de las sentencias de inserción, actualización y
Maestría en Informática Aplicada a Redes
Página 93 de 159
eliminación, carga de objetos, implementar las características anteriores independientes del
sistema RDBMS o contenedor usado, parametrización, etc. Todas estas característicos son
explicadas en la secciones siguientes del presente capitulo.
4.2 Sincronización Estructura ER y Modelo de Dominio
4.2.1 Planteamiento del Requerimiento
Dado que la persistencia de datos es una característica que debemos de implementar sobre
el modelo de dominio, es necesario que la funcionalidad del motor de persistencia a crear
contenga un mecanismo a través del cual se mantenga una relación bien sincronizada entre
el modelo de dominio y su respectivo equivalente en el RDBMS. Esta sincronización debe
de garantizar que cada instancia de una clase del Dominio pueda ser persistida como una o
varias filas en una o varias tablas especificas, de la misma forma se debe de garantizar que
la filas de las tablas puedan ser cargadas dentro de objetos en tiempo de ejecución.
Las operaciones antes mencionadas requieren que exista una forma de indicar al Motor una
relación uno a uno entre tablas y clases así como también relaciones uno a uno entre
columnas de una tabla y las propiedades de una clase.
Se debe de considerar como parte del requerimiento que esta operación de mapeo requiera
el menor tiempo posible al desarrollador, de tal forma que no le rastrase o le obligue a
realizar complejos o detallados mapeos entre cada propiedad de una tabla y las propiedades
de una clase.
4.2.2 Diseño de la Solución
Motores de persistencia como Hibernate o NHIbernate utilizan un archivo XML para
definir el mapeo entre clases y tablas. Para nuestro caso se ha considerado automatizar
totalmente dicho mapeo, sin embargo esta funcionalidad supone que el desarrollador
utilizará una herramienta CASE que le permita modelar un sistema en un diagrama de
clases, es decir construir un modelo de dominio y su respectivo código C# y a partir de este
generar el DDL para ser ejecutado en el RDBMS y construir de esa forma el ER a partir del
diagrama de clases. Este mecanismo solucionara el problema de mantener sincronizado
ambos modelos, asignando dicha responsabilidad a la herramienta CASE.
Maestría en Informática Aplicada a Redes
Página 94 de 159
4.2.2.1 Diseñando la Clase de Dominio
Por ejemplo para el modelamiento de los usuarios de un sistema, se diseña la siguiente
clase:
Usuario
-
-
-
-
-
-
-
-
-
-
-
-
-
-
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
usuarioID
usuarioNombres
usuarioApellidos
usuarioEmail
usuarioCelular
usuarioPassword
fechaActualizacion
_usuarioID
_usuarioNombres
_usuarioApell idos
_usuarioEmail
_usuarioCelular
_usuarioPassword
_fechaActualizacion
: string
: string
: string
: string
: string
: string
: Datetime
: string
: string
: string
: string
: string
: string
: Datetime
+
+
+
+
-
+
-
+
+
+
+
+
+
+
-
+
+
+
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
Usuario (string sUsuarioCuenta, string sUsuarioNombre, string sUsuarioPassword)
encriptarClave ()
validarClave (string sPassword)
cambiarPassword (string sPasswordAnterior, string sNuevoPassword)
set_usuarioID (string value)
get_usuarioID ()
set_usuarioNombres (string value)
get_usuarioNombres ()
set_usuarioApell idos (string value)
get_usuarioApellidos ()
set_usuarioEmail (string value)
get_usuarioEmail ()
set_usuarioCelular (string value)
get_usuarioCelular ()
set_usuarioPassword (string value)
get_usuarioPassword ()
set_fechaActualizacion (Datetime value)
get_fechaActualizacion ()
: void
: int
: bool
: int
: void
: string
: void
: string
: void
: string
: void
: string
: void
: string
: void
: string
: void
: Datetime
Se puede notar de esta clase que tiene 7 propiedades las cuales son privadas, es decir no
pueden ser acezadas directamente, sino solamente a través de la propiedades (getter y
setter) las cuales son métodos con el mismo nombre que los atributos de la clase, esta es la
implementación del Data Hidding y de la Encapsulación de objeto.
Adicionalmente se han agregado las siguientes reglas de negocio a este modelo:
• No es posible crear una nueva instancia de un objeto Usuario si no se cuenta con los
datos obligatorios UsuarioID, UsuarioNombre y UsuarioClave. Estos son
parámetros obligatorios del Constructor de la Clase.
Maestría en Informática Aplicada a Redes
Página 95 de 159
• No es posible cambiar las propiedades UsuarioID, UsuarioNombre e UsuacioClave
esta ultima solo puede ser cambiada a través del método cambiarPassword. Debido
a esto los Setter de la propiedades UsuarioID, UsuarioNombre y UsuarioClave, si
bien existen son privados por lo que no pueden ser invocados externamente.
• La clase cuenta con un método privado encriptarClave el cual se encarga de
codificar la clave del usuario de tal forma que este encriptada al momento que el
usuario sea persistido
• La clase Usuario cuenta con el método validarClave la cual recibe una cadena de
texto y devuelve un valor verdadero si es la clave asignada al usuario o falso si no
es así
Estas propiedades y métodos que mantienen un alto grado de cohesión permitirán dar a esta
clase la responsabilidad única de representar a los usuarios manteniendo un bajo grado de
acoplamiento de tal forma que el objeto pueda ser reutilizable.
El código generado por el case para esta clase, es el siguiente:
public class Usuario {
private string _usuarioID;
private string _usuarioNombres;
private string _usuarioApellidos;
private string _usuarioEmail;
private string _usuarioCelular;
private string _usuarioPassword;
private Datetime _fechaActualizacion;
public sealed void Usuario(string sUsuarioCuenta, string sUsuarioNombre, string
sUsuarioPassword) {
// TODO: implement
}
public sealed int encriptarClave() {
// TODO: implement
return 0;
}
public sealed bool validarClave(ref string sPassword) {
// TODO: implement
return false;
}
Maestría en Informática Aplicada a Redes
Página 96 de 159
public sealed int cambiarPassword(ref string sPasswordAnterior, ref string
sNuevoPassword) {
// TODO: implement
return 0; }
private string usuarioID {
get {
return _usuarioID;
}
Set {
if (this._usuarioID != value)
this._usuarioID = value;
}
}
private string usuarioNombres {
get {
return _usuarioNombres;
}
Set {
if (this._usuarioNombres != value)
this._usuarioNombres = value;
}
}
private string usuarioApellidos {
get {
return _usuarioApellidos;
}
Set {
if (this._usuarioApellidos != value)
this._usuarioApellidos = value;
}
}
private string usuarioEmail {
get {
return _usuarioEmail;
}
Set {
if (this._usuarioEmail != value)
this._usuarioEmail = value;
}
}
private string usuarioCelular {
get {
return _usuarioCelular;
}
Set {
if (this._usuarioCelular != value)
Maestría en Informática Aplicada a Redes
Página 97 de 159
this._usuarioCelular = value;
}
}
private string usuarioPassword {
get {
return _usuarioPassword;
}
Set {
if (this._usuarioPassword != value)
this._usuarioPassword = value;
}
}
Private Datetime fechaActualizacion {
Get {
return _fechaActualizacion;
}
Set {
if (this._fechaActualizacion != value)
this._fechaActualizacion = value;
}
}
}
4.2.2.2 Diseñando el Modelo Físico en el RDBMS Habiendo finalizado el modelo de dominio, podemos utilizar el CASE para que nos genere
el modelo Físico orientado a un sistema RDBMS especifico, para nuestro caso, generamos
el modelo físico especificando Microsoft SQL Server como RDBMS y el CASE nos genero
la siguiente tabla Usuario
usuarioID
usuarioNombres
usuarioApell idos
usuarioEmail
usuarioCelular
usuarioPassword
fechaActual izacion
varchar(50)
varchar(100)
varchar(100)
varchar(100n)
varchar(8)
varchar(100)
Datetime
<pk>
El DDL de dicha clase es el siguiente
create table Usuario ( usuarioID varchar(50) not null, usuarioNombres varchar(100) not null, usuarioApellidos varchar(100) null, usuarioEmail varchar(100n) null, usuarioCelular varchar(8) null, usuarioPassword varchar(100) not null, fechaActualizacion Datetime not null, constraint PK_USUARIO primary key (usuarioID) )
Este puede ya ser ejecutado contra la base de datos para definir el ER de nuestro sistema.
Maestría en Informática Aplicada a Redes
Página 98 de 159
4.2.3 Construcción de la Solución.
Los siguientes, son mas que construcciones dentro del prototipo, son bien lineamientos que
deberán seguirse al construir la aplicación particular para garantizar que el motor de
persistencia identifique la relación entre clases y tablas.
Se deberá construir un namespace denominado Dominio dentro del cual deberán de
declararse todas las clases de dominio que formen el aplicativo. Entonces el código
generado por el case quedaría de la siguiente manera:
Namespace Dominio {
public class Usuario {
private string _usuarioID;
private string _usuarioNombres;
private string _usuarioApellidos;
private string _usuarioEmail;
private string _usuarioCelular;
private string _usuarioPassword;
private Datetime _fechaActualizacion;…
…
}
}
Para cada clase de dominio se deberá crear una clase DAO en cuyo constructor se declare a
través de la ejecución del método setDoName el nombre de la tabla del ER al cual esta
mapeada dicha clase. Por nomenclatura el nombre de la clase deberá ser la cadena “DAO”
mas el nombre de la clase de dominio. Estas clases DAO deberán ser definidas dentro de un
namespace denominado “AccedoDatos” y cada clase deberá ser heredada de la clase
DAOMaster.
Para la clase de Dominio Usuario, la clase de acceso a datos quedaría de la siguiente forma:
using System; using System.Data;
using DAOMasterLibrary;
using Dominio;
namespace AccesoDatos
{
Maestría en Informática Aplicada a Redes
Página 99 de 159
class DAOUsuario : DAOMaster
{
public DAOUsuario()
{
this.setDOName("usuario");
}
}
}
4.3 Generación de operaciones transaccionales
4.3.1 Planteamiento del Requerimiento
El sistema a implementar debe de generar las operaciones de inserción, actualización y
eliminación de forma automática, recibiendo como insumo únicamente una instancia del
objeto a procesar.
Dado que el motor de persistencia trabaja en la capa de acceso a datos, será a este nivel
donde deberán de estar disponibles métodos para adicionar, actualizar y eliminar objetos.
Los cuales recibirán una instancia y generarán las operaciones pertinentes de la forma mas
eficiente posible. Esto significa para el caso de la actualización por ejemplo solo actualizar
las propiedades que hayan cambiado y no toda la fila.
4.3.2 Diseño de la Solución
Dado el requerimiento anterior, se han diseñado tres métodos concretos los cuales se
describen a continuación:
Método Parámetros Descripción
1 add Domain Object Adiciona el objeto 2 Update Domain Object Actualiza las propiedades del objeto que han
cambiado 3 Delete Domain Object Elimina el Objeto
4.3.2.1 Método para la inserción de registros. El método Add que será implementado en la Capa de acceso a Datos para ser usado en la
capa de negocios, tendrá la responsabilidad de recibir una instancia de un Domain Object y
convertirlo a un registro de la correspondiente tabla mapeada, generando la correspondiente
Maestría en Informática Aplicada a Redes
Página 100 de 159
sentencia insert. Para desarrollar esta tarea dicho método, se auxiliara de una serie de
métodos privados siguiendo la secuencia que se muestra en el siguiente diagrama:
Los métodos utilizados en la secuencia anterior se describen a continuación:
Método Descripción
SetdoName Método Setter que establece el nombre de la clase a procesar getSchema Obtiene el esquema de la tabla identificada por el nombre del objeto getPropierties Recibe la instancia del objeto a persistir y un Datarow vació con la
estructura de la tabla, barre la instancia y asigna los valores de cada propiedad a su respeciva columna en el datarow, devolviendo el datarow poblado
saveDS Toma un Dataset y genera una sentencia insert para el datarow contenido
4.3.2.2 Método para la actualización de registros. El método update a implementar en la Capa de Acceso a Datos. Recibirá la referencia del
objeto de dominio a actualizar y tendrá la responsabilidad de generar la sentencia update
Setear Nombre Objeto
Solicitar Esquema
Devuelve Esquema Tabla
Crear Row a paritr de esquema Envio de objeto y DataRow vacío
DataRow poblado con propiedades de objeto
Adicionar Datarow a Dataset
Envio DataSet envio de sentencia Insert generada
Resultado Exito o Exepción Exito o Exepción
Solicitar Pk de registro insertado
PK insertado
add setdoName getSchema getPropierties saveDS getID RDBMS
Setear Nombre Objeto
Solicitar Esquema
Devuelve Esquema Tabla
Crear Row a paritr de esquema Envio de objeto y DataRow vacío
DataRow poblado con propiedades de objeto
Adicionar Datarow a Dataset
Envio DataSet envio de sentencia Insert generada
Resultado Exito o Exepción Exito o Exepción
Solicitar Pk de registro insertado
PK insertado
Maestría en Informática Aplicada a Redes
Página 101 de 159
basado en los primary keys del registro actualizando únicamente las columnas que han
cambiado.
Para realizar esta actividad el método update, se Valera de la ayuda de una serie de métodos
privados, siguiendo la secuencia del diagrama siguiente:
Los métodos utilizados en la secuencia anterior se describen a continuación:
Método Descripción
SetdoName Método Setter que establece el nombre de la clase a procesar getSchema Obtiene el esquema de la tabla identificada por el nombre del objeto getPropierties Recibe la instancia del objeto a persistir y un Datarow vació con la
estructura de la tabla, barre la instancia y asigna los valores de cada
Setear Nombre Objeto
Solicitar Esquema
Devuelve Esquema Tabla
Crear DataSet a paritr de esquema
Envio de objeto y DataRow vacío
DataRow poblado con propiedades de objeto
Asignar nuevo valores a existentes en DataRow
Envio DataSet envio de sentencia update generada
Resultado Exito o Exepción Exito o Exepción
Generar Where para registro a partir de primaries Keys
Sentencia Where ejecutar select con el where construido
DataRow poblado
Asignar Datarow poblado a DataSet Creado
update setDoName getSchema getPropierties saveDS getStrWhere RDBMS2
Setear Nombre Objeto
Solicitar Esquema
Devuelve Esquema Tabla
Crear DataSet a paritr de esquema
Envio de objeto y DataRow vacío
DataRow poblado con propiedades de objeto
Asignar nuevo valores a existentes en DataRow
Envio DataSet envio de sentencia update generada
Resultado Exito o Exepción Exito o Exepción
Generar Where para registro a partir de primaries Keys
Sentencia Where ejecutar select con el where construido
DataRow poblado
Asignar Datarow poblado a DataSet Creado
Maestría en Informática Aplicada a Redes
Página 102 de 159
propiedad a su respectiva columna en el datarow, devolviendo el datarow poblado
saveDS Toma un Dataset y genera una sentencia update para el datarow contenido getWhere Genera un string que servirá como filtro where para un Quero, esta
sentencia esta formada por las columnas definidas como Primary Keys para la tabla mapeada así como el valor respectivo que hace único al registro
4.3.2.3 Método para la eliminación de registros El método delete que implementara el motor de persistencia, recibirá un objeto de dominio
y partir de esto deberá de generar la sentencia delete respectiva filtrada por las columnas
que forman la primary Key y sus valores respectivos. Al igual que los casos de adición y
actualización el método se auxiliara de métodos privados, siguiendo la secuencia mostrada
en el siguiente diagrama:
Los métodos utilizados en la secuencia anterior se describen a continuación:
Método Descripción
SetdoName Método Setter que establece el nombre de la clase a procesar getStrWhere Genera un string que servirá como filtro where para un Quero, esta
sentencia esta formada por las columnas definidas como Primary Keys para la tabla mapeada así como el valor respectivo que hace único al registro
execSQL Ejecuta una sentencia SQL
Setear Nombre Objeto
Contruir Where con Primary keys String para where
Envio de sentencia delete con where creado
Exito o Exepcion
Ejecutar Delete
Exito o Exepcion
delete setdoName execSQL getStrWhere RDBMS
Setear Nombre Objeto
Contruir Where con Primary keys String para where
Envio de sentencia delete con where creado
Exito o Exepcion
Ejecutar Delete
Exito o Exepcion
Maestría en Informática Aplicada a Redes
Página 103 de 159
4.3.3 Construcción de la Solución
En esta sección se muestra el código de los métodos implementados para soportar las
operaciones de adición, actualización y eliminación siguiendo la lógica y secuencias
planteados en el diseño de los mismos.
4.3.3.1 Método Add Este método público recibe un Domain Object e intenta persistirlo en Data Source
especificado. El código de dicho método es el siguiente:
// Salva el Domain Object en el Datasource
public long add(object aDO) {
try {
setDOName(aDO.GetType().Name.ToString());
DataSet oDS = new DataSet() ;
oDS.ReadXmlSchema(getSchema());
DataRow oRow = oDS.Tables[0].NewRow();
getPropiedades(oRow,aDO);
oDS.Tables[0].Rows.Add(oRow);
saveDS(oDS);
} catch (Exception ex) {
throw new Exception("Error Insertando objeto " + this._doName + " / " +
ex.Message);
}
return getID();
}
Puede observarse que debido a que el parámetro es un objeto de tipo Domain Object que
puede ser en si cualquier objeto, es necesario la utilización de “Late Binding” al momento
de definir el tipo de dato del argumento recibido.
El método ADD utiliza se vale de una serie de modos como se mostró en la secuencia del
diseño, el código de estos métodos es mostrado a continuación:
// Devuelve el Schema en formato XML StrinReader de la estructura de persistencia
del Domain Object actual
private System.IO.StringReader getSchema() {
string sXML = this.getDsSchema().GetXmlSchema();
return new System.IO.StringReader(sXML);
}
//Función privada que ejecuta y devuelve el Schema del Objeto mapeado private DataSet getDsSchema(){
if (dsSchema != null) return dsSchema;
else
{
Maestría en Informática Aplicada a Redes
Página 104 de 159
DataSet ds;
DbCommand oCommand;
DbDataAdapter oAdapter;
string SqlString = "select * from " + this._doName;
try
{
if (setConnection())
{
ds = new DataSet();
oCommand = _oCon.CreateCommand();
oAdapter = dbFactory.CreateDataAdapter();
oCommand.Connection = _oCon;
oCommand.CommandType = CommandType.Text;
oCommand.CommandText = SqlString;
oAdapter.SelectCommand = oCommand;
oAdapter.FillSchema(ds, SchemaType.Mapped);
dsSchema = ds;
}
else
{
return null;
}
}
catch (Exception ex)
{
throw ex;
}
return ds;
}
}
// Obtiene las propiedades de un Domain Object asignandolas a un DataRow a
traves de invocaciones dinamicas a los Getter
private void getPropiedades(DataRow aRow, object aDO){
PropertyInfo[] oProperties;
string sPropertyName="";
MethodInfo oMetodo;
try {
oProperties =
aDO.GetType().GetProperties(BindingFlags.NonPublic|BindingFlags.Instance|BindingF
lags.Static|BindingFlags.Public);
foreach(PropertyInfo oProperty in oProperties) {
sPropertyName = oProperty.Name.ToString();
oMetodo = oProperty.GetGetMethod(true);
switch (oMetodo.ReturnType.ToString()) {
case "System.String":
aRow[sPropertyName] = (string)oMetodo.Invoke(aDO, null);
break;
case "System.DateTime":
aRow[sPropertyName] = (DateTime)oMetodo.Invoke(aDO, null);
break;
case "System.Int16":
aRow[sPropertyName] = (Int16)oMetodo.Invoke(aDO, null);
break;
case "System.Int32":
aRow[sPropertyName] = (Int32)oMetodo.Invoke(aDO, null);
break;
case "System.Int64":
aRow[sPropertyName] = (Int64)oMetodo.Invoke(aDO, null);
break;
case "System.Decimal":
aRow[sPropertyName] = (Decimal)oMetodo.Invoke(aDO, null);
break;
case "System.Double":
Maestría en Informática Aplicada a Redes
Página 105 de 159
aRow[sPropertyName] = (Double)oMetodo.Invoke(aDO, null);
break;
case "System.Boolean":
aRow[sPropertyName] = (Boolean)oMetodo.Invoke(aDO, null);
break;
case "System.Char":
aRow[sPropertyName] = (Char)oMetodo.Invoke(aDO, null);
break;
}
}
} catch(Exception ex) {
throw new Exception("Error accesando la propiedad " + sPropertyName + " /
" + ex.Message);
}
}
// Objetivo: Actualizar el Dataset en el DataSource
private int saveDS(DataSet ds)
{
string sSQL = "select * from " + this._doName;
DbDataAdapter oAdapter;
DbCommandBuilder oCBuilder;
int iResult = 0;
if (setConnection())
{
try
{
oAdapter = dbFactory.CreateDataAdapter();
oAdapter.SelectCommand.CommandText = sSQL;
oAdapter.SelectCommand.Connection = this._oCon;
oCBuilder = dbFactory.CreateCommandBuilder();
oCBuilder.DataAdapter = oAdapter;
iResult = oAdapter.Update(ds);
oAdapter.Dispose();
oAdapter = null;
}
catch (Exception ex)
{
throw new Exception("Error actualizando objeto " + this._doName + " / " +
ex.Message);
}
}
return iResult;
}
4.3.3.2 Método Update. Este método público recibe un Domain Object e intenta actualizarlo en el Data Source
especificado. El código de dicho método es el siguiente:
Maestría en Informática Aplicada a Redes
Página 106 de 159
//Actualizar el Domain Object en el Datasource
public bool update(object aDO) {
this.setDOName(aDO.GetType().Name.ToString());
try {
string sSQL = "select * from " + this._doName + " " + this.getWhere(aDO);
DataSet oDS, fDS;
fDS = new DataSet();
fDS.ReadXmlSchema(getSchema());
oDS = getDS(sSQL);
DataRow oRow = oDS.Tables[0].Rows[0];
DataRow fRow = fDS.Tables[0].NewRow();
foreach(DataColumn oColumn in oDS.Tables[0].Columns) {
fRow[oColumn.ColumnName.ToString()] =
oRow[oColumn.ColumnName.ToString()];
}
fDS.Tables[0].Rows.Add(fRow);
fDS.AcceptChanges();
getPropiedades(fRow, aDO);
saveDS(fDS,true,aDO);
} catch(Exception ex) {
throw new Exception("Error actualizando objeto " + this._doName + " / " +
ex.Message);
}
return true;
}
El método actualizar se vale de los mismos métodos que Add, es decir los métodos
getSchema(), readXMLSchema(),getPropiedades() y saveDS() incorpora además el método
getDS() y getWhere() de los cuales se muestra el código a continuación:
//Función protected que ejecuta y devuelve un DataSet
protected DataSet getDS(string SqlString){
DataSet ds;
DbCommand oCommand = _oCon.CreateCommand();
DbDataAdapter oAdapter = dbFactory.CreateDataAdapter();
try {
if(setConnection()) {
ds = new DataSet() ;
oCommand.Connection = _oCon;
oCommand.CommandType = CommandType.Text;
oCommand.CommandText = SqlString;
oAdapter.SelectCommand = oCommand;
oAdapter.Fill(ds);
} else {
return null;
}
} catch(Exception ex) {
throw ex;
}
return ds;
}
// Generar la Sentencia where correspondiente usando los primary key y sus
valores
private string getWhere(object aDO)
{
DataColumn[] colArr;
string sWhere = "", sColumn, sAND, sType;
DataSet ds;
DataRow fila;
Maestría en Informática Aplicada a Redes
Página 107 de 159
int ikeys;
try
{
ds = getDsSchema();
fila = ds.Tables[0].NewRow();
getPropiedades(fila,aDO);
colArr = ds.Tables[0].PrimaryKey;
ikeys = colArr.Length;
sColumn = "";
sWhere = " where ";
if (ikeys == 0) throw new Exception("Objeto " + _doName + " no tiene definido
Primary Key en el ER, imposible continuar");
for (int i = 1; i < ikeys; i++) {
sAND = (i>0)? " AND ":"";
sColumn = colArr[i].ColumnName;
sType = colArr[i].DataType.Name.ToString();
if(sType.CompareTo("String")==0||sType.CompareTo("Char")==0) {
sWhere += sAND + sColumn + " = '" + fila[sColumn] + "'";
} else {
sWhere += sAND + sColumn + " = " + Convert.ToString(fila[sColumn]) +
" ";
}
}
}
catch (Exception ex) {
throw new Exception("Error obteniendo Primary Keys / " + ex.Message);
}
return sWhere;
}
4.3.3.3 Método Delete Este método público recibe un Domain Object e intenta eliminarlo del Data Source
especificado. El código de dicho método es el siguiente:
// Elimina el DVO en el Datasource
public bool delete(object aDO) {
try {
setDOName(aDO.GetType().Name.ToString());
string sSQL = "delete from " + this._doName + " " + getWhere(aDO);
execSQL(sSQL);
} catch(Exception ex) {
throw new Exception("Error eliminando objeto " + this._doName + " / " +
ex.Message);
}
return true;
}
Este método utiliza el mismo método getWhere utilizado en el Update, incorpora además
un nuevo método de tipo protected denominado execSQL. El código de este método se
muestra a continuación:
Maestría en Informática Aplicada a Redes
Página 108 de 159
// Ejecutar un SQL
protected bool execSQL(string sSQL) {
DbCommand oCommand;
if(setConnection()) {
oCommand = dbFactory.CreateCommand();
try {
oCommand.CommandText = sSQL;
oCommand.Connection = this._oCon ;
oCommand.ExecuteNonQuery();
} catch(Exception ex) {
throw ex;
}finally {
oCommand.Dispose();
oCommand = null;
}
} else return false;
return true;
}
4.4 Construcción y Cargas de los Objetos
4.4.1 Planteamiento del Requerimiento
El motor de persistencia, debe de ser capas de recuperar un objeto indicando únicamente el
ID del objeto a recuperar.
4.4.2 Diseño de la Solución
Dado el requerimiento anterior, se han diseñado dos métodos para realizar la carga de un
objeto a través de su ID
Método Parámetros Descripción 1 cargar ID de tipo numérico Devuelve la instancia de la clase llena con las
propiedades identificados por el ID numérico dado
2 cargar ID de tipo string Devuelve la instancia de la clase llena con las propiedades identificados por el ID string dado
El método “cargar” hace uso de los servicios proporcionados por otros métodos de la
misma clase, esto se muestra en la siguiente secuencia:
Maestría en Informática Aplicada a Redes
Página 109 de 159
Contruir Where con ID enviado
String para where
Envio de sentencia sql con filtro por ID
Exito o Exepcion
Solicitar Registro
Exito o Exepcion
Envio de Registro y Domain Object
Domain Object Poblado
Enviar SQL y Solicitar Objeto
Instancia Domain Object Poblado
Identificación de Tipo de Objeto
Creación de instancia de Tipo de Objeto
cargar getObject getDSgetWhereID RDBMSsetPropiedades
Contruir Where con ID enviado
String para where
Envio de sentencia sql con filtro por ID
Exito o Exepcion
Solicitar Registro
Exito o Exepcion
Envio de Registro y Domain Object
Domain Object Poblado
Enviar SQL y Solicitar Objeto
Instancia Domain Object Poblado
Identificación de Tipo de Objeto
Creación de instancia de Tipo de Objeto
4.4.3 Construcción de la Solución
El código C# del método sobrecargado “cargar” tanto en su versión para id numérico como string, se muestra a continuación: // Metodo cargar para menejo de ID numericos public object cargar(long id)
{
string sSQL;
object aDO;
try
{
sSQL = "select * from " + this._doName + getWhereID(id);
aDO = getObject(sSQL);
}
catch (Exception ex)
{
throw ex;
}
return aDO;
}
// Metodo cargar para menejo de ID string public object cargar(string id)
{
string sSQL;
object aDO;
try
{
Maestría en Informática Aplicada a Redes
Página 110 de 159
sSQL = "select * from " + this._doName + getWhereID(id);
aDO = getObject(sSQL);
}
catch (Exception ex)
{
throw ex;
}
return aDO;
}
El método cargar una ves construido el SQL con filtro Where, delega la responsabilidad de creación y poblado de los datos al método getObjet, el código de este método, se muestra a continuación: //Metodo privado que devuelve la instancia cargada del objeto a partir de
un registro private object getObject(string sSQL)
{
DataSet miDs;
object aDO;
try
{
string spaceName = this.GetType().AssemblyQualifiedName;
string objectDAOName = this.GetType().Namespace + "." + this.GetType().Name;
string objectName = "Dominio." + this._doName ;
spaceName = spaceName.Replace(objectDAOName, objectName);
Type tTipo = Type.GetType(spaceName,true,true);
aDO = Activator.CreateInstance(tTipo);
miDs = this.getDS(sSQL);
if (miDs.Tables[0].Rows.Count > 0) setPropiedades(miDs.Tables[0].Rows[0],
aDO); else throw new Exception("Problemas con el objeto " + this._doName );
}
catch (Exception ex)
{
throw new Exception("Error en objeto " + this.GetType().Name + " / " +
ex.Message);
}
finally
{
miDs = null;
}
return aDO;
}
El método cargar utiliza en su secuencia de ejecución los métodos getWhereID que
devuelve un string con el filtro Where compuesto por el ID del objeto, por su lado el
metodo getobject utiliza el método setPropiedades el cual puebla las propiedades de un
objeto con los datos de un DataRow utilizando la Reflexión.
El código de ambos métodos, se detalla a continuación:
//Metodo que devuelve una cadena con la construccion del Where con los
primarykeys del objeto
private string getWhereID(string id){
DataColumn[] colArr;
string sColumn;
int ikeys;
try {
DataSet ds = getDsSchema();
Maestría en Informática Aplicada a Redes
Página 111 de 159
colArr = ds.Tables[0].PrimaryKey;
ikeys = colArr.Length;
sColumn = " where " ;
if(ikeys==0) throw new Exception("Objeto " + _doName + " no tiene definido
Primary Key en el ER, imposible continuar");
for(int i = 1; i<ikeys;i++) sColumn += colArr[i].ColumnName + " = '" + id
+ "'";
} catch(Exception ex) {
throw new Exception("Error obteniendo Primary Keys / " + ex.Message );
}
return sColumn;
}
// Llenar el Domain Object a partir del DataRow invocando dinamicamente los
Setter de cada propiedad
private void setPropiedades(DataRow aRow, object aDO) {
PropertyInfo[] oProperties;
string sPropertyName="";
MethodInfo oMetodo;
try {
oProperties =
aDO.GetType().GetProperties(BindingFlags.NonPublic|BindingFlags.Instance|BindingF
lags.Static|BindingFlags.Public);
foreach(PropertyInfo oProperty in oProperties) {
sPropertyName = oProperty.Name.ToString();
if(aRow.IsNull(sPropertyName)) {
oProperty.SetValue(aDO,null,null);
} else {
oMetodo = oProperty.GetGetMethod(true);
switch (oProperty.GetSetMethod(true).ReturnType.Name.ToString()) {
case "System.String":
oProperty.SetValue(aDO, (string)aRow[sPropertyName], null);
break;
case "System.DateTime":
oProperty.SetValue(aDO, (DateTime)aRow[sPropertyName], null);
break;
case "System.Int16":
oProperty.SetValue(aDO, (Int16)aRow[sPropertyName], null);
break;
case "System.Int32":
oProperty.SetValue(aDO, (Int32)aRow[sPropertyName], null);
break;
case "System.Int64":
oProperty.SetValue(aDO, (Int64)aRow[sPropertyName], null);
break;
case "System.Decimal":
oProperty.SetValue(aDO, (Decimal)aRow[sPropertyName], null);
break;
case "System.Double":
oProperty.SetValue(aDO, (Double)aRow[sPropertyName], null);
break;
case "System.Boolean":
Boolean bValor;
if(aRow[sPropertyName].GetType().ToString().CompareTo("System.SByte")==0) {
SByte sbValor = (SByte)aRow[sPropertyName];
bValor = (sbValor.ToString().Equals("1"))?true:false;
} else
if(aRow[sPropertyName].GetType().ToString().CompareTo("System.Byte")==0) {
Byte sbValor = (Byte)aRow[sPropertyName];
bValor = (sbValor.ToString().Equals("1"))?true:false;
} else {
Maestría en Informática Aplicada a Redes
Página 112 de 159
bValor = (Boolean)aRow[sPropertyName];
}
oProperty.SetValue(aDO,bValor,null);
break;
case "System.Char":
oProperty.SetValue(aDO, (string)aRow[sPropertyName], null);
break;
}
}
}
} catch(Exception ex) {
throw new Exception("Error seteando la propiedad " + sPropertyName + " / "
+ ex.Message); }
}
4.5 Acceso Independiente del sistema RDBMS
4.5.1 Planteamiento del Requerimiento
La funcionalidad a construir ya que implementará la “Capa de Acceso a Datos”, debe de ser
capas de manejar eficientemente el acceso a distintos sistema de bases de datos relacionales
de forma transparente y parametrizada para el desarrollador. Esto supone que el
desarrollador solo deberá indicar dentro de la configuración del aplicativo que motor de
base de datos utilizará y el motor de persistencia debe de hacer el resto. Sin embargo esto
supone los siguientes problemas
Aunque ADO .Net 2.0 contiene una serie de objetos genéricos agrupados en el namespace
System.Data, entre otros el DataSet, DataTable, DataView, DataColumn, DataRow, etc., al
momento de interactuar con distintas bases de datos como SQL Server u Oracle, hace uso
de controles específicos para cada RDBMS. De esta forma existe una clase SqlConenction
para Microsoft SQL y una clase OraConnection para Oracle, así como MySqlConnections
para Mysql y OleConnection para acceso via OleDB.
El uso de estas clases especificas por proveedor es necesaria ya que garantiza la eficiencia
en las operaciones en contra de cada contenedor.
Si bien esta considerado el uso de acceso vía OleDB a cualquier base con este tipo de
acceso, esto ocasiona una perdida de rendimiento por lo que es conveniente utilizar los
namespaces ofrecidos por Microsoft o construidos por cada proveedor.
Maestría en Informática Aplicada a Redes
Página 113 de 159
La funcionalidad a construir requiere de la utilización de objetos específicos para cada
RDBMS tales como:
Clase Descripción Microsoft SQL Oracle OleDB
Connection Clase Conexión especifica para cada proveedor
SqlConnection OraConnection OleConnection
DataAdapter Adaptador de datos especifico para cada proveedor, permite incorporar un contenido de datos dentro de un DataSet.
SqlDataAdapter OraDataAdapter OleDataAdapter
Command Clase Coomand, la que ejecuta un sql en una conexión especifica para cada proveedor
SqlCommand OraCommand OleCommand
DataReader Clase para acceso conectado especifica para cada proveedor (implementa un cursor Forward Only)
SqlDataReader OraDataReader OleDataReader
4.5.2 Diseño de la Solución
Conociendo el requerimiento establecido. Donde se plantea la necesidad de crear familias
de objetos en tiempo de ejecución, el patrón idóneo para modelar una solución de este tipo
es el patrón Abstract Factory 6.
El framework .Net 2.0 posee dentro de ADO .Net 2.0 una implementación de este patrón, el
cual esta disponible en el namespace System.Data.Common, esta solución permite la
creación de objetos específicos para cada proveedor. Sin embargo a la fecha de este estudio,
únicamente existen Factorías concretas para SQL , Oracle y OLE DB, las cuales son
proporcionadas por Microsoft a través del mismo framework. Proveedores como Mysql,
Sybase, PostGress y el mismo Oracle ofrecen conectores específicos para ADO .Net, pero
6 Ver numeral 3.4.7 para mayor información sobre el patrón Abstract Factory
Maestría en Informática Aplicada a Redes
Página 114 de 159
estos no son heredados de la clase System.Data.Comon por lo que no pueden ser utilizados
para implementar el patrón Abstract Factory. Dado esto para el caso de Proveedores
distintos a SQL y Oracle se utilizará el método de Acceso OLE DB, esperando que en
pronto tiempo el resto de proveedores liberen conectores que si puedan ser utilizados dentro
de este esquema.
Un esquema de la solución propuesta a través del patrón Abstract Factory implementado en
.Net, se muestra a continuación:
<<Usa>>
<<Usa>>
<<Usa>>
<<Crea>>
<<Crea>>
<<Crea>>
<<Crea>>
DbProviderFactory
{abstract}
+
+
+
+
+
+
getFactory (string Provider)
createCommand ()
createConnection ()
createParameter ()
createDataAdapter ()
createTransaction ()
: DbProviderFactory
: DbCommand
: DbConnection
: DbParameter
: DbDataAdapter
: DbTransaction
DAOMasterl ibrary
SQLProviderFactory
+
+
+
+
+
createCommand ()
createConnection ()
createParameter ()
createDataAdapter ()
createTransaction ()
: SQLCommand
: SQLConnection
: SQLParameter
: SQLDataAdapter
: SQLTransaction
OraProviderFactory
+
+
+
+
+
createCommand ()
createConnection ()
createParameter ()
createDataAdapter ()
createTransaction ()
: OraCommand
: OraConnection
: OraParameter
: OraDataAdapter
: OraTransaction
DbConnection
{abstract}
DbCommand
{abstract}
SQLConnection OraConnection
SqlCommandOraCommand
ADO .Net provee la clase Abstracta DbProviderFactory la cual es capas de crear instancias
de clases xxConnections, xxCommand, xxDataAdapter, etc. Estos son referenciados a
través de productos abstractos DbConnection, DbCommand, DbDataAdapter que en
realidad contienen objetos concretos de tipo SqlConnection, SqlCommand, SqlDataAdapter
u OraConnection, OraCommand, OraDataAdapter para el caso de Oracle.
Maestría en Informática Aplicada a Redes
Página 115 de 159
Dado que dentro de la funcionalidad a crear se deberá manejar mecanismos de crear la
DBFactory adecuada, así como crear las cadenas de conexión correctas, etc. Se deberá
diseñar una clase separada para implementar estos mecanismos la cual proporcionara sus
servicios a la clase principal que implementara el patrón DAO.
Dado que la clase DAOMaster implementara los métodos de persistencia, la
responsabilidad de crear el DBFactory correcta, así como el de crear conexiones a la base
de datos caerá sobre una nueva clase denominada DataFactory cuyos servicios serán usados
por la clase principal DAOMaster. Esta relación se muestra en el siguiente diagrama.
DAOMasterLibrarydataFactory
<<Crea>>
<<Usa>>
0..1
1..1
DataFactory
-
-
-
dataFactory
dbFactory
dbCon
: DataFactory
: DbProviderFactory
: DbConnection
= new DataFactory()
-
+
+
+
-
DbFactory ()
getInstancia ()
getFactory ()
getConnection ()
setDB ()
: void
: DataFactory
: DbProviderFactory
: DbConnection
: void
DBProviderFactory
DAOMaster
4.5.3 Construcción de la Solución
El procedimiento de utilización de la Factory consiste en los siguientes pasos: 1. Definición de la Factory Para realizar esta tarea bastara con definir una instancia de tipo DbProvider Factory
de la siguiente manera:
Maestría en Informática Aplicada a Redes
Página 116 de 159
DbProviderFactory DbFactoria;
2. Instanciamiento de la Factory de acuerdo al Proveedor Teniendo la definición del tipo de dato, pasaremos al proceso de creación de la
instancia a través del método getFactory() el cual devuelve una instancia concreta
de acuerdo al argumento enviado el cual debe de indicar el namespace del
proveedor a utilizar, así:
DbFactoria = DbProviderFactory.GetFactory(“System.Data.SqlClient”);
Crea una instancia de una factory para SQL Server.
3. Definición de productos abstractos
Para utilizar objetos de tipo Connection, Command , TableAdapter o DataAdapter
dentro del código del motor de persistencia se hace referencia a objetos de tipo DB
como se muestra en las siguientes definiciones
DbConnection conn;
DbCommand command;
DbTableAdapter tableAdapter;
DbDataAdapter dataAdapter;
4. Creación de Productos concretos.
Para la instanciación de objetos concretos se hará referencia a la clase DbFactoria como se
muestra a continuación.
Conn = DbFactoria.createConnection() ; Command = DbFactoria.createCommand(); tableAdapter = DbFactoria.createTableAdapter(); dataAdapter = DbFactoria.createDataAdapter();
El código C# de la clase DataFactory se muestra a continuación: using System;
using System.Data.Common;
namespace DAOMasterLibrary
{
class DataFactory
Maestría en Informática Aplicada a Redes
Página 117 de 159
{
static DataFactory dataFactory = new DataFactory();
DbProviderFactory dbFactory;
DbConnection dbCon;
private void DbFactory()
{
}
static public DataFactory getInstancia()
{
return dataFactory;
}
public DbProviderFactory getFactory()
{
if (dbFactory == null) setDB();
return dbFactory;
}
public DbConnection getConnection()
{
try
{
if (dbCon == null)
{
setDB();
dbCon = dbFactory.CreateConnection();
dbCon.ConnectionString = "";
dbCon.Open();
}
}
catch (Exception ex)
{
throw new Exception("Imposible Crear Conexión a RDBMS / " +
ex.Message);
}
return dbCon;
}
private void setDB()
{
dbFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
}
}
}
4.6 Configuración y Parametrización
4.6.1 Planteamiento del Requerimiento
Para que el motor de persistencia sea reutilizable en cualquier aplicación, debe de permitir
su parametrización, es decir el desarrollador al utilizar esta funcionalidad debe poder
indicar el tipo de dialecto o contenedor a utilizar, indicar parámetros de servidor, usuario,
password y bases de datos, etc.
Maestría en Informática Aplicada a Redes
Página 118 de 159
4.6.2 Diseño de la Solución
Para definir los parámetros como datos de la conexión, dialectos, etc. Se ha considerado la
creación de un archivo XML el cual será denominado DAOConfig.ini, este contendrá entre
otros los siguientes parámetros.
• Dialecto: Es el nombre del sistema RDBMS a utiliza, podrá tomar los valores
SqlClient, Oracle, MySql, OleDB.
• DataSource: Es el nombre del servidor o la ip address del datasource.
• Usuario: El nombre del usuario con el cual se crearán las conexiones hacia el
datasource
• Password: El password del usuario a conectarse.
• DataBase: El nombre de la base de datos a la cual se deberá conectar la aplicación.
4.6.3 Construcción de la Solución
El archivo DAOConfig deberá ser ubicado en el mismo directorio donde se ubique la
librería DAOMasterLibrary.dll, como generalmente se agregará como referencia a un
proyecto .Net. El directorio por defecto será el directorio bin el cual ya esta protegido para
no descargar información desde dicha ruta.
Un ejemplo del archivo de configuración, se muestra a continuación:
<DAOConfig>
<Parametros>
<Dialecto>SqlClient</dialecto>
<DataSource>Localhost<DataSource>
<Usuario>sa<Usuario>
<Password>daoMasterSA<Password>
<DataBase>Northwind<DataBase>
</Parametros>
</DAOConfig>
Maestría en Informática Aplicada a Redes
Página 119 de 159
Dado que la responsabilidad de crear y manejar las conexiones es de la clase DataFactory,
esta que es implementada a través del patrón Singleton, tendrá una serie de propiedades
asociadas a los parámetros ingresados en el archivo XML
namespace DAOMasterLibrary
{
class DataFactory
{
private string _dialecto;
private string _datasource;
private string _database;
private string _usuario;
private string _password;
…
De igual forma esta clase posee el método loadParameters() el cual se encarga de leer el
archivo XML cargando los parámetros a las propiedades de la clase. La implementación de
este método, se muestra a continuación:
private void loadParameters()
{
XPathDocument doc;
XPathNavigator nav;
try
{
StreamReader stFile = new StreamReader("DAOConfig.xml");
string xml = stFile.ReadToEnd();
stFile.Close();
doc = new XPathDocument(new StringReader(xml));
nav = doc.CreateNavigator();
_dialecto = nav.SelectSingleNode("/*/Parametros/Dialecto").InnerXml;
_datasource = nav.SelectSingleNode("/*/Parametros/DataSource").InnerXml;
_database = nav.SelectSingleNode("/*/Parametros/DataBase").InnerXml;
_usuario = nav.SelectSingleNode("/*/Parametros/Usuario").InnerXml;
_password = nav.SelectSingleNode("/*/Parametros/Password").InnerXml;
}catch (Exception ex) {
throw new Exception("Problemas cargando parametros de conexion al
datasource / " + ex.Message );
}
}
Maestría en Informática Aplicada a Redes
Página 120 de 159
V. RESULTADOS Y VERIFICACION EXPERIMENTAL
Este capitulo documenta procedimiento empleado para verificar la funcionalidad del
producto creado, así como los resultados obtenidos a partir de dichas pruebas.
Para la pruebas del motor de persistencia, se construyo un mantenimiento de usuarios, este
es en si, una interfase Win32 construida con C# .
5.1 Objetivo de las Pruebas
• Verificar que el motor de persistencia creado, ejecuta automáticamente las
conversiones entre operaciones con objetos a sentencias SQL y viceversa.
• Demostrar que la utilización del motor de persistencia reduce el tiempo necesario
para el desarrollo de un aplicativo.
• Demostrar que la utilización del motor de persistencia permite abstraer el diseño y
construcción del sistema de forma tal que es independiente la base de datos
empleada.
5.2 Definición del Requerimiento
Para realizar las pruebas de prototipo desarrollado, se deberá construir un aplicativo que de
mantenimiento a usuarios, ya que esta es una funcionalidad común en muchas aplicaciones.
El aplicativo deberá de contener.
• Herramienta de carga y búsqueda de usuarios
• Herramienta de Adición de Usuarios
• Herramienta de actualización de los datos de un usuario
• Herramienta de Eliminación de Usuarios.
• Del usuario nos interesan los siguientes datos:
o Cuenta asociada al usuario
o Password del Usuario
Maestría en Informática Aplicada a Redes
Página 121 de 159
o Nombres del Usuario
o Apellidos del Usuario
o Email del Usuario
o Si el usuario esta activo o no
o Fecha de Creación
o Fecha de Actualización de los datos del usuario
Se deben de considerar las siguientes consideraciones.
• Por razones de seguridad el password debe de persistirse de forma encriptada
• Se debe de considerar métodos de cambio de password
• No pueden existir dos usuarios con el mismo nombre de cuenta
• Los datos obligatorio para crear un usuario es el nombre de cuenta, su password y
su nombre.
• Para la implementación, se utilizará el RDBMS. SQL Server 2005 para manejar la
base de datos
5.3 Modelado y Diseño de la Solución A continuación se diseñan los distintos modelos que componen el sistema
5.3.1 Modelo de Dominio.
Dado que nuestro requerimiento solo establece un concepto, es decir el Usuario al momento
de modelar solo tendremos esta entidad la cual quedara modelada de la siguiente forma:
Usuario
-
-
-
-
-
-
-
-
cuenta
password
nombres
apell idos
activo
fechaCreacion
fechaActualización
: string
: string
: string
: string
: string
: bool
: DateTime
: DateTime
La clase anterior cuenta únicamente con los atributos definidos para la entidad usuario.
Estas posteriormente al aplicarles el encapsulamiento y Data Hide son convertidos en
propiedades quedando de la siguiente forma:
Maestría en Informática Aplicada a Redes
Página 122 de 159
Usuario
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
cuenta
password
nombres
apell idos
activo
fechaCreacion
fechaActualización
_cuenta
_password
_nombres
_apellidos
_email
_activo
_fechaCreacion
_fechaActualización
: string
: string
: string
: string
: string
: bool
: DateTime
: DateTime
: string
: string
: string
: string
: string
: bool
: DateTime
: DateTime
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
set_Cuenta (string value)
get_Cuenta ()
set_Password (string value)
get_Password ()
set_Nombres (string value)
get_Nombres ()
set_Apellidos (string value)
get_Apel lidos ()
set_Email (string value)
get_Email ()
set_Activo (bool value)
get_Activo ()
set_FechaCreacion (DateTime value)
get_FechaCreacion ()
set_FechaActualizacion (DateTime value)
get_FechaActualizacion ()
: void
: string
: void
: string
: void
: string
: void
: string
: void
: string
: void
: bool
: void
: DateTime
: void
: DateTime
Finalmente, se agregan métodos para soportar las operaciones de validar password, cambiar
password y encriptar el password ingresado. Además se adiciona un constructor que no
dejara se cree una instancia a menos que se ingrese la cuenta, password y nombre del
usuario, los correspondientes Setters de estas propiedades son declarados privados, para
que no puedan ser invocados externamente y las propiedades seteadas únicamente a través
del constructor. La clase queda de la siguiente forma
Maestría en Informática Aplicada a Redes
Página 123 de 159
Usuario
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
cuenta
password
nombres
apell idos
activo
fechaCreacion
fechaActualización
_cuenta
_password
_nombres
_apellidos
_email
_activo
_fechaCreacion
_fechaActualización
: string
: string
: string
: string
: string
: bool
: DateTime
: DateTime
: string
: string
: string
: string
: string
: bool
: DateTime
: DateTime
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
+
+
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
<<Setter>>
<<Getter>>
Usuario (string sCuenta, string sPassword, string sNombre)
set_Cuenta (string value)
get_Cuenta ()
set_Password (string value)
get_Password ()
set_Nombres (string value)
get_Nombres ()
set_Apell idos (string value)
get_Apell idos ()
set_Email (string value)
get_Email ()
set_Activo (bool value)
get_Activo ()
set_FechaCreacion (DateTime value)
get_FechaCreacion ()
set_FechaActualizacion (DateTime value)
get_FechaActualizacion ()
encryptPassword (string sCadena)
passwordIsValid (string sPassword)
cambiarPassword (string sPasswordAnterior, string sNuevoPassword)
: void
: void
: string
: void
: string
: void
: string
: void
: string
: void
: string
: void
: bool
: void
: DateTime
: void
: DateTime
: void
: bool
: bool
El código de la clase es el siguiente:
using System;
public sealed class Usuario
{
private string _Cuenta;
private string _Password;
private string _Nombres;
private string _Apellidos;
private string _Email;
private bool _Activo;
private DateTime _FechaCreacion;
private DateTime _FechaActualizacion;
public sealed void Usuario(string sCuenta, string sPassword, string sNombre)
{
// TODO: implement
}
private string Cuenta {
get {
return _Cuenta;
Maestría en Informática Aplicada a Redes
Página 124 de 159
}
set {
if (this._Cuenta != value)
this._Cuenta = value;
}
}
private string Password {
get {
return _Password;
}
set {
if (this._Password != value)
this._Password = value;
}
}
private string Nombres {
get {
return _Nombres;
}
set {
if (this._Nombres != value)
this._Nombres = value;
}
}
private string Apellidos {
get {
return _Apellidos;
}
set {
if (this._Apellidos != value)
this._Apellidos = value;
}
}
private string Email {
get {
return _Email;
}
set {
if (this._Email != value)
this._Email = value;
}
}
private bool Activo {
get {
return _Activo;
}
set {
if (this._Activo != value)
this._Activo = value;
}
}
private DateTime FechaCreacion {
get {
return _FechaCreacion;
}
set {
if (this._FechaCreacion != value)
this._FechaCreacion = value;
Maestría en Informática Aplicada a Redes
Página 125 de 159
}
}
private DateTime FechaActualizacion {
get {
return _FechaActualizacion;
}
set {
if (this._FechaActualizacion != value)
this._FechaActualizacion = value;
}
}
public sealed bool PasswordIsValid(string sPassword)
{
// TODO: implement
return false;
}
public sealed bool CambiarPassword(string sPasswordAnterior, string
sNuevoPassword)
{
// TODO: implement
return false;
}
private sealed string EncryptPassword(string sCadena)
{
// TODO: implement
return "";
}
}
5.3.2 Modelo de Acceso a Datos
Para el modelado de la Capa de Acceso a Datos, tenemos como directivas la utilización del
patrón DAO y la incorporación de la funcionalidad del motor de persistencia creado a
través de la Herencia en nuestra clase DAO. El modelado de esta capa se muestra en la
siguiente figura:
DAOMaster
DAOUsuario
+ DAOUsuario () : void
Maestría en Informática Aplicada a Redes
Página 126 de 159
Ya que solo utilizaremos una entidad, también en la capa de acceso a datos solo tendremos
una sola clase denominada DAOUsuario.
Gracias a la utilización del motor de persistencia la funcionalidad se heredara por lo que no
será necesario escribir mucho código, el único método que deberá de implementarse es el
constructor de la clase, en este se invocara el método de setteo del nombre del objeto de
dominio a procesar. El código generado a nivel de diseño es el siguiente:
public class DAOUsuario : DAOMaster
{
public void DAOUsuario()
{
// TODO: implement
}
}
5.3.3 Modelo de Reglas del Negocio.
Para la capa de negocio se modela una clase que se denominará NgcUsuario la cual
brindara los servicios a la capa de presentación, esta clase contendrá los métodos de
adición, actualización, eliminación y carga de una entidad. Sin embargo es importante
recalcar que la interfase de los métodos de esta clase recibirán valores primitivos, es decir
enteros, Strings, fechas, etc e internamente se manipularan como objetos. La siguiente
figura muestra el modelado de dicha clase:
NgcUsuario
+
+
+
+
+
adicionarUsuario (string sCuenta, string sPassword, string sNombre, string sApell ido, string sEmail)
actualizarUsuario (string sCuenta, string sNombre, string sApellido, string sEmail)
eliminarUsuario (string sCuenta)
cambiarPassword (string sCuenta, string sPassword, string sNuevoPassword)
obtenerUsuario (string sCuenta)
: int
: int
: int
: int
: Usuario
El código generado para la clase es el siguiente:
public sealed class NgcUsuario
{
Maestría en Informática Aplicada a Redes
Página 127 de 159
public sealed int AdicionarUsuario(string sCuenta, string sPassword, string
sNombre, string sApellido, string sEmail)
{
// TODO: implement
return 0;
}
public sealed int ActualizarUsuario(string sCuenta, string sNombre, string
sApellido, string sEmail)
{
// TODO: implement
return 0;
}
public int EliminarUsuario(string sCuenta)
{
// TODO: implement
return 0;
}
public int CambiarPassword(string sCuenta, string sPassword, string
sNuevoPassword)
{
// TODO: implement
return 0;
}
public Usuario ObtenerUsuario(string sCuenta)
{
// TODO: implement
return null;
}
}
El modelado final de todas las clases que interactúan es el siguiente:
Maestría en Informática Aplicada a Redes
Página 128 de 159
<<Usa>>
<<Crea>>
<<Usa>>
Usuario
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
<<PropertyImplementation>>
cuenta
password
nombres
apell idos
activo
fechaCreacion
fechaActualización
_cuenta
_password
_nombres
_apellidos
_email
_activo
_fechaCreacion
_fechaActualización
: string
: string
: string
: string
: string
: bool
: DateTime
: DateTime
: string
: string
: string
: string
: string
: bool
: DateTime
: DateTime
+
- <<Setter>>
Usuario (string sCuenta, string sPassword, string sNombre)
set_Cuenta (string value)
DAOMaster
DAOUsuario
+ DAOUsuario () : void
NgcUsuario
+
+
+
+
+
adicionarUsuario (string sCuenta, string sPassword, string sNombre, string sApell ido, string sEmail)
actualizarUsuario (string sCuenta, string sNombre, string sApell ido, string sEmail)
el iminarUsuario (string sCuenta)
cambiarPassword (string sCuenta, string sPassword, string sNuevoPassword)
obtenerUsuario (string sCuenta)
: int
: int
: int
: int
: Usuario
5.4 Construcción de la Aplicación
5.4.1 Creación de la Estructura de Datos.
Dado que el motor de persistencia creado requiere una total sincronía entre el modelo de
dominio y el las estructuras de persistencia, la mejor forma de garantizar esto como ya se
explico antes, es utilizar un CASE que pueda manejar ambos modelos es decir objetos y
datos o DDL . Para nuestro caso utilizamos el producto PowerDesigner 12.0 de la empresa
Sybase. Sin embargo se puede utilizar el producto que mas le convenga o parezca al
desarrollador.
Como solo tenemos una entidad en el modelo de dominio, igual al transformar este modelo
en un ER obtendremos una sola entidad como muestra la siguiente figura:
Maestría en Informática Aplicada a Redes
Página 129 de 159
Usuario
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
<<Property>>
cuenta
password
nombres
apellidos
activo
fechaCreacion
fechaActualización
varchar(30)
varchar(50)
varchar(50)
varchar(50)
varchar(75)
bit
datetime
datetime
El código DDL para esta entidad y generado por el CASE PowerDesigner, es el siguiente:
/*==============================================================*/
/* Table: Usuario */
/*==============================================================*/
create table Usuario (
Cuenta varchar(30) not null,
Password varchar(100) not null,
Nombres varchar(50) not null,
Apellidos varchar(50) null,
Email varchar(75) null,
Activo bit null,
FechaCreacion datetime not null,
FechaActualizacion datetime not null,
constraint PK_USUARIO primary key (Cuenta)
)
Go
Este Script se ejecutara sobre una instancia de SQL Server 2005 con las siguientes
características de conexión:
• Servidor: Localhost
• Base de Datos: Maestria
• Usuario: MaestriaUFG
• Password: Maestria$UFG$2006
5.4.2 Creación del Proyecto Visual C# Win32
Ya con el diseño de la solución y la base de datos creada, procedemos a abrir el Visual C#
2005 Express Edition y creamos un nuevo proyecto de tipo Win32 Application, como se
muestra en la siguiente imagen:
Maestría en Informática Aplicada a Redes
Página 130 de 159
Se puede notar que en el Solution Explorer se agregaron automáticamente las referencias a
las librerías necesarias para manejar la parte visual del proyecto.
Procederemos a agregar una referencia a nuestro motor de persistencia el cual reside dentro
del Assembly DAOMasterLibrary.dll, para esto deberemos copiar dicho dll a una ruta física
en la maquina de desarrollo y agregar la referencia a dicha ruta como se muestra a
continuación:
Maestría en Informática Aplicada a Redes
Página 131 de 159
Se deberá observar la referencia agregada en el proyecto como se muestra en la siguiente
imagen:
Posteriormente procederemos a incorporar el código generado a partir del modelamiento y
diseño, para organizar mejor dicho código se ha creado un Fólder al que nombramos
“Clases” y bajo este subfolders “Dominio”, “AccesoDatos” y “Negocio” donde crearemos
las clases respectivamente, esto se muestra en la siguiente imagen.
Maestría en Informática Aplicada a Redes
Página 132 de 159
El código final de cada una de las clases es el siguiente:
***************************** ****** Clase Usuario ********** ***************************** using System;
namespace Dominio
{
public sealed class Usuario
{
private string _Cuenta;
private string _Password;
private string _Nombres;
private string _Apellidos;
private string _Email;
private bool _Activo;
private DateTime _FechaCreacion;
private DateTime _FechaActualizacion;
public Usuario(string sCuenta, string sPassword, string sNombre)
{
_Cuenta = sCuenta;
_Password = this.EncryptPassword(sPassword);
_Nombres = sNombre;
}
private string Cuenta
{
get
{
return _Cuenta;
}
set
{
if (this._Cuenta != value)
this._Cuenta = value;
}
}
private string Password
{
get
{
return _Password;
}
set
{
if (this._Password != value)
this._Password = value;
}
}
public string Nombres
{
get
{
return _Nombres;
}
set
Maestría en Informática Aplicada a Redes
Página 133 de 159
{
if (this._Nombres != value)
this._Nombres = value;
}
}
public string Apellidos
{
get
{
return _Apellidos;
}
set
{
if (this._Apellidos != value)
this._Apellidos = value;
}
}
public string Email
{
get
{
return _Email;
}
set
{
if (this._Email != value)
this._Email = value;
}
}
public bool Activo
{
get
{
return _Activo;
}
set
{
if (this._Activo != value)
this._Activo = value;
}
}
public DateTime FechaCreacion
{
get
{
return _FechaCreacion;
}
set
{
if (this._FechaCreacion != value)
this._FechaCreacion = value;
}
}
public DateTime FechaActualizacion
{
get
{
return _FechaActualizacion;
}
Maestría en Informática Aplicada a Redes
Página 134 de 159
set
{
if (this._FechaActualizacion != value)
this._FechaActualizacion = value;
}
}
//Devuelve verdadero si el password enviado coincide con el almacenado en
la instancia
public bool PasswordIsValid(string sPassword)
{
return _Password.Equals(this.EncryptPassword(sPassword));
}
//Realiza cambio de password en instancia si el password actual enviado
coincide con el almacenado en la instancia
public bool CambiarPassword(string sPasswordActual, string
sNuevoPassword)
{
if (PasswordIsValid(sPasswordAnterior)) _Password =
EncryptPassword(sNuevoPassword);
else
throw new Exception("Password Invalido");
return true;
}
//Devuelve Cadena Encriptada con algoritmo Hash SHA
private string EncryptPassword(string sCadena)
{
return Utils.Encrypt.encryptSHA(sCadena);
}
}
}
***************************** ****** Clase DAOUsuario ****** ***************************** using System;
using System.Data;
using DAOMasterLibrary;
using Dominio;
namespace AccesoDatos
{
class DAOUsuario : DAOMaster
{
public DAOUsuario()
{
this.setDOName("usuario");
}
}
}
Maestría en Informática Aplicada a Redes
Página 135 de 159
***************************** ****** Clase NgcUsuario ******* *****************************
using System;
using System.Data;
using Dominio;
using AccesoDatos;
namespace Negocio
{
class NgcUsuario
{
public int AdicionarUsuario(string sCuenta, string sPassword, string
sNombre, string sApellido, string sEmail)
{
DAOUsuario daoUsuario = new DAOUsuario();;
Usuario usuario;
try
{
usuario = new Usuario(sCuenta, sPassword, sNombre);
if (!daoUsuario.existe(usuario))
{
usuario.Apellidos = sApellido;
usuario.Activo = true;
usuario.FechaCreacion = DateTime.Now;
usuario.FechaActualizacion = DateTime.Now;
daoUsuario.add(usuario);
}
else throw new Exception("Cuenta de usuario ya existe...");
}
catch (Exception ex)
{
throw new Exception("Error al intentar adicionar Usuario / " +
ex.Message);
}
finally
{
if (daoUsuario != null) daoUsuario.release();
}
return 1;
}
public int ActualizarUsuario(string sCuenta, string sNombre, string
sApellido, string sEmail)
{
DAOUsuario daoUsuario = new DAOUsuario(); ;
Usuario usuario;
try
{
usuario = (Usuario)daoUsuario.cargar(sCuenta);
usuario.Nombres = sNombre;
usuario.Apellidos = sApellido;
usuario.Email = sEmail;
usuario.FechaActualizacion = DateTime.Now;
daoUsuario.update(usuario);
}
catch (Exception ex)
{
Maestría en Informática Aplicada a Redes
Página 136 de 159
throw new Exception("Error al intentar actualizar Usuario / " +
ex.Message);
}
finally
{
if (daoUsuario != null) daoUsuario.release();
}
return 1;
}
public int EliminarUsuario(string sCuenta)
{
DAOUsuario daoUsuario = new DAOUsuario(); ;
try
{
daoUsuario.delete(sCuenta);
}
catch (Exception ex)
{
throw new Exception("Error al intentar eliminar Usuario / " +
ex.Message);
}
finally
{
if (daoUsuario != null) daoUsuario.release();
}
}
public int CambiarPassword(string sCuenta, string sPassword, string
sNuevoPassword)
{
DAOUsuario daoUsuario = new DAOUsuario(); ;
Usuario usuario;
try
{
usuario = (Usuario)daoUsuario.cargar(sCuenta);
usuario.CambiarPassword(sPassword, sNuevoPassword);
daoUsuario.update(usuario);
}
catch (Exception ex)
{
throw new Exception("Error al intentar actualizar Password de
Usuario / " + ex.Message);
}
finally
{
if (daoUsuario != null) daoUsuario.release();
}
}
public Usuario ObtenerUsuario(string sCuenta)
{
DAOUsuario daoUsuario = new DAOUsuario(); ;
Usuario usuario;
try
{
usuario = (Usuario)daoUsuario.cargar(sCuenta);
}
catch (Exception ex)
{
throw new Exception("Error al intentar actualizar Usuario / " +
ex.Message);
Maestría en Informática Aplicada a Redes
Página 137 de 159
}
finally
{
if (daoUsuario != null) daoUsuario.release();
}
return usuario;
}
}
}
***************************** ****** Clase Visual Form1 ***** *****************************
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Negocio;
using Dominio;
namespace pruebaPersistencia
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void cbtAdd_Click(object sender, EventArgs e)
{
try
{
new NgcUsuario().AdicionarUsuario(txtCuenta.Text,
txtPassword.Text, txtNombre.Text, txtApellido.Text, txtEmail.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
private void cbtUpdate_Click(object sender, EventArgs e)
{
try
{
new NgcUsuario().ActualizarUsuario(txtCuenta.Text,
txtNombre.Text, txtApellido.Text, txtEmail.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
Maestría en Informática Aplicada a Redes
Página 138 de 159
private void cbtDelete_Click(object sender, EventArgs e)
{
try
{
new NgcUsuario().EliminarUsuario(txtCuenta.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
private void cbtLoad_Click(object sender, EventArgs e)
{
try
{
Usuario usuario = new
NgcUsuario().ObtenerUsuario(txtCuenta.Text);
txtNombre.Text = usuario.Nombres;
txtApellido.Text = usuario.Apellidos;
txtEmail.Text = usuario.Email;
usuario = null;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error");
}
}
private void button5_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
5.5 Ejecución y Resultados
Construida la interfase que invoca los servicios de la capa de negocios. Al momento de
ejecutarla se obtiene la siguiente interfase:
Maestría en Informática Aplicada a Redes
Página 139 de 159
Al ejecutar la funcionalidad de la interfase que invoca los métodos de la capa de negocios,
se obtienen los siguientes resultados.
Ya que se esta utilizando SQL como RDBMS se utilizará el SQL Server Profiler para
verificar las sentencias enviadas por el aplicativo al motor de base de datos.
5.5.1 Operación de Adición.
Al momento de ejecutar el método de negocio adicionarUsuario, el cual crea una instancia
de la clase de acceso a datos que hereda la funcionalidad creada y se invoca el método Add
específicamente la instrucción:
daoUsuario.add(usuario);
El motor de persistencia genera la siguiente instrucción SQL:
exec sp_executesql N'INSERT INTO [Usuario] ([Cuenta], [Password], [Nombres],
[Apellidos], [Email], [Activo], [FechaCreacion], [FechaActualizacion]) VALUES
(@p1, @p2, @p3, @p4,
@p5, @p6, @p7, @p8)',N'@p1 varchar(11),@p2 varchar(44),@p3 varchar(7),@p4
varchar(8),@p5 varchar(19),@p6 bit,@p7 datetime,@p8
datetime',@p1='ufgMaestria',@p2='Vr5RWMG2az/rADYZLrrvwB3QwFB1ZmdNYWVzdHJpYQ==',@p
3='Usuario',@p4='Maestría',@p5='[email protected]',@p6=1,@p7=''2006-12-22
16:17:48:423'',@p8=''2006-12-22 16:17:48:423''
Maestría en Informática Aplicada a Redes
Página 140 de 159
5.5.2 Operación de Actualización:
Al momento de ejecutar el método de negocio actualizaUsuario, el cual crea una instancia
de la clase de acceso a datos que hereda la funcionalidad creada y se invoca el método
cargar específicamente la instrucción:
usuario = (Usuario)daoUsuario.cargar(sCuenta);
El motor de persistencia genera la siguiente instrucción SQL:
select * from usuario where Cuenta = 'ufgMaestria'
Posteriormente cuando se ejecuta la instrucción de acceso a datos:
daoUsuario.update(usuario);
El motor de persistencia genera la siguiente instrucción SQL:
exec sp_executesql N'UPDATE [Usuario] SET [Nombres] = @p1, [FechaActualizacion] =
@p2 WHERE (([Cuenta] = @p3) AND ([Password] = @p4) AND ([Nombres] = @p5) AND
((@p6 = 1 AND
[Apellidos] IS NULL) OR ([Apellidos] = @p7)) AND ((@p8 = 1 AND [Email] IS NULL)
OR ([Email] = @p9)) AND ((@p10 = 1 AND [Activo] IS NULL) OR ([Activo] = @p11))
AND
([FechaCreacion] = @p12) AND ([FechaActualizacion] = @p13))',N'@p1
varchar(18),@p2 datetime,@p3 varchar(11),@p4 varchar(44),@p5 varchar(7),@p6
int,@p7 varchar(8),@p8 int,@p9
varchar(19),@p10 int,@p11 bit,@p12 datetime,@p13 datetime',@p1='Usuario
Acualizado',@p2=''2006-12-22
16:20:03:923'',@p3='ufgMaestria',@p4='Vr5RWMG2az/rADYZLrrvwB3QwFB1ZmdNYWVzdHJpYQ=
=',@p5='Usuario',@p6=0,@p7='Maestría',@p8=0,@p9='[email protected]',@p10=0,@p11
=1,@p12=''2006-12-22 16:17:48:423'',@p13=''2006-12-22 16:17:48:423''
Maestría en Informática Aplicada a Redes
Página 141 de 159
5.5.3 Operación de Eliminación.
Al momento de ejecutar el método de negocio eliminaUsuario, el cual crea una instancia de
la clase de acceso a datos que hereda la funcionalidad creada y se invoca el método cargar
específicamente la instrucción:
usuario = (Usuario)daoUsuario.cargar(sCuenta);
El motor de persistencia genera la siguiente instrucción SQL:
select * from usuario where Cuenta = 'ufgMaestria'
Posteriormente cuando se ejecuta la instrucción de acceso a datos:
daoUsuario.delete(usuario);
El motor de persistencia genera la siguiente instrucción SQL:
exec sp_executesql N'DELETE DROM [Usuario] WHERE (([Cuenta] = @p1))',N'@p1
varchar(18), ,@p1='ufgMaestria'
5.6 Conclusiones sobre las Pruebas. Al finalizar estas pruebas después de analizar el código construido podemos concluir.
• La funcionalidad del motor de persistencia heredada en las clases DAO genera
correctamente las operaciones SQL de inserción, actualización, eliminación y carga
de objetos.
• Estas construcción es automática y transparente para el desarrollador y el usuario.
• El motor de persistencia utiliza adecuadamente los campos que funcionan como
primary key para generar los filtros y condiciones where.
• Las operaciones de Update se realizan eficientemente únicamente sobre los campos
modificados.
Maestría en Informática Aplicada a Redes
Página 142 de 159
VI. CONCLUSIONES Y FUTURAS LINEAS DE
INVESTIGACION
6.1 Conclusiones Generales En el desarrollo de este proyecto se muestra las ventajas del desarrollo de aplicaciones
siguiendo un modelo de desarrollo completamente orientado a objetos, donde el acceso a
datos es abstraído y separado a una capa especifica de la aplicación, donde debe de
manejarse la relación entre objetos, las tablas y registros donde serán persistidos. Si bien
como objetivo general se ha demostrado la funcionalidad del prototipo creado al aplicarlo a
esta la capa de acceso a datos, existen una serie de puntos y conclusiones más específicos
donde resaltan los siguientes:
• Sobre la operabilidad del prototipo, podemos concluir, que es sencilla ya que solo
requiere la incorporación en el proyecto .Net del Assembly DAOMasterLibrary.dll
y seguir los linimientos de uso. Dado las características de la plataforma .Net el
proyecto puede ser de cualquier tipo que requiera acceso a un RDBMS y es
independiente del lenguaje a utilizar.
• El motor de persistencia construido es parametrizable a través del archivo XML de
configuración DAOConfig.xml. Cambiando por ejemplo el dialecto en este archivo,
nuestro prototipo puede trabajar perfectamente con otra base de datos, sin ningún
problema.
• El motor de persistencia construido permite fácilmente trabajar o interactuar con
distintos sistemas RDBMS, evitando que el desarrollador se preocupe de estas
actividades. El motor de persistencia oculta esta complejidad al desarrollador
teniendo este nada más que efectuare la parametrización y especificación del
dialecto a utilizar.
• El uso de un motor de persistencia, evita que el usuario se preocupe por las
operaciones transaccionales de Acceso a Datos. El desarrollador nada mas se
Maestría en Informática Aplicada a Redes
Página 143 de 159
preocupara por ejecutar métodos Add, cargar, Update o Delete sobre los objetos de
dominio, el motor se encargará del resto.
• El modelo distribuido propuesto facilita la reusabilidad de código, por ejemplo las
clases DAO construidas pueden ser reutilizadas por otras aplicaciones.
• La abstracción de la capa de Acceso a Datos permite hacer operaciones a nivel de
negocios sobre objetos y no sobre registros.
• El modelado de las clases de dominio permite que los objetos imiten de la realidad
modelada y como en el caso construido no solo contengan datos, sino ejecuten
métodos propios o internos a sus datos, cosa que no es natural para un registro.
• El uso de patrones de diseño, permite que el código generado sea muy flexible y
potencia grandemente la reusabilidad.
• El uso de este material por educadores será de beneficios para estudiantes que
puedan utilizar estos ejemplo como base para construir o mejorar el código o como
simple aplicación de diversos conceptos relacionados a la ingeniería de software.
6.2 Futuras Líneas de investigación. Dado que el prototipo desarrollado en este documento, esta limitado en su diseño y
funcionalidad principalmente por factores de tiempo, existen ciertos aspectos no
considerados en este documento que podrían ser desarrollados como futuras líneas de
investigación.
Entre esas posibles líneas de investigación se proponen las siguientes:
6.2.1 Manejo de Herencia y Composición.
El objetivo de este tema, es el de extender la funcionalidad actual del motor con el fin de
dar soporte a la herencia y la composición. Investigando la forma mas eficiente de definir
este tipo de relaciones y manejarlas al momento de ser persistidas.
Maestría en Informática Aplicada a Redes
Página 144 de 159
Se propone este tema, debido a que la herencia es una de las principales propiedades de la
Orientación a Objetos, es una de las características que más denotan la diferencia al
construir un modelo orientado a objetos contra uno relacional u orientado a datos. El
soporte de esta funcionalidad al igual que el caso de la composición en el motor de
persistencia como ya lo hacen productos como Hibernate, mejoraría en gran medida la
utilidad de esta herramienta.
6.2.2 Eficiencia y Rendimiento.
El desarrollo de este tema, abarca un proceso de revisión completo al aplicativo de tal
forma de buscar los mecanismos y técnicas mas eficientes para la construcción de los
métodos, documentando los resultados y exponiendo el porque de dichas mejoras y como
impactan el rendimiento de la funcionalidad construida en un ambiente de múltiples
usuarios o con cargas considerables de datos. Se propone tratar temas como manejo de
pools y cache de objetos y conexiones, etc.
Se propone este tema dado que los ejemplos planteados en este documento han sido
orientados más que todo a la funcionalidad en si del producto y no a un uso masivo o con
grandes cargas de estrés. Lo que permitiría la utilización de este modelo en aplicaciones de
tipo Enterprise o de alto rendimiento.
6.2.3 Ejecución sobre plataformas no Windows.
Este tema esta orientado a la ejecución del motor sobre una plataforma no Windows, esto
debido a las limitantes de la plataforma .Net y a que actualmente existen ya proyectos muy
avanzados de ejecución del framework sobre otras plataformas, como el proyecto Mono
(http://www.mono-project.com) , esto brindaría la oportunidad de ejecutar dicho aplicativo
sobre plataformas Linux, Unix, Mac, etc.
Maestría en Informática Aplicada a Redes
Página 145 de 159
VII. Bibliografía y Referencias Estudiadas.
• Design Patterns: Elements of Reusable Object-Oriented Software (Erich Gamma,
Richard Helm, Ralph Johnson and John Vlissides) 1995
• Paulk, Paul C. et al. The Capability Maturity Model, Guidelines for improving the
software process, CMU/SEI, Addison-Wesley, 1995.
• CBA Lead Assessor Training. Participant’s Guide. December, 2001. Version 1.2.
Software Engineering Institute. Carnegie Mellon University.
• Kitson David. CMMI: Current status & standardization aspects. SPIN meeting at
LA, October 2000.
• Kulpa, Margaret. CMM not for the little guy? SEPG Conference, February 2002.
• Servello, Kasse Tim. Et al. Panel. The loyal opposition versus the CMMI
champions: A frank discussion of CMMI models. Setting the stage. SEPG
Conference, February 2002.
• Diseño de Sistemas de Bases de Datos Merche Marqués. 12 de abril de 2002
Cattell, R.G. The Object Database Standard: ODMG-93 (Release 1.2). Morgan
Kauffman Publishers. San Francisco, 1995.
• Codd, E.F. A Relational Model of Data for Large Shared Data Banks. CACM
13(6): 377-387. 1970.
• Elmasri, R. & Navathe, S.B. Fundamentals of Database Systems 3e. Addison
Wesley, 2000.
• McClure, S. IDC Bulletin #14821E. August, 1997. Nahouraii, E. & Petry, F.
Object-Oriented Databases. IEEE, 1991.
• Rao, B.R. Object-Oriented Databases: Technology, Applications, and Products
McGraw-Hill. New York, 1994.
• Stonebraker, M. Architectural Options for Object-Relational DBMSs. Informix
Software, CA. Feb, 1997.
Maestría en Informática Aplicada a Redes
Página 146 de 159
• Stonebraker, M. Object-Relational DBMS: The Next Wave. Informix Software, CA.
Stonebraker, M., Brown, P., and Moore, D. Object-Relational DBMSs: Tracking the
Next Great Wave 2e. Morgan-Kauffman Publishers. San Francisco, 1999.
Maestría en Informática Aplicada a Redes
Página 147 de 159
VIII. ANEXO A: Código Fuente del Motor de Persistencia
********************************************************************************
**** Clase: DataFactoy
**** Descripción: Clase encargada del manejo de los factories y conexiones
********************************************************************************
using System;
using System.Data;
using System.Data.Common;
using System.Xml;
using System.Xml.XPath;
using System.IO;
namespace DAOMasterLibrary
{
class DataFactory
{
static DataFactory dataFactory = new DataFactory();
DbProviderFactory dbFactory;
DbConnection dbCon;
private string _dialecto;
private string _datasource;
private string _database;
private string _usuario;
private string _password;
private void DbFactory()
{
}
static public DataFactory getInstancia()
{
return dataFactory;
}
public DbProviderFactory getFactory()
{
if (dbFactory == null) setDB();
return dbFactory;
}
public DbConnection getConnection()
{
try
{
if (dbCon == null)
{
setDB();
dbCon = dbFactory.CreateConnection();
dbCon.ConnectionString = getStrCon();
dbCon.Open();
}
if (dbCon.State == ConnectionState.Closed || dbCon.State ==
ConnectionState.Broken)
{
dbCon.ConnectionString = getStrCon();
dbCon.Open();
}
}
catch (Exception ex)
{
throw new Exception("Imposible Crear Conexión a RDBMS / " + ex.Message);
}
return dbCon;
}
Maestría en Informática Aplicada a Redes
Página 148 de 159
private void setDB()
{
loadParameters();
switch (_dialecto.ToUpper())
{
case "SQLCLIENT":
dbFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
break;
case "ORACLE":
dbFactory = DbProviderFactories.GetFactory("System.Data.OraClient");
break;
case "MYSQL":
dbFactory = DbProviderFactories.GetFactory("System.Data.Odbc");
break;
case "OLEDB":
dbFactory = DbProviderFactories.GetFactory("System.Data.OleDb");
break;
case "ODBC":
dbFactory = DbProviderFactories.GetFactory("System.Data.Odbc");
break;
}
}
private string getStrCon()
{
string strCon="";
switch (_dialecto.ToUpper())
{
case "SQLCLIENT":
strCon = "Server=" + _datasource + ";Database=" + _database + ";User
ID=" + _usuario + ";Password=" + _password + ";Trusted_Connection=False";
break;
case "ORACLE":
strCon = "Data Source=" + _datasource + ";User Id=" + _usuario +
";Password=" + _password + ";Integrated Security=no;";
break;
case "MYSQL":
strCon = "Driver={MySQL ODBC 3.51 Driver};Server=" + _datasource +
";Database=" + _database + ";User=" + _usuario + ";Password=" + _password + ";Option=3";
break;
}
return strCon;
}
private void loadParameters()
{
XPathDocument doc;
XPathNavigator nav;
try
{
StreamReader stFile = new StreamReader("DAOConfig.xml");
string xml = stFile.ReadToEnd();
stFile.Close();
doc = new XPathDocument(new StringReader(xml));
nav = doc.CreateNavigator();
_dialecto = nav.SelectSingleNode("/*/Parametros/Dialecto").InnerXml;
_datasource = nav.SelectSingleNode("/*/Parametros/DataSource").InnerXml;
_database = nav.SelectSingleNode("/*/Parametros/DataBase").InnerXml;
_usuario = nav.SelectSingleNode("/*/Parametros/Usuario").InnerXml;
_password = nav.SelectSingleNode("/*/Parametros/Password").InnerXml;
}
catch (Exception ex)
{
throw new Exception("Problemas cargando parametros de conexion al datasource
/ " + ex.Message );
}
}
}
}
Maestría en Informática Aplicada a Redes
Página 149 de 159
********************************************************************************
**** Clase: DaoMaster
**** Descripción: Clase encargada de implementar la funcionalidad del motor
********************************************************************************
using System;
using System.Data;
using System.Data.Common;
using System.Reflection;
using System.Collections;
namespace DAOMasterLibrary
{
public abstract class DAOMaster : IDisposable
{
private DbConnection _oCon;
private string _doName;
private DbProviderFactory dbFactory;
private DataSet dsSchema;
protected bool disposed;
//Constructor
public DAOMaster()
{
dbFactory = DataFactory.getInstancia().getFactory();
}
//Getter y Setter de la Propieda Conexión
private DbConnection Conn
{
get
{
return _oCon;
}
set
{
if (this._oCon != value)
this._oCon = value;
}
}
//Getter y Setter de la Propieda Nombre del Domain Object
private string doName
{
get
{
return _doName;
}
set
{
if (this._doName != value)
this._doName = value;
}
}
//Setter del Domain Object Name
protected void setDOName(string sName)
{
if (dbFactory == null) dbFactory = DataFactory.getInstancia().getFactory();
this._doName = sName;
}
//Metodo Privado que obtiene uan conexion asignandola a la instancia actual
private bool setConnection()
{
try
{
if (_oCon == null) _oCon = DataFactory.getInstancia().getConnection();
Maestría en Informática Aplicada a Redes
Página 150 de 159
if (_oCon.State == ConnectionState.Closed || _oCon.State ==
ConnectionState.Broken) _oCon = DataFactory.getInstancia().getConnection();
} catch(Exception ex) {
throw new Exception("Error intentando obtener conexión / " + ex.Message );
}
return true;
}
//Función protected que ejecuta y devuelve un DataSet
protected DataSet getDS(string SqlString){
DataSet ds;
DbCommand oCommand;
DbDataAdapter oAdapter;
try {
if(setConnection()) {
ds = new DataSet() ;
oCommand = _oCon.CreateCommand();
oAdapter = dbFactory.CreateDataAdapter();
oCommand.Connection = _oCon;
oCommand.CommandType = CommandType.Text;
oCommand.CommandText = SqlString;
oAdapter.SelectCommand = oCommand;
oAdapter.Fill(ds);
} else {
return null;
}
} catch(Exception ex) {
throw ex;
}
return ds;
}
//Función privada que ejecuta y devuelve el Schema del Objeto mapeado
private DataSet getDsSchema(){
if (dsSchema != null) return dsSchema;
else
{
DataSet ds;
DbCommand oCommand;
DbDataAdapter oAdapter;
string SqlString = "select * from " + this._doName;
try
{
if (setConnection())
{
ds = new DataSet();
oCommand = _oCon.CreateCommand();
oAdapter = dbFactory.CreateDataAdapter();
oCommand.Connection = _oCon;
oCommand.CommandType = CommandType.Text;
oCommand.CommandText = SqlString;
oAdapter.SelectCommand = oCommand;
oAdapter.FillSchema(ds, SchemaType.Mapped);
dsSchema = ds;
}
else
{
return null;
}
}
catch (Exception ex)
{
throw ex;
}
return ds;
}
}
//Metodo getWhereId para ID de tipo Numero
private string getWhereID(long id) {
DataColumn[] colArr;
string sColumn;
int ikeys;
Maestría en Informática Aplicada a Redes
Página 151 de 159
try
{
DataSet ds = getDsSchema();
colArr = ds.Tables[0].PrimaryKey;
ikeys = colArr.Length;
sColumn = " where ";
if (ikeys == 0) throw new Exception("Objeto " + _doName + " no tiene
definido Primary Key en el ER, imposible continuar");
for (int i = 0; i < ikeys; i++) sColumn += colArr[i].ColumnName + " = " + id
+ " ";
}
catch (Exception ex)
{
throw new Exception("Error obteniendo Primary Keys / " + ex.Message);
}
return sColumn;
}
//Metodo que devuelve una cadena con la construccion del Where con los primarykeys
del objeto
private string getWhereID(string id){
DataColumn[] colArr;
string sColumn;
int ikeys;
try {
DataSet ds = getDsSchema();
colArr = ds.Tables[0].PrimaryKey;
ikeys = colArr.Length;
sColumn = " where " ;
if(ikeys==0) throw new Exception("Objeto " + _doName + " no tiene definido
Primary Key en el ER, imposible continuar");
for(int i = 0; i<ikeys;i++) sColumn += colArr[i].ColumnName + " = '" + id +
"'";
} catch(Exception ex) {
throw new Exception("Error obteniendo Primary Keys / " + ex.Message );
}
return sColumn;
}
// Devuelve el Schema en formato XML StrinReader del DVO actual
private System.IO.StringReader getSchema() {
string sXML = this.getDsSchema().GetXmlSchema();
return new System.IO.StringReader(sXML);
}
// Generar la Sentencia where correspondiente usando los primary key y sus valores
private string getWhere(object aDO)
{
DataColumn[] colArr;
string sWhere = "", sColumn, sAND, sType;
DataSet ds;
DataRow fila;
int ikeys;
try
{
ds = getDsSchema();
fila = ds.Tables[0].NewRow();
getPropiedades(fila,aDO,false);
colArr = ds.Tables[0].PrimaryKey;
ikeys = colArr.Length;
sColumn = "";
sWhere = " where ";
if (ikeys == 0) throw new Exception("Objeto " + _doName + " no tiene
definido Primary Key en el ER, imposible continuar");
for (int i = 0; i < ikeys; i++) {
sAND = (i>0)? " AND ":"";
sColumn = colArr[i].ColumnName;
sType = colArr[i].DataType.Name.ToString();
if(sType.CompareTo("String")==0||sType.CompareTo("Char")==0) {
sWhere += sAND + sColumn + " = '" + fila[sColumn] + "'";
} else {
Maestría en Informática Aplicada a Redes
Página 152 de 159
sWhere += sAND + sColumn + " = " + Convert.ToString(fila[sColumn])
+ " ";
}
}
}
catch (Exception ex)
{
throw new Exception("Error obteniendo Primary Keys / " + ex.Message);
}
return sWhere;
}
// Objetivo: Actualizar el Dataset en el DataSource
private int saveDS(DataSet ds)
{
string sSQL = "select * from " + this._doName;
DbDataAdapter oAdapter;
DbCommandBuilder oCBuilder;
DbCommand oCommand;
int iResult = 0;
if (setConnection())
{
try
{
oAdapter = dbFactory.CreateDataAdapter();
oCommand = _oCon.CreateCommand();
oCommand.CommandText = sSQL;
oAdapter.SelectCommand = oCommand;
oCBuilder = dbFactory.CreateCommandBuilder();
oCBuilder.DataAdapter = oAdapter;
iResult = oAdapter.Update(ds);
oAdapter.Dispose();
oAdapter = null;
}
catch (Exception ex)
{
throw new Exception("Error actualizando objeto " + this._doName + " / "
+ ex.Message);
}
}
return iResult;
}
// Actualizar el Dataset en el DataSource utilizando filtro where por primary
Key(Metodo Sobrecargado)
private int saveDS( DataSet ds, bool useWhere, object aDO) {
string sSQL = "select * from " + this._doName;
DbDataAdapter oAdapter;
DbCommandBuilder oCBuilder;
DbCommand oCommand;
int iResult = 0;
sSQL = (useWhere)? sSQL + " " + this.getWhere(aDO):sSQL;
if (setConnection())
{
try
{
oAdapter = dbFactory.CreateDataAdapter();
oCommand = _oCon.CreateCommand();
oCommand.CommandText = sSQL;
oAdapter.SelectCommand = oCommand;
oCBuilder = dbFactory.CreateCommandBuilder();
oCBuilder.DataAdapter = oAdapter;
iResult = oAdapter.Update(ds);
oAdapter.Dispose();
oAdapter = null;
}
catch (Exception ex)
{
throw new Exception("Error actualizando objeto " + this._doName + "
/ " + ex.Message);
}
Maestría en Informática Aplicada a Redes
Página 153 de 159
}
return iResult;
}
// Obtiene las propiedades de un Domain Object asignandolas a un DataRow a traves de
invocaciones dinamicas a los Getter
private void getPropiedades(DataRow aRow, object aDO, bool actualizar){
PropertyInfo[] oProperties;
string sPropertyName="";
MethodInfo oMetodo;
try {
oProperties =
aDO.GetType().GetProperties(BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static
|BindingFlags.Public);
foreach(PropertyInfo oProperty in oProperties) {
sPropertyName = oProperty.Name.ToString();
oMetodo = oProperty.GetGetMethod(true);
if (!(actualizar&&aRow.Table.Columns[sPropertyName].ReadOnly))
{
switch (oMetodo.ReturnType.ToString())
{
case "System.String":
aRow[sPropertyName] = (string)oMetodo.Invoke(aDO, null);
break;
case "System.DateTime":
aRow[sPropertyName] = (DateTime)oMetodo.Invoke(aDO, null);
break;
case "System.Int16":
aRow[sPropertyName] = (Int16)oMetodo.Invoke(aDO, null);
break;
case "System.Int32":
aRow[sPropertyName] = (Int32)oMetodo.Invoke(aDO, null);
break;
case "System.Int64":
aRow[sPropertyName] = (Int64)oMetodo.Invoke(aDO, null);
break;
case "System.Decimal":
aRow[sPropertyName] = (Decimal)oMetodo.Invoke(aDO, null);
break;
case "System.Double":
aRow[sPropertyName] = (Double)oMetodo.Invoke(aDO, null);
break;
case "System.Boolean":
aRow[sPropertyName] = (Boolean)oMetodo.Invoke(aDO, null);
break;
case "System.Char":
aRow[sPropertyName] = (Char)oMetodo.Invoke(aDO, null);
break;
}
}
}
} catch(Exception ex) {
throw new Exception("Error accesando la propiedad " + sPropertyName + " / "
+ ex.Message);
}
}
// Llenar el Domain Object a partir del DataRow invocando dinamicamente los Setter
de cada propiedad
private void setPropiedades(DataRow aRow, object aDO) {
PropertyInfo[] oProperties;
string sPropertyName="";
try {
oProperties =
aDO.GetType().GetProperties(BindingFlags.NonPublic|BindingFlags.Instance|BindingFlags.Static
|BindingFlags.Public);
foreach(PropertyInfo oProperty in oProperties) {
sPropertyName = oProperty.Name.ToString();
if(aRow.IsNull(sPropertyName)) {
oProperty.SetValue(aDO,null,null);
} else {
Maestría en Informática Aplicada a Redes
Página 154 de 159
switch (oProperty.GetGetMethod(true).ReturnType.ToString())
{
case "System.String":
oProperty.SetValue(aDO, (string)aRow[sPropertyName], null);
break;
case "System.DateTime":
oProperty.SetValue(aDO, (DateTime)aRow[sPropertyName],
null);
break;
case "System.Int16":
oProperty.SetValue(aDO, (Int16)aRow[sPropertyName], null);
break;
case "System.Int32":
oProperty.SetValue(aDO, (Int32)aRow[sPropertyName], null);
break;
case "System.Int64":
oProperty.SetValue(aDO, (Int64)aRow[sPropertyName], null);
break;
case "System.Decimal":
oProperty.SetValue(aDO, (Decimal)aRow[sPropertyName], null);
break;
case "System.Double":
oProperty.SetValue(aDO, (Double)aRow[sPropertyName], null);
break;
case "System.Boolean":
Boolean bValor;
if(aRow[sPropertyName].GetType().ToString().CompareTo("System.SByte")==0) {
SByte sbValor = (SByte)aRow[sPropertyName];
bValor = (sbValor.ToString().Equals("1"))?true:false;
} else
if(aRow[sPropertyName].GetType().ToString().CompareTo("System.Byte")==0) {
Byte sbValor = (Byte)aRow[sPropertyName];
bValor = (sbValor.ToString().Equals("1"))?true:false;
} else
if(aRow[sPropertyName].GetType().ToString().CompareTo("System.Int16")==0) {
Int16 sbValor = (Int16)aRow[sPropertyName];
bValor = (sbValor.ToString().Equals("1"))?true:false;
} else {
bValor = (Boolean)aRow[sPropertyName];
}
oProperty.SetValue(aDO,bValor,null);
break;
case "System.Char":
oProperty.SetValue(aDO, (string)aRow[sPropertyName], null);
break;
}
}
}
} catch(Exception ex) {
throw new Exception("Error seteando la propiedad " + sPropertyName + " / " +
ex.Message);
}
}
// Metodo cargar para manejo de ID numericos
public object cargar(long id)
{
string sSQL;
object aDO;
try
{
sSQL = "select * from " + this._doName + getWhereID(id);
aDO = getObject(sSQL);
}
catch (Exception ex)
{
throw ex;
}
Maestría en Informática Aplicada a Redes
Página 155 de 159
return aDO;
}
// Metodo cargar para manejo de ID string
public object cargar(string id)
{
string sSQL;
object aDO;
try
{
sSQL = "select * from " + this._doName + getWhereID(id);
aDO = getObject(sSQL);
}
catch (Exception ex)
{
throw ex;
}
return aDO;
}
//Metodo privado que devuelve la instancia cargada del objeto a partir de un
registro
private object getObject(string sSQL)
{
DataSet miDs;
object aDO;
try
{
string spaceName = this.GetType().AssemblyQualifiedName;
string objectDAOName = this.GetType().Namespace + "." + this.GetType().Name;
string objectName = "Dominio." + this._doName ;
spaceName = spaceName.Replace(objectDAOName, objectName);
Type tTipo = Type.GetType(spaceName,true,true);
aDO = Activator.CreateInstance(tTipo);
miDs = this.getDS(sSQL);
if (miDs.Tables[0].Rows.Count > 0) setPropiedades(miDs.Tables[0].Rows[0],
aDO); else throw new Exception("Problemas con el objeto " + this._doName );
}
catch (Exception ex)
{
throw new Exception("Error en objeto " + this.GetType().Name + " / " +
ex.Message);
}
finally
{
miDs = null;
}
return aDO;
}
//Metodo que verifica si una instancia de una clase ya ha sido persistida
public Boolean existe(object aDO)
{
long iResult = 0;
string sSQL;
try
{
sSQL = "select count(*) from " + _doName + " " + getWhere(aDO);
iResult = getVal(sSQL);
}
catch (Exception ex)
{
throw ex;
}
return (iResult > 0) ? true : false;
}
Maestría en Informática Aplicada a Redes
Página 156 de 159
// Ejecutar un SQL
protected bool execSQL(string sSQL) {
DbCommand oCommand;
if(setConnection()) {
oCommand = dbFactory.CreateCommand();
try {
oCommand.CommandText = sSQL;
oCommand.Connection = this._oCon ;
oCommand.ExecuteNonQuery();
} catch(Exception ex) {
throw ex;
}finally {
oCommand.Dispose();
oCommand = null;
}
} else return false;
return true;
}
// Obtener un valor numerico escalar
protected long getVal(string sSQL) {
DbCommand oCommand;
long iresult = 0;
if(setConnection()) {
oCommand = dbFactory.CreateCommand();
try {
oCommand.CommandText = sSQL;
oCommand.Connection = this._oCon ;
iresult = Convert.ToInt64(oCommand.ExecuteScalar());
} catch(Exception ex) {
throw ex;
}finally {
oCommand.Dispose();
oCommand = null;
}
} ;
return iresult;
}
// Obtener un valor String escalar
protected string getStrVal(string sSQL)
{
DbCommand oCommand;
string sResult ;
if (setConnection())
{
oCommand = dbFactory.CreateCommand();
try
{
oCommand.CommandText = sSQL;
oCommand.Connection = this._oCon;
sResult = Convert.ToString(oCommand.ExecuteScalar());
}
catch (Exception ex)
{
throw ex;
}
finally
{
oCommand.Dispose();
oCommand = null;
}
}
else return null;
return sResult;
}
// Obtener un valor decimal
protected decimal getDecimalVal(string sSQL)
{
DbCommand oCommand;
Maestría en Informática Aplicada a Redes
Página 157 de 159
decimal dResult = new decimal();
if (setConnection())
{
oCommand = dbFactory.CreateCommand();
try
{
oCommand.CommandText = sSQL;
oCommand.Connection = this._oCon;
dResult = Convert.ToDecimal(oCommand.ExecuteScalar());
}
catch (Exception ex)
{
throw ex;
}
finally
{
oCommand.Dispose();
oCommand = null;
}
}
return dResult;
}
// Obtener un valor de tipo DateTime
protected DateTime getDatetimeVal(string sSQL)
{
DbCommand oCommand;
DateTime dResult = new DateTime();
if (setConnection())
{
oCommand = dbFactory.CreateCommand();
try
{
oCommand.CommandText = sSQL;
oCommand.Connection = this._oCon;
dResult = Convert.ToDateTime(oCommand.ExecuteScalar());
}
catch (Exception ex)
{
throw ex;
}
finally
{
oCommand.Dispose();
oCommand = null;
}
}
return dResult;
}
// Metodo publico encargado de salvar el Domain Object en el Datasource
public long add(object aDO) {
try {
DataSet oDS = new DataSet() ;
oDS.ReadXmlSchema(getSchema());
DataRow oRow = oDS.Tables[0].NewRow();
getPropiedades(oRow,aDO,false);
oDS.Tables[0].Rows.Add(oRow);
saveDS(oDS);
} catch (Exception ex) {
throw new Exception("Error Insertando objeto " + this._doName + " / " +
ex.Message);
}
return getID();
}
public virtual long getID()
{
return 0;
}
Maestría en Informática Aplicada a Redes
Página 158 de 159
//Metodo publico encargado de actualizar el Domain Object en el Datasource
public bool update(object aDO) {
try {
string sSQL = "select * from " + this._doName + " " + this.getWhere(aDO);
DataSet oDS, fDS;
fDS = new DataSet();
fDS.ReadXmlSchema(getSchema());
oDS = getDS(sSQL);
DataRow oRow = oDS.Tables[0].Rows[0];
DataRow fRow = fDS.Tables[0].NewRow();
foreach(DataColumn oColumn in oDS.Tables[0].Columns) {
fRow[oColumn.ColumnName.ToString()] =
oRow[oColumn.ColumnName.ToString()];
}
fDS.Tables[0].Rows.Add(fRow);
fDS.AcceptChanges();
getPropiedades(fRow, aDO,true);
saveDS(fDS,true,aDO);
} catch(Exception ex) {
throw new Exception("Error actualizando objeto " + this._doName + " / " +
ex.Message);
}
return true;
}
// Metodo publico encargado de eliminar el objeto en el Datasource
public bool delete(object aDO) {
try {
string sSQL = "delete from " + this._doName + " " + getWhere(aDO);
execSQL(sSQL);
} catch(Exception ex) {
throw new Exception("Error eliminando objeto " + this._doName + " / " +
ex.Message);
}
return true;
}
// Metodo publico encargado de eliminar el objeto en el Datasource a partir de un Id
string
public bool deleteById(string id ) {
try
{
string sSQL = "delete from " + this._doName + " " + getWhereID(id);
execSQL(sSQL);
}
catch (Exception ex)
{
throw new Exception("Error eliminando objeto " + this._doName + " / " +
ex.Message);
}
return true;
}
// Metodo publico encargado de eliminar el objeto a partir de un Id numerico
public bool deleteById(long id)
{
try
{
string sSQL = "delete from " + this._doName + " " + getWhereID(id);
execSQL(sSQL);
}
catch (Exception ex)
{
throw new Exception("Error eliminando objeto " + this._doName + " / " +
ex.Message);
}
return true;
}
Maestría en Informática Aplicada a Redes
Página 159 de 159
//Metodo publico que devuelve un Dataset con todos los registros de una tabla
filtrados por el Where enviado
public DataSet getDSWhere(string sWhere) {
try
{
if(setConnection()) return getDS("select * from " + this._doName + " where
" + sWhere);
return null;
} catch (Exception ex) {
throw new Exception("Imposible Obtener Datos de Objeto " + this._doName +
" filtrando por" + sWhere + " / " + ex.Message);
}
}
//Devuelve un Dataset con todos los registros de una tabla
public DataSet getDSAllRecords()
{
try
{
if (setConnection()) return getDS("select * from " + this._doName );
return null;
}
catch (Exception ex)
{
throw new Exception("Imposible Obtener Datos de Objeto " + this._doName +
" / " + ex.Message);
}
}
//Metodo Privado que libera la conexion
private bool releaseConnection()
{
try
{
if (_oCon != null) _oCon.Close();
}
catch (Exception ex)
{
throw new Exception("Error intentando liberar conexión / " + ex.Message);
}
return true;
}
//Metodo publico para liberar recursos y es invocado por el usuario
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
//Metodo protegido que implementa el dispose de los recursos
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
releaseConnection();
}
disposed = true;
}
}
//Destructor del objeto que sera llamado por el Garbage Colector e invocara el
metodo Dispose
~DAOMaster() {
Dispose(false);
}
}
}