HERRAMIENTA CASE PARA MODELADO DE ALMACENES DE DATOS BASADA EN LENGUAJES ESPECÍFICOS DE DOMINIO AUTORES: ENRIQUE CATALA BAÑULS VICENTE SORIANO CLAVER TUTOR: JUAN CARLOS TRUJILLO MONDEJAR DEPARTAMENTO: DPTO. DE LENGUAJES Y SISTEMAS INFORMÁTICOS CURSO: 2005-2006
229
Embed
HERRAMIENTA CASE PARA MODELADO DE ALMACENES DE DATOS BASADA EN LENGUAJES ESPECÍFICOS DE DOMINIO
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
HERRAMIENTA CASE PARA MODELADO DE ALMACENES DE DATOS BASADA EN LENGUAJES
ESPECÍFICOS DE DOMINIO
AUTORES:
ENRIQUE CATALA BAÑULS
VICENTE SORIANO CLAVER
TUTOR:
JUAN CARLOS TRUJILLO MONDEJAR
DEPARTAMENTO:
DPTO. DE LENGUAJES Y SISTEMAS INFORMÁTICOS
CURSO:
2005-2006
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
¿Qué son y para qué sirven? .......................................................................... 4 Software Factories y MDA ............................................................................... 4 Proceso de desarrollo ..................................................................................... 5 Modelo de dominio (DomainModel) ................................................................ 6 Diseñador gráfico (Designer) .......................................................................... 8 Plantillas de generación de código ................................................................ 10 Compilación .................................................................................................. 11 Ejecución ....................................................................................................... 11 Ejemplo sencillo ............................................................................................ 12
I. Gestión del proyecto ...................................................................................... 17
Planificación .................................................................................................. 17 Proceso de desarrollo ................................................................................... 21
Diagrama de Gantt .................................................................................... 22 Repositorio .................................................................................................... 23
Gráfico de revisiones ................................................................................. 24 Sincronización con el repositorio ............................................................... 26 Estadísticas de desarrollo .......................................................................... 27 Versiones estables por hito ....................................................................... 29
II. Lenguaje específico de dominio para modelado multidimensional ............... 30
Modelo de dominio ........................................................................................ 30 Esquema conceptual ................................................................................. 30 Hacia un modelo compilable ...................................................................... 33
Atributos embebidos .............................................................................. 33 Relaciones en el modelo ........................................................................ 35 Errores de compilación .......................................................................... 38
Esquema definitivo .................................................................................... 42 Conectores ............................................................................................. 42 La clase DegenerateFact ...................................................................... 44 Conector del DegenerateFact ................................................................ 48 Esquema final del Modelo de Dominio ................................................... 50
Interfaz de usuario ........................................................................................ 52 Clases y formas ......................................................................................... 53 Conectores entre clases ............................................................................ 55 Problemas encontrados ............................................................................. 58
Cambio de iconos en la Toolbox ............................................................ 58 Etiquetas en los conectores (Text Decorators) ...................................... 59 Iconos en las Compartment Shapes ...................................................... 60 Iconos transparentes .............................................................................. 63
Restricciones y validaciones ......................................................................... 63 Archivos de recursos ................................................................................. 64
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
3
Soft Constraints ......................................................................................... 66 Añadir cardinalidades en las relaciones ................................................. 68 Restricciones de la clase Base .............................................................. 71 Restricciones de los conectores del DegenerateFact ............................ 74 Atributos derivados ................................................................................ 75
Mensajes de error ...................................................................................... 93 Lista de errores original (modelo de la Universidad de Alicante) ........... 93 Lista de errores del proyecto .................................................................. 96
Menú de comandos ..................................................................................... 102 Cambios en el CommandSet ................................................................... 103 Ficheros embebidos como recursos ........................................................ 105 Cuadros de diálogo.................................................................................. 110
III. Generación de código. ............................................................................... 121
Modelo de generación de código ................................................................ 121 Introducción ............................................................................................. 121 Descripción del proceso de procesamiento de los diagramas OOMM .... 123 Tipos de datos implicados en la generación de código ........................... 135
Especificación del motor de BBDD destino de la generación de código . 184 Extensión de nuevos motores de BBDD destino ..................................... 185
Modelo de validación del generador de código ........................................... 189 Generación de código ................................................................................. 190
Generación de código SQL Estrella......................................................... 195 Generación de código SQL Snowflake .................................................... 204 Generación de código Oracle Warehouse Builder ................................... 216
Detector de palabras reservadas ................................................................ 223 Abstracción de tipos de datos ..................................................................... 225
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
4
DSL Tools
¿Qué son y para qué sirven?
Un Lenguaje Específico de Dominio (Domain-Specific Language, o DSL) es un
lenguaje diseñado para realizar una determinada tarea o para resolver un problema
específico, en contraste con los lenguajes de propósito general (C#, Java…). Al usar
lenguajes específicos de dominio, se pueden construir herramientas de modelado
personalizadas y, básicamente, diseñar un nuevo lenguaje de modelado e implementarlo de
una forma muy sencilla. Por ejemplo, un lenguaje específico puede usarse para describir
una interfaz de usuario, un proceso de negocio, una base de datos o un flujo de
información, y después, a partir de estas descripciones, ser usado para generar código.
Las Domain-Specific Language Tools (a partir de ahora, DSL Tools) o
herramientas para construir DSLs, pueden ser usadas para construir herramientas de diseño
personalizadas, adaptadas a cualquier problema. Por ejemplo, se puede crear una
herramienta de modelado para un proceso de negocio usando las DSL Tools, para describir
así determinados conceptos de cómo funcionan los modelos de negocio de tu organización.
Si estás construyendo una herramienta para representar diagramas de estados, puedes
describir qué es un estado, las propiedades que tiene un estado, qué tipos de estados
existen, cómo están definidas las transiciones entre estados, etc. Un diagrama de estado
usado para describir el estado de los contratos en una compañía de seguros y otro para
especificar la interacción del usuario entre las páginas de un sitio Web son
superficialmente similares, pero los conceptos subyacentes que representan son totalmente
distintos. Creando una herramienta de diseño personalizada, se puede especificar
exactamente la definición de los conceptos del diagrama de estado que se necesitan para
dicha herramienta.
Software Factories y MDA
En los últimos años, han surgido dos principales metodologías que siguen el
paradigma de desarrollo software dirigido por modelos: la Model Driven Architecture
(MDA) y las Software Factories. La MDA es una propuesta del Object Management
Group (OMG) y es una de las aproximaciones más divulgadas en la comunidad científica
por su estado de madurez. Por otro lado, una aproximación más reciente y que está
teniendo un gran impacto es la denominada Software Factories, propuesta por Microsoft.
El término MDA se refiere a un enfoque sobre el desarrollo dirigido por modelos
basado en el uso de tecnologías de modelado del OMG, haciendo especial hincapié en el
Lenguaje de Modelado Unificado (UML - Unified Modeling Language) y en el Servicio
para Meta-Objetos (MOF – MetaObjects Facility). La esencia de MDA consiste en hacer
una distinción entre los modelos de plataforma independiente (PIMs – Platform
Independent Models) y los modelos de plataforma específica (PSMs - Platform Specific
Models). Para desarrollar una aplicación con MDA es necesario primero construir un PIM
de la aplicación, luego transformarlo a un PSM usando un mapeado estandarizado para así,
finalmente, obtener de este último el código de la aplicación.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
5
Las fábricas de Software utilizan conocimientos de dominio específicos,
arquitecturas de solución, herramientas y otros activos reutilizables para ayudar a sus
usuarios a producir tipos específicos de soluciones de software. Una fábrica de Software se
basa en tres puntos claves:
Un sistema para la fábrica de software.
Una plantilla para la fábrica de software
Un entorno de desarrollo extensible.
La fábrica de software configura el entorno de desarrollo extensible, como por
ejemplo Eclipse, Borland Jbuilder o Microsoft Visual Studio Team System (VSTS),
utilizando un paquete de instalables llamado plantilla de la fábrica de software o paquete
de instrucciones. Si se configura de esta forma, el entorno de desarrollo se vuelve una
utilidad especializada que acelera el desarrollo de un tipo específico de solución de
software, como una interfaz del usuario o una capa de acceso a una base de datos, o tal vez
toda una aplicación en un dominio empresarial como por ejemplo el cuidado de la salud o
la seguridad nacional.
La plantilla de la fábrica de software se organiza por medio de un modelo llamado
sistema de la fábrica de software. El sistema define uno o más puntos de vista que son
relevantes para las partes interesadas en la producción de la solución de software deseada.
Cada punto de vista define artefactos del ciclo de vida producidos o consumidos por los
interesados, las actividades que ellos realizan con estos artefactos y los bienes reutilizables
disponibles para soportarlos al realizar estas actividades. La metodología de la fábrica de
software integra el Desarrollo Orientado por un Modelo (MDD – Model Driven
Development), el Desarrollo Basado en el Componente (CBD – Component-Based
Development) y las prácticas de desarrollo ágil, incluyendo el uso de patrones y lenguaje
de patrones con modelos, marcos y Herramientas (Ver “Recursos”).
Para nivelar los modelos de forma efectiva para las varias formas de
automatización, las fábricas de software hacen gran uso de los lenguajes específicos de
dominio. La tecnología DSL es mucho más nueva que varias de las otras tecnologías
utilizadas en las fábricas de software, y depende de familias de lenguajes extensibles. Sin
embargo, los marcos y herramientas de creación del DSL han estado en desarrollo por
algún tiempo en los grupos académicos, y han comenzado a aparecer recientemente en
forma comercial (como las DSL Tools).
Proceso de desarrollo
Para llevar a cabo un proyecto guiado por las DSL Tools hay que tener en cuenta un
proceso de desarrollo necesario para cada nuevo proyecto. Dicho proceso no es secuencial,
hay una serie de pasos que se repiten y a los que se vuelve atrás a fin de ir avanzando en el
desarrollo del modelo. Dichos pasos se pueden esquematizar de la siguiente forma:
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
6
Lo primero es crear un nuevo proyecto DSL, seleccionando File, New, Project…, y
en la parte de Other Project Types, Extensibility buscar el Domain Specific Language
Designer.
El cuadro central se refiere a la creación del lenguaje de dominio. Se compone de
dos partes, la definición del modelo de dominio y la del diseñador gráfico. Ambas partes se
realizan de forma paralela, se debe estar sincronizándolas conforme avanzamos para crear
así un lenguaje válido.
Cada vez que creamos un doblete Modelo de dominio – Diseñador Gráfico
consistente, debemos después transformar los templates, depurar y/o ejecutar el código,
modelar el nuevo lenguaje creado en la ventana de depuración del Visual Studio y, por
último, escribir las plantillas de generación de código para ese lenguaje.
Una vez acabado se puede volver a definir el DSL, depurar, modelar y generar
código, así hasta que se logre el lenguaje específico de dominio que se anda buscando.
Modelo de dominio (DomainModel)
Un proyecto dirigido por las DSL Tools se divide en dos partes fundamentales,
aunque muy relacionadas. La primera de ellas consiste en crear un modelo del lenguaje o
metamodelo. De forma esquemática, se pretende mostrar el funcionamiento que va a tener
nuestro lenguaje específico de dominio. Para ello se utilizan conceptos ya conocidos, como
relaciones, herencia, clases, propiedades… El fichero que guarda este modelo es el
DomainModel.dsldm, contenido en el proyecto DomainModel.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
7
La figura básica del modelo es la clase. Con las clases podemos representar
cualquier elemento significativo de nuestro lenguaje (un diagrama, un cuadro de diálogo de
un asistente, un atributo de otra clase…). Dichas clases pueden estar compuestas de
propiedades. Estas propiedades pueden ser de los tipos de datos más comunes: String,
Boolean, Int32, Int64, Double… También se pueden definir tipos de datos enumerados y
tipos de datos simples. Para visualizar las propiedades de una clase, debemos desplegar el
símbolo + que se encuentra más a la derecha de la clase. Tanto clases como propiedades se
dibujan arrastrando los elementos Class y Value Property de la Toolbox.
La clase que aparece con una X significa que es la raíz del modelo, y es de donde
deben derivar el resto de clases. Si una clase no está relacionada con la clase raíz no podrá
mostrarse posteriormente en la pantalla del diseñador.
Tenemos tres tipos de relaciones entre clases:
- Embedding: relaciones embebidas. Significa que una clase contiene a otra, o
que un concepto está formado por otro. Normalmente se suele utilizar para
establecer atributos dentro de las clases (ya que es necesario que sea una
Embedding relationship para que luego se pueda representar gráficamente de
esa manera). Representada por una línea continua.
- Reference: referencias entre clases. Simplemente es una relación entre dos
conceptos (A se relaciona con B). Representada por una línea discontinua.
- Inheritance: relaciones de herencia entre clases. Aquí existe una clase padre, y
una clase hija que hereda las propiedades del padre (y que contendrá además las
suyas propias). Se representa por una flecha que apunta al padre.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
8
Todas ellas menos la relación de herencia se pueden representar a parte en el
esquema seleccionando la clase con el botón derecho y dándole a la opción “Show As
Class”. Las clases que representan relaciones se muestran en color rojo oscuro. Así le
podemos asignar también propiedades a las relaciones e incluso relacionarlas con otras
clases.
El triángulo y el rectángulo encima de las relaciones indican los roles y las
cardinalidades en ambos sentidos. Para el triángulo el sentido en que se lee es el que
indica, de izquierda a derecha, y para el rectángulo el sentido contrario. El texto que
aparece encima de la relación pertenece al nombre del role del triángulo. Para saber el
nombre del role rectángulo y el de la relación hay que seleccionarlos y mirar en la ventana
de propiedades.
Poniendo como ejemplo la figura anterior y las distintas cardinalidades que le
podemos asignar al role ‘Pages’, representado como el triángulo en la imagen, vamos a
explicar el significado de cada cardinalidad y cómo obtenerla (valores max y min en la
ventana de propiedades):
- 1 (max=1, min=1) Una PageFlow debe tener exactamente una única Page.
- 0 (max=1, min=0) Una PageFlow puede tener como mucho un Page (esto es,
o 0 o 1).
- + (max=0, min=1) Una PageFlow debe tener 1 o más Pages.
- * (max=0, min=0) Una PageFlow puede tener 0, 1 o más Pages.
Este significado se puede intuir con las relaciones máximo-mínimo. Para el caso de
0 y 1 es tal y como se supone: max y min expresan sus correpondientes valores máximo y
mínimo. Para el caso de + y * es igual si pensamos que max=0 tiene el sentido de muchos.
Diseñador gráfico (Designer)
La segunda parte de la que se compone un proyecto con las DSL Tools es la del
diseñador gráfico. Es la parte que relaciona los elementos del Domain Model con sus
correspondientes en el entorno gráfico. El fichero principal que contiene todas las
definiciones es el Designer.dsldd, contenido en el proyecto Designer.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
9
Dicho fichero contiene el código XML con todas las definiciones necesarias. Pero
resulta algo complicado editarlo, porque la documentación es escasa y el código
complicado. Afortunadamente una empresa (Modelisoft) creó una aplicación llamada
DslDm2Dd para sincronizar el DomainModel.dsldm con el Designer.dsldd de forma
gráfica y de manera muy intuitiva. Al instalarse la herramienta se puede arrancar
directamente desde el entorno de Visual Studio seleccionando Tools/DslDm->Dd.
A la izquierda se encuentran los elementos del Domain Model, y a la derecha sus
correspondientes en el Designer. Las rayas rojas indican los que están relacionados entre
sí. Si existe alguna incompatibilidad, aparecerá un mensaje de aviso en la ventana de abajo.
Normalmente las clases en el Domain Model se corresponden con las Shapes en el
Designer, y las RelationShip con los Connectors. En el ejemplo de la figura, ExampleClass
se corresponde con ExampleShape; y ExampleRelation con ExampleConnector.
Para editar las Shapes o los conectores basta con seleccionarlos y darle al botón
derecho y ‘Edit’. Si tenemos un elemento en el Domain Model que aun no está relacionado
con nada, para crear una nueva Shape o Connector habrá que seleccionarlo y arrastrarlo
hasta la raíz de la parte del Designer. Enseguida aparecerá el asistente que nos ayudará en
el proceso.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
10
Si una clase está embebida por otra, poder mostrar en el Designer esa clase como
un atributo de la segunda. Para ello, al editar la clase principal hay que seleccionarla como
Compartment Shape, y en la parte donde te piden los Compartments of the shape, añadir
un nuevo compartment dándole al símbolo + y seleccionar la clase del desplegable
melCollection Expression.
Una vez acabado la edición, hay que guardar los cambios, cerrar la aplicación y
volver al entorno del Visual Studio.
Plantillas de generación de código
Los ficheros del DomainModel.dsldm y el Designer.dsldd una vez definidos son
utilizados para generar otro código. Ese es el código que será la base de nuestro lenguaje
de dominio. Para generarlo y saber si hemos hecho todo correctamente, debemos darle al
botón que se encuentra a la derecha de la ventana del Solution Explorer llamado
“Transform All Templates”. Si no aparece ningún error, el Domain Model y el Designer
estarán sincronizados correctamente.
También existe otro tipo de ficheros que generan código. Son aquellos que
podemos encontrar con extensión *.dslddt para el proyecto del Designer y *.dsldmt para
los del Domain Model. Son ficheros templates, y si nos fijamos todos ellos tienen un
archivo anidado, que corresponde al código que generan. Para generar dicho código se
puede seleccionar el archivo de generación con el botón derecho y pinchar en “Run
Custom Tool”. Esta Custom Tool está especificada en la ventana de propiedades del
archivo, normalmente con valor TextTemplatingFileGenerator. Estos ficheros también
generan su código cuando le damos al botón “Tranform All Templates”.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
11
Del mismo modo se pueden definir templates que generen código para el lenguaje
específico de dominio final. Se pueden añadir en el proyecto destino, y utilizarlos de la
misma manera que los anteriores. Pueden llevar extensiones como *.t4 o
*.ReportTemplate.
Compilación
Una vez creado el lenguaje DSL y generados todos los templates correctamente,
pasamos a depurar o ejecutar el código. Para ello no hay más que darle a F5 o al botón en
forma de rectángulo verde en el entorno del Visual Studio. Al lado de dicho botón
podemos seleccionar si queremos ejecutarlo en modo depuración o en modo release.
Normalmente cuando se desarrollo un proyecto se ejecuta siempre en modo depuración. El
release se usará cuando se esté desarrollando el instalador, para la versión final del
proyecto.
El hecho de que hayamos generado todos los templates correctamente no significa
que el modelo sea correcto. Podemos encontrarnos errores debidos a otras circunstancias,
como por ejemplo que hayamos introducido algunos nombres con espacios en blanco que
posteriormente son transformados en variables. Habrá que estar atentos a los mensajes que
nos aparezcan en la ventana de errores para poder solucionarlos.
Ejecución
Cuando conseguimos ejecutar el proyecto DSL, surgirá una nueva instancia de
Visual Studio con un nuevo proyecto abierto, que corresponderá a nuestro lenguaje de
dominio creado. En la ventana de la solución veremos los archivos incluidos en él.
Algunos deben tener la extensión que decidimos que tendrían los archivos que
representarían el nuevo lenguaje al crear el proyecto DSL. Si abrimos algunos de estos
archivos, aparecerá la ventana del diseñador y un menú a la izquierda con las herramientas
que podemos incluir en el: formas, conectores, etc.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
12
Para modelar simplemente habrá que arrastrar estos elementos de la Toolbox al
campo de trabajo. Dependiendo de las cardinalidades y las restricciones que hayamos
definido, se podrán conectar o no los elementos entre sí. Del mismo modo, podremos
encontrarnos con errores de modelado si así se ha especificado con anterioridad.
Al acabar de modelar, se podrá generar código a partir de nuestro modelo con
aquellos archivos incluidos en el proyecto destinados para ese fin dándole al botón de
Transform All Templates.
Ejemplo sencillo
Vamos a ver de forma rápida como crear un lenguaje específico de dominio para
modelar tablas relacionales y generar su código sql correspondiente.
Creamos un nuevo proyecto DSL Designer con nombre “LenguajeRelacional” a
partir del Minimal Language. Le ponemos como nombre del lenguaje también
“LenguajeRelacional”, el Namespace “UA.EjemploDSL.LenguajeRelacional” y la
extensión “rlc”.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
13
Abrimos el fichero DomainModel.dsldm. La raíz del proyecto se llamará
ModeloRelacional, estará formado por Tablas que a su vez estarán formadas por Atributos
y por una Clave Primaria. Las tablas podrán relacionarse entre sí por claves ajenas.
Para crear el modelo de dominio empezamos haciendo un “Replace All” de
ExampleModel por ModeloRelacional, y otro de ExampleClass por Tabla. Reemplazamos
los nombres necesarios en clases y conectores, y añadimos las relaciones embebidas para
Atributo y Clave Primaria. Hay que asegurarse de que el rol triángulo de las relaciones
embebidas tenga su propiedad Accepts a “All”. También le quitamos a Tabla la propiedad
ExampleProperty y añadimos a Atributo la propiedad Tipo.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
14
Le damos al botón de “Transform All Templates” y ejecutamos el DslDm2Dd para
sincronizar con el diseñador. Editamos el ExampleShape y el ExampleConnector a fin de
cambiarles el nombre y sincronizarlos con Tabla y RelacionClavesAjenas. TablaShape
será una CompartmentShape, que tendrá embebidas las clases Atributo y Clave Primaria.
Salvamos el fichero y volvemos al Visual Studio. Volvemos a darle al botón de
“Transform All Templates” y depuramos. Si todo ha ido bien, se abrirá una nueva ventana
de Visual Studio donde podremos modelar tablas relacionales.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
15
Además, podemos incluir un fichero en el proyecto final que genere código sql para
cualquier modelo que dibujemos. Para ello le damos al botón derecho en el proyecto
LenguajeRelacionalDebugging y escogemos Add.. NewItem. Le llamamos
GeneraSQL.ReportTemplate y añadimos el siguiente código:
<# foreach(Tabla tabla in this.ModeloRelacional.Elementos)
{
#>
Create Table <#=tabla.Name#>
(
<#
foreach(Atributo atributo in tabla.atributos)
{
#> <#=atributo.Name#> <#=atributo.Tipo#>
<#
}
foreach(ClavePrimaria cp in tabla.cp)
{
#>
PrimaryKey <#=cp.Name#>
<# } #>)
<# }
#>
Añadimos en la propiedad Custom Tool del fichero el texto
“TextTemplatingFileGenerator” y así veremos como se crea un fichero llamado
GeneraSQL.sql con el siguiente código:
Create Table Tabla1
(
Atributo1 String
Atributo2 Int
PrimaryKey CP1
)
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
16
Create Table Tabla2
(
Atributo3 Float
PrimaryKey CP2
)
Que se generará automáticamente a partir del modelo contenido en el fichero
“Test.rlc”.
Finalmente, y tan solo como nota aclaratoria, hemos de decir que en este apartado
no se ha pretendido plasmar el modelo relacional por completo. Simplemente lo hemos
utilizado como ejemplo para mostrar las posibilidades que nos ofrecen las DSL Tools.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
17
I. Gestión del proyecto
Planificación
Para la planificación del proyecto hemos utilizado Microsoft Proyects puesto que al
ser dos personas no necesitábamos sistemas de planificación más avanzados y porque nos
ofrecía lo que necesitábamos, que era la planificación de requerimientos entre tareas, la
asignación de requisitos para llevarlas a cabo y la planificación de fechas. Esto añadido a la
posibilidad de realizar diagramas de gantt de forma automática nos hizo decidirnos.
Pese a que realizamos un primer estudio de la planificación de tareas que tenían que
ser llevadas a cabo, a medida que avanzábamos en los conocimientos sobre las DSL Tools
nos dimos cuenta que había que cambiar la planificación para adaptarla a la forma de
programación del modelo y la generación de código. De esta forma podremos ver mas
adelante como algunas de las tareas planeadas en un principio, como la fase de generación
de código, cambiaron radicalmente al estudiar la forma en la que teníamos que utilizar las
DSL Tools para generar código a partir de nuestros diagramas. De la misma forma,
pasamos de tener prevista la finalización del proyecto el día 16 de Mayo al día 26 de Mayo
como al final vimos que sería mas factible. Esta última fecha del día 26 de Mayo fue la
que finalmente cumplimos puesto que dimos por acabado el proyecto ese mismo día,
pese a que no teníamos finalizado el proyecto de instalación del pluggin, cosa que no
habíamos contemplado en la planificación por ser algo extra.
Vamos a ver un resumen de las 39 tareas en las que subdividimos el proyecto, para
hacernos una idea algo mas general de lo que tuvimos que llevar a cabo para su desarrollo,
para ello, adjuntamos la tabla de tareas realizadas del proyecto a día 28/06/2006, cuando ya
habíamos terminado la fase principal del proyecto, pero aún no teníamos implementado el
instalador de la aplicación:
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
18
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
19
En ella podemos ver de forma general, las 34 tareas que ya teníamos
implementadas, así como los tiempos de desarrollo que invertimos en cada una de ellas.
Ahora pasamos a mostrar el desglose de la planificación, atendiendo a los recursos
que utilizamos, que fuimos tanto vicente como enrique, puesto que fuimos los dos únicos
programadores del pluggin.
Como recursos, a parte de nosotros dos, hacemos referencia a tres archivos
llamados End-End.WizardUIPGuide.doc, Example.ValidationAndConstraints.doc y
Example.DSLCustomizations.doc puesto que fueron tenidos en cuenta en los comienzos del
desarrollo para estudiarnos el modelo, funcionamiento y programación de las DSL Tools.
No se ha tenido en cuenta como recurso por otra parte, la información relativa al
modelo multidimensional orientado a objeto que modela nuestra aplicación, puesto que eso
fue algo que tuvimos que aprendernos antes de llevar a cabo el proyecto y no hemos creído
conveniente incluir en los tiempos algo que se supone teníamos que saber para poder
realizar la herramienta CASE.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
20
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
21
Proceso de desarrollo
Para llevar a cabo un proyecto guiado por las DSL Tools hay que tener en cuenta un
proceso de desarrollo necesario para cada nuevo proyecto. Dicho proceso no es secuencial,
hay una serie de pasos que se repiten y a los que se vuelve atrás a fin de ir avanzando en el
desarrollo del modelo. Dichos pasos se pueden esquematizar de la siguiente forma:
El proceso de desarrollo usando DSL Tools, como podemos ver en el diagrama
anterior, es un proceso incremental e iterativo. El proceso de desarrollo comienza con la
creación de un nuevo proyecto Domain Specific Language Designer, que no es mas que el
diseñador gráfico que representará nuestro modelo y luego a partir de el será cuando
comencemos a programar la generación de código, la cual podemos ver representada
mediante la transformación de templates a la generación de código.
Pese a que en la planificación del proyecto que nos hicimos, podemos ver un una
planificación en cascada, puesto que vamos haciendo una cosa cuando acabamos la otra, el
modelo del lenguaje de dominio se ha realizado usando una metodología iterativa puesto
que una vez teníamos una versión estable, volvíamos al principio para añadir funcionalidad
y mejorar el modelo.
No nos ha hecho falta realizar muchas iteraciones completas puesto que el modelo
estaba muy bien especificado y pudimos realizar cada paso prácticamente conforme lo
teníamos previsto, pero eso no quita que lo normal sea tener un proceso iterativo en la
definición del modelo de dominio.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
22
Diagrama de Gantt
A continuación se muestra el diagrama de Gantt de todo el proceso de desarrollo del proyecto, incluyendo la fase 1 de preparativos en
la que estuvimos investigando el funcionamiento de las DSL Tools.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
23
Repositorio
Decidimos montar un sistema de control de versiones para poder controlar el
proyecto correctamente y no tener sobresaltos ante perdidas de información y sobre todo
porque podemos tener el control del código siempre que queramos, pudiendo volver a
versiones previas del desarrollo si llegábamos a algún punto de “no retorno” al ir
programando.
Las 3 opciones que barajamos eran:
CVS
Subversión
Visual SourceSafe
La tercera fue inmediatamente descartada a pesar que es la que nos propone por
defecto la herramienta Visual Studio 2005, puesto que su modelo de programación “en
exclusiva” no permitía trabajar simultáneamente a los desarrolladores en los mismos
archivos, quedando bloqueados siempre que los editaba alguien. Esto era un problema
puesto que al trabajar físicamente dispersos, no podíamos estar pendientes el uno del otro
en cada momento.
CVS era una buena candidata al principio por tratarse de un sistema de control de
versiones maduro y estable pero le faltaba algo, y este algo era que tiene la pega de que
cada uno de los cambios que se realizaban se subían completamente al repositorio y esto
quiere decir que si tenemos 1000 versiones distintas del mismo archivo con pequeños
cambios, tenemos 1000 archivos idénticos pero con pequeños cambios entre ellos y que
ocupan prácticamente lo mismo. Teniendo en cuenta que trabajaríamos con ficheros de
documentación de varios megas, .dll´s que podrían ocupar cientos de kilobytes,…esto
supondría una ocupación de disco bastante amplia para el servidor donde lo teníamos
montado (un servidor propiedad de Enrique Catalá) que tenia disco limitado.
Nos decantamos finalmente por Subversión por disponer de todo lo que
necesitábamos además de tratarse del nuevo sistema de control de versiones que se está
imponiendo en la comunidad de Software Libre para desarrollos distribuidos y que como
principal ventaja era que las actualizaciones de archivos no eran completas, sino que se
actualizaba en el repositorio única y exclusivamente la porción modificada. Incluso los
archivos de .doc funcionaban de esta forma (no siendo el caso de los archivos binarios
como imágenes, zip,…) y esto nos aseguraba actualizaciones mas rápidas, menos tráfico de
red y menos consumo de espacio en disco del servidor.
Finalmente instalamos subversión sobre un servidor con Sistema Operativo Ubuntu
Hoary.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
24
Gráfico de revisiones
A continuación se muestra el gráfico de revisiones que se ha ido formando a
medida que realizábamos el proyecto. Podemos ver como en cada uno de los hitos
conseguidos, realizábamos una nueva rama estable que almacenábamos en una carpeta de
backup dentro del repositorio.
Cada uno de los hitos está marcado en color gris. Cada vez que cumplíamos un hito
hacíamos un “fork” sobre el proyecto en desarrollo que almacenábamos ( para nunca más
tocar ) en una subcarpeta denominada “Backups\Versiones Estables” y que podemos ver
gráficamente mediante los recuadros de color verde.
Si nos fijamos, la ruta principal del proyecto es
/ProyectoDSL/ObjectOrientedMultidimensionalModel, mientras que la ruta de los backups
de los hitos es /ProyectoDSL/Backups/Version X/ObjectOrientedMultidimensionalModel
Hemos de resaltar que la Revisión 208 podemos ver que es eliminada en la revisión
214 porque lo que se almacenaba no consideramos conveniente tomarlo como un hito,
puesto que se trataba de la prueba de concepto de embeber los ficheros de generación de
código en la dll del proyecto, pero que no funcionaba aún por lo que decidimos eliminarla.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
25
Podemos observar si vemos el gráfico, que hay una etiqueta de texto explicativa
que se corresponde a la Revisión 225 ( versión 0.4 y última ), donde podemos ver que el 10
de Mayo de 2006 dimos por finalizada la tarea 30 que se correspondía con el paso de
embeber los ficheros de generación de código en la .dll cumpliendo la planificación que
nos marcamos y que podemos ver en el diagrama de Gantt.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
26
Sincronización con el repositorio
Vamos a mostrar la pantalla que hemos estado utilizando para controlar cada una de las revisiones que realizábamos. Esta pantalla
forma parte del programa TortoiseSVN (cliente de Subversión para Windows), que puede ser descargado de la Web
http://tortoisesvn.sourceforge.net/downloads totalmente gratuito y con licencia GPL.
La pantalla consta de 3 partes bien diferenciadas:
1. Podemos ver información sobre cada una de las revisiones, fecha, autor, mensajes que utilizábamos para describirla,..
2. En la segunda podemos ver el comentario que realizábamos en cada actualización
3. En la tercera los archivos modificados, añadidos o eliminados que han intervenido en la revisión.
IncorrectAggregationCardinality The aggregation cardinalities only can
be 0, 0..1, 0..*, 1 and 1..* DomainModel.Resource.resx
IncorrectBasesCardinality The bases association cardinalities only
can be 0, 0..1, 0..*, 1 and 1..* DomainModel.Resource.resx
Lenguaje de Especificacion del dominio para un Modelo Multidimensional Orientado a Objetos
Proyecto de fin de carrera de Enrique Catala Bañuls y Vicente Soriano Claver
Año académico 2005-2006
101
Error Texto Archivo de recursos NOTAS
IncorrectBaseRoles
In a Rolls-upTo or Completeness
association, one of the ends contains the
role '+r' and the other end contains the
role '+d'
DomainModel.Resource.resx
Mezcla entre el error 45 y el
error 48. Se produce cuando
se introduce un valor no
válido (distinto a ‘+r’ o ‘+d’)
SameBaseRoles
In a Rolls-upTo or Completeness
association, one of the ends contains the
role '+r' and the other end contains the
role '+d'
DomainModel.Resource.resx
Exactamente el mismo que el
anterior, pero se produce
cuando se introduce un valor
válido pero ya existente en el
otro extremo
SaveValidationFailed There were validation errors, continue
save? Designer.Resource.resx Ver apartado Soft Constraints
SaveOperationCancelled The model was not saved. Designer.Resource.resx Ver apartado Soft Constraints
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
102
Menú de comandos
Llegados a este punto, ya disponemos de un modelo completo. El modelo lógico
está acabado, la interfaz del diseñador tiene el aspecto que buscábamos (dentro de las
limitaciones de la herramienta) y toda la semántica queda establecida tras definir las
validaciones y restricciones. También suponemos que está implementada la parte de
generación de código (ver punto III, Generación de Código). La única parte gráfica que
falta es la que relaciona el diseñador de ficheros oomm con la generación de código.
Durante las pruebas con la generación de código, lo que se ha estado haciendo es
incluir los ficheros en el proyecto de depuración, y para generar el código simplemente se
le daba al botón de Transform All Templates (o seleccionar el fichero, botón derecho y
Run Custom Tool). Para que esto funcionara, había que poner en la propiedad Custom
Tool el valor “TextTemplatingFileGenerator”. De esta manera ya se podía usar el botón
para generar el código.
Pero en la versión final no queríamos que esto fuese así. Quedaba mucho más
vistoso seleccionar la opción de generar el código mediante un cuadro de diálogo. Además,
existían diversas opciones que tenían que ser elegidas por el usuario, así que la opción del
cuadro de diálogo se convertía en casi obligatoria. De lo contrario, el usuario tendría que
haber abierto cada vez los ficheros de generación de código y haber cambiado las variables
a mano para poder elegir, por ejemplo, el motor de base de datos para generar el fichero
sql, o las dimensiones a ser normalizadas en el modelo SnowFlake. Además, la idea de que
los ficheros que contenían el código apareciesen en la versión final del proyecto tampoco
nos era de mucho agrado, y podía resultar bastante sobrecargado para el usuario.
Por lo tanto en este apartado tratará sobre todo lo que hemos tenido que hacer para
solucionar estos puntos. Se hablará del CommandSet.dslddt, un fichero que ha sido crucial
para poder crear el menú contextual. También de cómo hemos incluido los ficheros de
generación de código como atributos embebidos, para que no apareciesen en la versión
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
103
final del proyecto, y por último hablaremos de cada uno de los cuadros de diálogo y de los
pasos que hemos seguido para crearlos.
Cambios en el CommandSet
Lo primero para realizar todo lo que hemos expuesto en el apartado anterior es
conseguir un menú contextual para poder seleccionar las distintas opciones. La idea
consistía en darle con el botón derecho a una parte vacía del esquema, y que nos dejara
elegir entre las opciones de generar el código con cada uno de los tres modelos. Y para
poder hacer esto, hemos tenido que realizar unos cambios en el archivo
Shell/CommandSet.dslddt principalmente, incluido en el proyecto del Designer.
Pues bien, para poder añadir un comando en el menú hay que seguir los siguientes
pasos:
1. Traer una copia del archivo CommandSet.dslddt. Si hasta ahora no se ha
modificado es muy posible que solo exista una referencia al archivo
CommandSet.dslddi. Si es así, hay que buscarlo en el directorio
TextTemplates de la ruta de instalación de las DSL Tools, reemplazarlo por
su include correspondiente y ponerlo al final del fichero.
2. Añadir un identificador para cada comando. Para ello, al final del archivo
CommandSet.dslddt hay que añadir una nueva clase llamada
CustomCommandIdList con el siguiente código:
internal static class CustomCommandIdList
{
//Values must be equal than those in CustomCmd.ctc
public const uint cmdIdEstrella = 0x400;
public const uint cmdIdSnowFlake = 0x500;
public const uint cmdIdWarehouseBuilder = 0x600;
}
Después, en Designer\CtcComponents\CustomCmd.ctc hay que añadir un
#define por cada uno de ellos:
#define cmdidEstrella 0x400
#define cmdidSnowFlake 0x500
#define cmdidWarehouseBuilder 0x600
Y en este mismo fichero, debajo de “GENERATED_BUTTONS” poner:
El texto que pondremos ahí entre comillas será el que aparezca en el menú.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
104
3. Añadir los comandos al CommandSet. Aquí es la parte donde se incluirá el
código que deberá realizarse cada vez que seleccionemos la opción del
menú. Primero hay que añadir un par de líneas por cada nuevo comando en
el método GetMenuCommands():
// Add "Genera Modelo Estrella" menu command
menuCommand = new DynamicStatusMenuCommand (
new EventHandler(OnStatusEstrella),
new EventHandler(OnMenuEstrella),
new CommandID(GuidList.guidObjectOrientedMultidimensionalModelCmdSet,
(int)CustomCommandIdList.cmdIdEstrella));
commandList.Add(menuCommand);
// Add "Genera Modelo SnowFlake" menu command
menuCommand = new DynamicStatusMenuCommand(
new EventHandler(OnStatusSnowFlake),
new EventHandler(OnMenuSnowFlake),
new CommandID(GuidList.guidObjectOrientedMultidimensionalModelCmdSet,
(int)CustomCommandIdList.cmdIdSnowFlake));
commandList.Add(menuCommand);
// Add "Genera Modelo WarehouseBuilder" menu command
menuCommand = new DynamicStatusMenuCommand(
new EventHandler(OnStatusWarehouseBuilder),
new EventHandler(OnMenuWarehouseBuilder),
new CommandID(GuidList.guidObjectOrientedMultidimensionalModelCmdSet,
(int)CustomCommandIdList.cmdIdWarehouseBuilder));
commandList.Add(menuCommand);
Y luego añadir los métodos propios que definirán su comportamiento. Esto
se compone de dos métodos por cada comando, OnStatus y OnMenu:
if(selection.Current is ObjectOrientedMultidimensionalModelDiagram)
cmd.Enabled = cmd.Visible = true;
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
105
}
4. Incrementar índice del menú. Lo encontramos en
Designer\Shell\Package.dslddt.
[ProvideMenuResource(1000, 3)]
5. Compilar y depurar.
Los comandos deben aparecer al darle al botón derecho en una zona vacía de un
diagrama oomm.
Para poder trabajar mejor con el fichero CommandSet.dslddt se recomienda
modificar primero su fichero generado, el CommandSet.cs, ya que este hace uso de la
sintaxis coloreada y de la llamada Intellisense prompting, que te puede ir mostrando código
de ayuda conforme se va escribiendo. Pero hay que acordarse al acabar de modificar
siempre el CommandSet.dslddt, si no en cuanto se generen templates los cambios
realizados en el CommandSet.cs desaparecerán.
Ficheros embebidos como recursos
Los ficheros que contienen toda la generación de código que daba lugar a los
archivos finales .sql se habían mantenido desde un principio en el proyecto que debería
utilizar el usuario final. Como ya se ha dicho, no se quería que estos ficheros pudiesen
verse, porque toda esa generación de código debía de ser transparente al usuario y el que
estuviesen incluidos en el proyecto solo resultaban un estorbo para el diseñador. Por ello se
decidió incluir estos ficheros como recursos embebidos en el proyecto
ObjectOrientedMultidimensionalModel, y recurrir a ellos cuando fuese necesario.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
106
Antes debemos hablar un poco del fichero de recursos CommandSet.Resource.resx.
Este archivo no existía en un principio, se añadió debido a la cantidad de recursos que nos
han sido necesarios a la hora de modificar el CommandSet y añadir los nuevos comandos
para el menú. Se han usado dos tipos de recursos:
Strings. Cadenas de caracteres que podemos dividir en:
o Ficheros de entrada y salida: fileInputEstrella, fileInputSnowFlake,
fileInputWarehouseBuilder, fileOutputEstrella,
fileOutputSnowFlake y fileOutputWarehouseBuilder.
o Cadenas identificativas para sustituir en los ficheros de generación
de código: conditionNormalizeDims, fileModel y motorBDModel.
Estas cadenas tiene el formato: $_CADENA_EN_FICHERO_$,
donde CADENA_EN_FICHERO es la cadena que aparece en el
fichero de generación de código que habrá que sustituir por un valor
determinado. Dicho valor dependerá de la elección del usuario.
o Motores de base de datos, para seleccionar el motor de base de datos
con el que se generará el código: motorOracle y motorSQLServer.
Ficheros. Aquí se encuentran embebidos los archivos de los que antes
hablábamos, utilizados para la generación de código. Son once:
o cabecera.comentarios,
o ClaseTClaveAjena.t4,
o ClaseTColumna.t4,
o ClaseTTabla.t4,
o ClaseTTablaMultidimensional.t4,
o ClaseValidacion.t4,
o DepuracionGeneracion.ReportTemplate,
o GeneradorSQLEstrella.ReportTemplate,
o GeneradorSnowFlake.ReportTemplate,
o GeneradorWarehouseBuilder.ReportTemplate y
o RecursosApoyoGeneracionCodigo.t4.
Aunque los principales son los Generador*.ReportTemplate, los demás son
librerías necesarias sin las que no podríamos generar los ficheros .sql. Por lo tanto se ha
programado de forma que cuando se genere código por primera vez, todos estos ficheros se
copien en el path del proyecto, y así puedan estar a mano para cualquier otro momento que
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
107
se necesiten. Esto se ha englobado en una método privado llamado crearFicsApoyo(), que
StreamWriter stw = new StreamWriter(interFicPath);
stw.Write(templateContent);
stw.Close();
File.Move(interFicPath, filePath);
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
StreamWriter stw = new StreamWriter(interFicPath);
stw.Write(templateContent);
stw.Close();
File.Move(interFicPath, filePath);
}
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
StreamWriter stw = new StreamWriter(interFicPath);
stw.Write(templateContent);
stw.Close();
File.Move(interFicPath, filePath);
}
}
Como se ve, hay un trozo de código para cada uno de los ficheros. Todos ellos
consisten en lo mismo. Primero cogemos el path donde debería estar el fichero. Si está ahí
no haremos nada, pero si el fichero no existe entonces lo crearemos. Para ellos cogemos el
contenido del fichero desde el archivo de recursos, y lo volcamos en un fichero de texto
intermedio. Esto se hace así porque si no se copia en un fichero de texto los caracteres no
aparecerán con el formato adecuado. Al final se le cambia el nombre del fichero de texto al
que debe realmente tener.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
110
De esta manera también conseguimos que si en algún momento se borra alguno de
los ficheros por la razón que sea, podamos recuperarlo de forma transparente. Este método
se le llamará cada vez que se ejecute un comando, al principio del método OnMenu.
Por último comentar que existía otro fichero llamado PalabrasReservadas.txt que
en un principio se embebió al igual que los otros. Sin embargo este fichero, a diferencia de
los demás, se abre y se lee como un StreamReader dentro del código generado, y la ruta en
la que se busca no es la misma que donde se crea el proyecto. Por eso se decidió copiarlo
en una ruta fija junto con la instalación del proyecto, en el directorio
C:\WINDOWS\OOMM Files. Esto se lleva a cabo en el proyecto del Setup, y todos los
nuevos proyectos OOMM leerán dicho archivo desde esa ruta.
Cuadros de diálogo
Aquí explicaremos como se han implementado las funciones de los comandos, más
concretamente el código que se encuentra en los métodos OnMenu del CommandSet.
Antes de pasar a explicar cada uno, debemos comentar algunas funciones auxiliares que
utilizan:
condicionDimsNormalizadas(). Crea una cadena de texto con las
dimensiones que van a ser normalizadas en forma de condición, para que así
Se le pasan dos parámetros. El primero es la lista de las dimensiones, y se
utiliza para obtener su nombre. El segundo es un vector de booleanos que
indica las dimensiones que deben estar normalizadas y las que no. Un true
en la posición de una dimensión indica que dicha dimensión debe estar
normalizada.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
111
Recorreremos el vector de booleanos, y cada vez que se encuentre un valor
true se concatenará en el string sentenciaIF la cadena
“dim.Name=="nombreDeLaDimension" ||”, donde nombreDeLaDimension
se obtiene de la lista de dimensiones. Si no se encuentra ninguna dimensión
a normalizar devolverá la cadena “false”. En caso contrario se le quitarán
los cuatro últimos caracteres, que corresponden al símbolo OR (||) más los
espacios.
Así se devolverá la variable sentenciaIF que contendrá una expresión del
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
112
crearFicsApoyo();
//Preguntamos por el motor de base de datos
MotorBDForm bdForm = new MotorBDForm();
DialogResult dr = bdForm.ShowDialog();
if (dr == DialogResult.OK)
{
//Leemos el codigo del fichero, y reemplazamos el nombre
string result = templateGen.ProcessTemplate(inFic,
templateContent, null);
//Escribimos en el fichero de salida
StreamWriter stw = new StreamWriter(outFic);
stw.Write(result);
str.Close();
stw.Close();
//Añadimos el fichero al proyecto
if (!existiaOutput) addToProject(outFic);
System.Windows.Forms.MessageBox.Show("El codigo generado se
ha guardado en el fichero \"" + Shell.CommandSet_Resource.fileOutputEstrella
+ "\"", "Sql Estrella Generado");
}
}
Lo primero siempre en cada modelo es guardar los paths de entrada (fichero
GeneradorSQLEstrella.ReportTemplate, en este caso) y de salida (GeneradorEstrella.sql),
en las variables inFic y outFic, respectivamente. También se guarda en la variable
existiaOutput si el fichero de salida ya existía, y hacemos la llamada a la creación de los
ficheros de apoyo (que los creará en el caso que sea necesario, como se explicó en el
apartado Ficheros embebidos como recursos).
A continuación sacamos un cuadro de diálogo que nos pregunte por el motor de
base de datos. Se ha creado una nueva clase llamada MotorBDForm para esto, y la
explicaremos más adelante. Ahora, por el momento nos basta saber que el método
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
113
ShowDialog aplicado a dicha clase nos devuelve una variable de tipo DialogResult que nos
dice si se le ha dado al botón de aceptar. En caso de ser así continuamos, y realizamos los
siguientes pasos:
1. Leer el código del fichero de entrada (el template que generará el código
final), y guardarlo en la variable templateContent.
2. Reemplazar el nombre del fichero (el de extensión oomm) en el que
estamos actualmente. Para ello usamos la cadena contenida en fileModel
que encontraremos en el fichero de entrada.
3. Reemplazar el motor de base de datos que se usará. Esta información hay
que sacarla del cuadro de diálogo que preguntaba por el motor de base de
datos. Concretamente se obtiene llamando al método getMotorBD() de la
clase MotorBDForm. El valor 1 corresponde a SQL Server, y el valor 2 a
Oracle.
4. Generar código, y guardar el resultado en la variable result.
5. Escribir el resultado en el fichero de salida.
6. Añadir el fichero al proyecto si no existía de antes.
7. Mostrar mensaje informativo diciendo que se ha generado el código.
La clase MotorBDForm se encuentra en el proyecto del Designer, en su directorio
raíz. Contiene el código necesario para crear una ventana que te pregunta sobre el motor de
base de datos con el que quieres generar el código sql.
En el archivo MotorBDForm.cs se han añadido un par de métodos útiles para
comunicarse con el CommandSet:
public partial class MotorBDForm : Form
{
int motorBD;
public MotorBDForm()
{
InitializeComponent();
}
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
SnowFlakeForm sfWin = new SnowFlakeForm(dimensions, ref
dimsParaNormalizar);
DialogResult drDim = sfWin.ShowDialog();
if (drDim == DialogResult.OK)
{
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
115
//Creacion de la condicion IF que muestre las dimensiones
Empezamos de la misma manera que en el modelo Estrella. Después de comprobar
que se le ha dado a Aceptar en el diálogo del MotorBDForm, debemos mostrar otro
diálogo con respecto a las dimensiones que queremos normalizar. Aquí también se ha
hecho una nueva clase para este cuadro de diálogo llamada SnowFlakeForm. Tenemos que
pasarle dos parámetros a dicha clase para poder crear un objeto: una lista con las
dimensiones del modelo actual, y un vector de booleanos del mismo tamaño que el número
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
116
de dimensiones, y que contendrá “true” o “false” dependiendo si la dimensión con el
mismo índice está o no normalizada.
Una vez creadas dichas variables invocamos el cuadro de diálogo con ShowDialog,
y si el usuario le da a Aceptar continuaremos. Los pasos a seguir en este caso son muy
parecidos a los del modelo Estrella, pero con un par de añadidos:
1. Creación de la condición if que muestre las dimensiones que están
normalizadas. Para ello usamos el método auxiliar
condicionDimsNormalizadas(), explicado anteriormente en el apartado
Cuadros de diálogo.
2. Leer el código del fichero de entrada y guardarlo en la variable
templateContent.
3. Reemplazar el nombre del fichero oomm en el que estamos actualmente.
4. Reemplazar el motor de base de datos que se usará.
5. Reemplazar la condición para las dimensiones que hay que normalizar
creada en el punto 1.
6. Generar código, y guardar el resultado en la variable result.
7. Escribir el resultado en el fichero de salida.
8. Añadir el fichero al proyecto si no existía de antes.
9. Mostrar mensaje informativo diciendo que se ha generado el código.
La única diferencia es la selección de las dimensiones que hay que normalizar. Para
hacerlo nos valemos de la clase SnowFlakeForm, creada en la raíz del proyecto Designer.
Nos muestra una lista con las dimensiones del fichero actual, y un checkBox a la izquierda
de cada una de ellas para seleccionar aquellas que se quieren normalizar.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
117
Si intentamos abrir el fichero SnowFlakeForm.cs con el diseñador del Visual
Studio de ventanas de Windows, veremos que nos aparece un cuadro de diálogo vacío.
Esto es porque se ha tenido que modificar el código generado por el Visual para poder
crear un cuadro de diálogo en tiempo de ejecución, ya que será distinto dependiendo del
número de dimensiones que tengamos en un determinado momento.
Si vemos el código nos encontraremos con lo siguiente:
public partial class SnowFlakeForm : Form
{
bool[] dimsParaNormalizar;
public SnowFlakeForm(IList listaDims, ref bool[] vector)
/// A partir de una lista con las dimensiones del modelo,
devuelve otra con los
/// strings de los nombres de las dimensiones para manejarlos
mas facilmente
/// </summary>
/// <param name="listaDims"> Lista de dimensiones del modelo
</param>
/// <returns> Lista con los nombres de las dimensiones
</returns>
private IList getListaStrings(IList listaDims)
{
IList listaStrings = new ArrayList();
foreach (Dimension dim in listaDims)
listaStrings.Add(dim.GetComponentName());
return listaStrings;
}
}
Tenemos un vector de booleanos global llamado dimsParaNormalizar que será el
que contenga justo eso, un “true” en aquellas posiciones correspondientes a las
dimensiones que van a ser normalizadas. Dicho vector se asigna por referencia al vector
que se le pasa al crear el objeto. El objetivo de esta clase es rellenar dicho vector.
Se ha cambiado la definición del InitializeComponent, de manera que se le pase un
parámetro que se obtiene del método getListaStrings. Este método recibe una IList con las
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
118
dimensiones del modelo, y devuelve otra IList con los strings de los nombres de dichas
dimensiones. Como esos strings son lo único que necesitamos, se ha creado este método
para extraerlos y poder trabajar con ellos más fácilmente.
Para ver como conseguir obtener las dimensiones que selecciona el usuario para
normalizar hay que abrir el fichero SnowFlakeForm.Designer.cs. Se ha modificado el
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
119
// SnowFlakeForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F,
13F);
this.AutoScaleMode =
System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(440, 121 +
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
120
//Creacion de los ficheros de apoyo
crearFicsApoyo();
//Leemos el codigo del fichero, y reemplazamos el nombre
1. Obtener los paths de entrada y salida, y crear los ficheros de apoyo de ser
necesario.
2. Leer el código del fichero de entrada y guardarlo en templateContent.
3. Reemplazar el nombre del fichero del modelo en el que estamos
actualmente.
4. Generar código, y guardar el resultado en la variable result.
5. Escribir el resultado en el fichero de salida.
6. Añadir el fichero al proyecto si no existía de antes.
7. Mostrar mensaje informativo diciendo que se ha generado el código.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
121
III. Generación de código
Modelo de generación de código
Introducción
El modelo de generación de código ha sido diseñado pensando especialmente en el
desarrollo rápido de scripts de generación de código, el mantenimiento y la ampliación de
motores de Bases de Datos soportados.
Se ha hecho hincapié sobre todo en disponer de una API de programación sencilla
de utilizar y fácil de ampliar por futuros diseñadores de DSL.
Aquí podemos ver el diagrama de las clases implicadas en el proceso de generación
de código a partir de los diagramas .oomm que el usuario ha diseñado utilizando una
solución ObjectOrientedMuldimensionalModel desde Visual Studio 2005 (ver manual de
usuario).
(*) Diagrama de clases de las clases implicadas en la generación de Código.
Podemos ver que tenemos solo 6 clases relacionadas con la generación de código y
una Enumeración llamada MotorBBDD.
Tal y como hemos comentado anteriormente, la API de generación de código la
hemos diseñado pensando en la facilidad de cara a la generación de scripts SQL y es por
ello que el programador de nuevos scripts de SQL va a tener que utilizar únicamente la
clase TTabla o TTablaMultimensional, por lo que el resto de clases no van a tener que
aprender a utilizarlas.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
122
La enumeración MotorBBDD se ha pensado para que se vayan añadiendo nuevos
motores de Bases de Datos ( informix, DB2,cache,…) de forma fácil puesto que las clases
son independientes del lenguaje de generación de código para el que el script vaya a
generarse, teniendo que ampliar unos pocos métodos de TTabla o TTablaMultimensional
para soportarlos, quedando el grueso de la generación de código 100% válido e intacto.
El ejemplo palpable de todas las bondades de esta API es que en nuestro proyecto
damos la opción de generar código para los dos motores de Bases de Datos mas potentes
de hoy en día, ORACLE y SQL Server y que los mismos scripts de generación de código
SQL son exactamente idénticos para ambas bases de datos. Esto es posible en gran medida
a que tanto para la generación de SQL Estrella como para la generación de SQL
Snowflake, se ha utilizado el ANSI SQL-99, quedando adaptadas algunas particularidades
de cada motor de base de datos como simples mejoras ( como el soportar nombres largos,
con espacios,… como nombres de objetos de la BBDD a generar ).
Para la programación de la API hemos optado por el lenguaje de programación C#
2.0 por dos motivos: El primero es por tratarse del lenguaje de programación que se ha
seguido desde un principio para la construcción del diseñador gráfico y el segundo porque
nos proporciona una legibilidad similar a la de C++, Java,… que nos da la seguridad de
que el abanico de potenciales programadores capaces de hacer frente a una extensión de la
API sea mayor ( esto no seria así de haber elegido la opción de Visual Basic 2005 ).
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
123
Descripción del proceso de procesamiento de los diagramas OOMM
En este punto vamos a explicar brevemente el proceso de procesamiento de los
diagramas OOMM. No se pretende aun hacer un análisis detallado de los scripts de
generación de código, sino explicar los razonamientos que nos han llevado a la
construcción de la API así como de los scripts de procesamiento que se verán mas
adelante.
Los diagramas diseñados desde el editor visual de Visual Studio 2005 pueden ser
desglosados en varias partes de procesamiento diferenciadas, que pueden ser fácilmente
distinguibles si atendemos al siguiente diagrama de ejemplo:
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
124
*Diagrama de ejemplo que contiene el 100% de funcionalidad.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
125
En color verde, podemos distinguir un bloque formado por una clase Dimension,
una clase Fact y una clase Degenerate Fact.
Este tipo de estructuras van a generar siempre un código fijo consistente en lo
siguiente:
Una tabla que producirá la clase Fact ( en este caso Auto-Sales )
Una tabla que producirá la clase Dimension ( según sea SQL Estrella
o SQL Snowflake tendrá una u otra estructura).
Una tabla con el mismo nombre que el Degenerate Fact ( en este
caso se llamara [SP Commission] ) que tendrá como clave primaria una serie de
columnas que a su vez tendrán que ser clave ajena apuntando a la clave primaria de
la tabla que genera la clase Fact y a la clave primaria de la tabla que genera la clase
Dimension.
El código SQL Estrella del bloque verde del diagrama anterior para SQL Server
seria el siguiente:
CREATE TABLE Salesperson
(
Salesperson int NOT NULL IDENTITY PRIMARY KEY
,[SP personal data_Fullname] varchar(255),
[SP personal data_Name] varchar(255),
[SP personal data_Surname] varchar(255),
[SP personal data_Borndate] varchar(255),
Group_Name varchar(255),
Group_Description varchar(600),
Position_Name char(255),
Position_Description varchar(255)
)
GO
CREATE TABLE [Auto-Sales]
(
ContractN int NOT NULL,
Auto int NOT NULL,
Customer int NOT NULL,Commission varchar(255),
Quality decimal(5,3),
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
126
Price varchar(255),
Total varchar(255)
)
GO
---
---Creacion de la clave primaria compuesta de la tabla [Auto-Sales]
---
ALTER TABLE [Auto-Sales]
ADD CONSTRAINT [pk_Auto-Sales] PRIMARY KEY(
ContractN,Auto,Customer )
GO
---
---Creacion de las claves ajenas a las tablas principales de la
tabla Auto-Sales
---
ALTER TABLE [Auto-Sales]
ADD CONSTRAINT [FK_Auto-Sales_to_Auto]
FOREIGN KEY ( Auto )
REFERENCES Auto ( Auto )
GO
ALTER TABLE [Auto-Sales]
ADD CONSTRAINT [FK_Auto-Sales_to_Customer]
FOREIGN KEY ( Customer )
REFERENCES Customer ( Customer )
GO
--
-- Ahora van las asociaciones de DegenerateFact.
--
CREATE TABLE [SP commission]
(
ContractN int NOT NULL,
Auto int NOT NULL,
Customer int NOT NULL,
Salesperson int NOT NULL,Commission char(255)
)
GO
---
---Creacion de la clave primaria compuesta de la tabla [SP
commission]
---
ALTER TABLE [SP commission]
ADD CONSTRAINT [pk_SP commission] PRIMARY KEY(
ContractN,Auto,Customer,Salesperson )
GO
---
---Creacion de las claves ajenas a las tablas principales de la
GO * Se han omitido las tablas Customer y Auto por no ser necesarias para la explicación
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
127
En color azul, podemos distinguir un bloque formado por una clase Fact y una
clase Dimension que se encuentra libre, sin estar unida a ninguna clase Base.
En este caso, también tendremos una estructura fija para describir este bloque del
diagrama. Tendremos dos tablas, la primera la formara la clase Fact y la segunda la tabla
Dimension. La relación entre ambas quedara definida por la clave ajena que habrá entre
ambas y que irá desde la tabla Fact a la tabla Dimension.
El código SQL Estrella del bloque azul del diagrama anterior para SQL Server seria
el siguiente:
--
-- Tabla Dimension llamada Auto
--
CREATE TABLE Auto
(
Auto int NOT NULL IDENTITY PRIMARY KEY
)
GO
--
-- Tabla Fact llamada Auto-Sales
--
CREATE TABLE [Auto-Sales]
(
ContractN int NOT NULL,
Auto int NOT NULL,
Customer int NOT NULL,Commission varchar(255),
Quality decimal(5,3),
Price varchar(255),
Total varchar(255)
)
GO
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
128
---
---Creacion de la clave primaria compuesta de la tabla [Auto-Sales]
---
ALTER TABLE [Auto-Sales]
ADD CONSTRAINT [pk_Auto-Sales] PRIMARY KEY(
ContractN,Auto,Customer )
GO
---
---Creacion de las claves ajenas a las tablas principales de la
tabla Auto-Sales
---
ALTER TABLE [Auto-Sales]
ADD CONSTRAINT [FK_Auto-Sales_to_Auto]
FOREIGN KEY ( Auto )
REFERENCES Auto ( Auto )
GO
ALTER TABLE [Auto-Sales]
ADD CONSTRAINT [FK_Auto-Sales_to_Customer]
FOREIGN KEY ( Customer )
REFERENCES Customer ( Customer )
GO
* Se ha omitido la tabla Customer
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
129
En color rosa podemos distinguir un Grafo Acíclico Dirigido (GAD) formado por 4
clases Base, unido a una clase Dimension que esta unida a su vez a la clase Fact.
Este tipo de estructuras mas complejas ya no son fijas, puesto que ahora ya depende
tanto del código SQL que queramos obtener (Snowflake, Estrella,…), como de la
organización del GAD que forman entre si las clases Base. Es por ello que no nos vamos a
extender en este apartado hablando del código que generan este tipo de estructuras porque
para eso están los apartados específicos de generación de scripts SQL Estrella ,Snowflake
y ORACLE Warehouse Builder.
Lo que si que podemos explicar es que este tipo de bloques se procesan de la
siguiente forma:
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
130
1. Partimos de la clase Fact (Auto-Sales) y rellenamos la estructura
TTabla que lo compone. No escribimos directamente el código que genera esta
clase Fact porque será de las últimas sentencias SQL que tendrá el script ya que
hay varias tablas que deben estar con anterioridad creadas en la BBDD antes de
poder generar esta estructura de tipo Fact (ya que tiene claves ajenas a las tablas
Dimension (customer) ).
2. Una vez tenemos la estructura TTabla de la clase Fact, nos vamos a
la Dimension (en este caso Customer ) y generamos su estructura TTabla.
En este caso la estructura de una TTabla Dimension puede ser muy
compleja puesto que según la organización del GAD de las clases Base, podemos
tener múltiples tablas con múltiples relaciones entre las mismas. Además la
organización de las mismas diferirá si se trata de un script Snowflake y se ha
decidido normalizar la dimensión, a si se trata de un script Estrella en el que las
dimensiones están todas desnormalizadas.
Una vez tengamos la TTabla rellena, generamos las sentencias pertinentes y
las escribimos al fichero .sql
3. Por último, una vez tenemos generado ya el código de generación de
tablas para las tablas Dimension, ya podremos generar las sentencias pertinentes de
la tabla Fact que saldrán de la estructura TTabla que hemos rellenado en el paso 1.
No dará error porque las tablas a las que apuntan sus claves ajenas ya estarán
creadas con anterioridad en el paso 2.
En relación al paso 2, da igual que estemos ante un caso snowflake, estrella o oracle
warehouse builder, hemos de anticipar ( se verá con mas detalle mas adelante ), que las
estructuras GAD se van recorriendo mediante un algoritmo de recorrido en profundidad (
DFS ) de Grafos Aciclicos Dirigidos y que para dar la sensación de que los scripts son
generados “al vuelo” se utilizan estructuras tipo Queue de .NET ( colas FIFO ) que
después de ser procesadas se escribirán a fichero dando la apariencia de haber sido
generadas en tiempo de ejecución y sin preprocesado alguno.
De este modo, el GAD que forman las clases Base se convertirá en una cola FIFO
de tipos TTabla perfectamente definidos y rellenados que posteriormente se iran
imprimiendo uno a uno a fichero como si se hubiera realizado “al vuelo”.
Esta última afirmación hay que comprenderla bien para afrontar el siguiente
escalafón que es el bloque marcado con color amarillo. En este bloque se complican
mucho mas las cosas porque cada uno de los nodos clase Base de los que aquí hablamos
puede ser a su vez la raíz de un árbol de clases Base. Esto hay que tenerlo en cuenta porque
la afirmación realizada anteriormente se complica algo mas, siendo estas estructuras como
Cola de Colas TTabla. Lo veremos mas detalladamente en el siguiente apartado.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
131
En color Amarillo podemos distinguir un árbol de clases Base formado por 4
bases. La particularidad de este árbol reside en que tiene como raíz a la base “Region”, por
lo que sus nodos van a ser independientes del anterior grafo y entonces podremos ver al
grafo de color rosa como un GRAFO DE ÁRBOLES puesto que de cada nodo podrá salir
un nuevo árbol.
Esta particularidad ha de tenerse muy en cuenta a la hora de procesar el diagrama
para la generación de código puesto que las tablas y relaciones entre las mismas
dependerán en gran medida de lo que se acaba de explicar.
*árbol de clases Base con raíz en la clase Base “Region”
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
132
Dicho esto, para que se vea mas claro, vamos a ver la situación desde el punto de
vista práctico.
Aquí podemos ver el diagrama de la estructura GRAFO DE ÁRBOLES de clases
Base que hemos mencionado.
En ella podemos ver como existe un grafo (color rosa) y un árbol ( color amarillo)
con raíz en un nodo del grafo ( “Region”).
Para procesar este tipo de estructuras, siempre se hace de la misma forma y es
generando una estructura COLA DE COLAS de tipos TTabla.
Lo que hacemos es ir recorriendo el Grafo Aciclico Dirigido de forma que en cada
nodo del grafo nos adentramos para ver si existe algún árbol en el; de esta forma vamos
encolando las distintas instancias de TTabla que vamos instanciando conforme vamos
accediendo a una nueva clase Base dando lugar a una estructura mas simple de procesar y a
partir de la cual ya podemos obtener el código del script que sea de una manera mas
sencilla.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
133
Para que nos hagamos a la idea de forma gráfica, a continuación se muestra un
ejemplo de la famosa estructura COLA DE COLAS.
Estructura COLA DE COLAS que se obtiene del bloque anterior
Podemos fijarnos en que el rojo se corresponde al GAD y el amarillo al ARBOL
En color rojo se ha marcado la COLA principal cuyos nodos están compuesto de
COLAS de clases TTabla.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
134
Esto quiere decir que:
El primer elemento de la cola principal ( la de color rojo ) será una
COLA con un único elemento TTabla denominado “Customer Personal Data”
El Segundo elemento de la cola principal será una COLA con un
único elemento TTabla denominado “City”
El Tercer elemento de la cola principal será una COLA con 5
elementos TTabla encolados de forma que el primer elemento de la cola (el
primero en salir) será el que tiene por nombre “Region”
El Cuarto elemento de la cola principal será una COLA con un único
elemento denominado “State”
Esta estructura se obtiene tal y como hemos comentado, de explorar el grafo
principal en busca de los árboles que parten de cada nodo del mismo.
Tal y como hemos comentado anteriormente, la bondad de esta estructura esta en
que si nos fijamos detenidamente veremos que la estructura si se va desencolando y se va
generando el código ( da igual el tipo de esquema y de lenguaje salida ), el resultado será
similar al de ir procesando “al vuelo” el diagrama que el usuario ha dibujado, dándole un
toque mas profesional.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
135
Tipos de datos implicados en la generación de código
En este apartado vamos a explicar los tipos de datos implicados en la generación de
código, uno a uno.
Teniendo el diagrama de clases visto anteriormente presente, pasamos a explicar
cada tipo de datos.
Enumeración MotorBBDD
Tipo de datos Enumeración que contiene los motores de Bases de Datos que
soporta la aplicación. Por defecto solo soporta ORACLE y SQL Server pero en el punto
“extensión de nuevos motores de BBDD destino”, vamos a explicar lo sencillo que
resultará la extensión de los mismos.
Este tipo de datos es utilizado internamente para realizar las conversiones
necesarias y únicamente ha de ser tenido en cuenta a la hora de programar nuevos scripts
para indicar el motor de base de datos destino en la clase TTabla ( se vera en el punto
“Especificación del motor de BBDD destino de la generación de código” ).
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
136
Clase TClaveAjena
Implementada para proporcionar una interfaz con la que generar nombres de
restricciones de claves ajenas o columnas afectadas por una clave ajena.
Posee 2 metodos estáticos unicamente que pasaremos a explicar:
GenerarNombreConstraint:
Genera un nombre de restriccion de clave ajena. Este nombre no esta validado
contra el Motor de BBDD por lo que hay que validarlo seguidamente.
o nombreTabla
Nombre de la tabla origen
o nombreTablaReferenciada
Nombre de la tabla destino
o Devuelve
Nombre de la restriccion como FK_nombretabla_to_nombretablareferenciada
public static string GenerarNombreConstraint(string nombreTabla, string
DEPRECATED - No se usa, pero se da soporte por si se desea utilizar.
Genera una lista de las columnas afectadas por la clave ajena.
Esto es util por ejemplo cuando nuestra tabla ajena tiene una clave primaria
compuesta de varias columnas y por lo tanto tenemos varias columnas en nuestra tabla que
apuntan hacia la tabla principal.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
137
o colaColumnas
Cola FIFO con TColumna columnas afectadas (generalmente se pasa la cola
FIFO de clave primaria de la tabla principal.
o Devuelve
Cadena separada con comas con los nombres de las columnas que formaran
parte de la clave ajena
public static string GenerarListaColumnas(Queue colaColumnas,
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
138
Clase MetodosBase
Esta clase contiene únicamente los métodos utilizados para obtener información
sobre las clases Base de nuestro modelo multidimensional.
Posee únicamente 4 métodos y son utilizados internamente por la clase TTabla para
la generación de los scripts SQL.
Pasamos a detallar su funcionamiento de forma mas detallada a continuación:
Contiene
Sirve para saber si una base determinada ya se ha añadido a una COLA de
COLAS de bases
Devuelve true si la base esta contenida en la cola de colas de bases o false si no lo
es.
public static bool Contiene(Base baseRaiz, Queue colaBases)
{
bool retorno = false;
// Recorremos las colas que tenemos dentro de la cola de colas y
vemos en las bases que contienen por si estuvieran.
foreach(Queue cola in colaBases)
{
if (cola.Contains(baseRaiz))
retorno = true;
}
return(retorno);
}
EsBaseHoja
Una clase base es una hoja, cuando de ella no podemos llegar a otra base.
Devuelve true si la base es una base hoja.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
139
public static bool EsBaseHoja(Base b)
{
bool retorno;
// Es una base hoja si no podemos ir a otra base desde ella (su
Implementacion de un algoritmo DFS de recorrido de grafos dirigidos en
profundidad.
Esta funcion se utiliza para recorrer las clases Bases que heredan de una clase Base.
Estas clases "Base" se organizan segun un arbol por lo que la mejor forma para
recorrerlo es utilizando un algoritmo para ello.
o baseRaiz
Es la base a partir de la cual vamos a ir recorriendo hacia abajo siguiendo un
recorrido en profundidad
o Visitados
Cola donde se van a ir guardando los nodos (Bases) visitadas según el
recorrido en profundidad del árbol. Se guardan en una estructura tipo FIFO para
que al generarse el código, se genere como si lo hubiéramos ido generando online.
Se pasa por referencia puesto que esa estructura se va a ir modificando
(añadiéndose nodos visitados).
public static void RecorrerBasesHijas(Base baseRaiz, ref Queue
visitados)
{
visitados.Enqueue(baseRaiz);
// Me meto por todas las bases hijas. Solo me interesan ellas.
foreach(Base b in baseRaiz.parentToChild)
{
if (!visitados.Contains(b))
{
// Recordemos que solo nos interesan las bases hijas (
las que hereden de ella )
RecorrerBasesHijas(b,ref visitados);
}
}
}
RecorrerBases
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
140
Implementacion de un algoritmo DFS de recorrido de grafos dirigidos en
profundidad.
Esta funcion se utiliza para recorrer las clases Bases que cuelgan de las clases
Dimension.
Estas clases "Base" se organizan segun un grafo aciclico dirigido por lo que la
mejor forma para recorrerlo es utilizando un algoritmo para ello.
o baseRaiz
Es la base a partir de la cual vamos a ir recorriendo hacia abajo siguiendo un
recorrido en profundidad
o visitados
Cola donde se van a ir guardando los nodos (Bases) visitadas según el
recorrido en profundidad del grafo. El contenido van a ser Colas de Bases. De
forma que tendremos una Cola de Colas Base. De esta forma tendremos en una
posición de la cola a todas las bases relacionadas con parentesco. Se guardan en una
estructura tipo FIFO para que al generarse el código, se genere como si lo
hubiéramos ido generando online. Se pasa por referencia puesto que esa estructura
se va a ir modificando (añadiéndose nodos visitados).
public static void RecorrerBases(Base baseRaiz, ref Queue
visitados)
{
Queue basesHijas = new Queue();
RecorrerBasesHijas(baseRaiz,ref basesHijas);
visitados.Enqueue(basesHijas);
foreach(Base b in baseRaiz.baseAssociates2)
{
if (!Contiene(b,visitados))
{
RecorrerBases(b,ref visitados);
}
}
}
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
141
Clase Validacion
Contiene la clase que se encarga de todo lo que tenga que ver con la validación de
objetos en la generación de código. En ella podremos validar nombres de objetos dentro de
un determinado motor de base de datos, construir tipos de datos de columnas validos
dentro de un motor de base de datos específicos...
Implementación de la clase:
Validacion (constructor de la clase)
Constructor de la clase estatica Validacion
Puesto que es una clase estática, este se ejecuta una sola vez y de forma
transparente, cargando en la propiedad estatica palabrasReservadas, la lista de palabras
reservadas de los motores de Bases de Datos. Esto nos servirá para validar nuestra cadena
contra las Bases de Datos y determinar si el nombre de objeto que queremos usar es una
palabra reservada. De ser así, tendremos que marcarla para que el motor de base de datos
no de error al procesar el script.
El fichero con las palabras reservadas se llama PalabrasReservadas.txt y se instala
en la ruta por defecto de instalacion de Windows, cuando se realiza la instalacion del
pluggin. Editando ese fichero podremos añadir o quitar palabras reservadas de los motores
de bases de datos. Actualmente el fichero contiene TODAS las palabras reservadas del
motor de Base de Datos SQL Server 2005
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
142
La unica separacion entre palabra y palabra dentro del fichero es el \n por lo que no
hace falta marcar ni el inicio ni el fin de fichero.
static Validacion()
{
palabrasReservadas = new Queue();
StreamReader sr;
try
{
sr = new
StreamReader(@"PalabrasReservadas.txt");
String palabra;
while((palabra = sr.ReadLine()) != null)
{
palabrasReservadas.Enqueue(palabra);
}
}
catch(Exception e)
{
Throw;
}
}
BuildSQLDataType
Construye el tipo de datos en función del tipo de datos seleccionados en el combo
de la interfaz del Visual Studio 2005. Este cuadro aparece cuando pulsamos sobre las
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
143
switch(a.dataType)
{
case(DataType.BOOLEAN):
switch(MotorBBDDSalida)
{
case(MotorBBDD.ORACLE):
retorno = "boolean";
break;
case(MotorBBDD.SQLServer):
retorno = "bit";
break;
default:break;
}
if(a.tam!="")
{
mostrarWarningSobraTam = true;
}
break;
case(DataType.CHARACTER):
switch(MotorBBDDSalida)
{
case(MotorBBDD.ORACLE):
retorno = "char";
break;
case(MotorBBDD.SQLServer):
retorno = "char";
break;
default:break;
}
if(a.tam=="")
{
mostrarWarningFaltaTam = true;
retorno += "(10)";
}
else
{
retorno+= "(" + a.tam + ")";
}
break;
case(DataType.CHARACTER_VARYING):
switch(MotorBBDDSalida)
{
case(MotorBBDD.ORACLE):
retorno = "varchar2";
break;
case(MotorBBDD.SQLServer):
retorno = "varchar";
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
144
break;
default:break;
}
if(a.tam=="")
{
mostrarWarningFaltaTam = true;
retorno += "(10)";
}
else
{
retorno+= "(" + a.tam + ")";
}
break;
case(DataType.DATE):
switch(MotorBBDDSalida)
{
case(MotorBBDD.ORACLE):
retorno = "date";
break;
case(MotorBBDD.SQLServer):
retorno = "datetime";
break;
default:break;
}
if(a.tam!="")
{
mostrarWarningSobraTam = true;
}
break;
case(DataType.DECIMAL):
switch(MotorBBDDSalida)
{
case(MotorBBDD.ORACLE):
retorno = "number";
break;
case(MotorBBDD.SQLServer):
retorno = "decimal";
break;
default:break;
}
if(a.tam=="")
{
mostrarWarningFaltaTam = true;
retorno += "(10,2)";
}
else
{
retorno+= "(" + a.tam + ")";
}
break;
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
145
case(DataType.FLOAT):
switch(MotorBBDDSalida)
{
case(MotorBBDD.ORACLE):
retorno = "number";
break;
case(MotorBBDD.SQLServer):
retorno = "float";
break;
default:break;
}
// Ni en sql server, ni en oracle se necesita precision,
pero se puede poner opcional
if(a.tam!="")
{
retorno+= "(" + a.tam + ")";
}
break;
case(DataType.INTEGER):
switch(MotorBBDDSalida)
{
case(MotorBBDD.ORACLE):
retorno = "number";
break;
case(MotorBBDD.SQLServer):
retorno = "int";
break;
default:break;
}
if(a.tam!="")
{
mostrarWarningSobraTam = true;
}
break;
case(DataType.REAL):
switch(MotorBBDDSalida)
{
case(MotorBBDD.ORACLE):
retorno = "number";
break;
case(MotorBBDD.SQLServer):
retorno = "real";
break;
default:break;
}
break;
default:break;
}
if (mostrarWarningSobraTam)
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
146
{
Warning(String.Format("El atributo {0} es de tipo {1} y a pesar de que
no tiene tamaño, se le ha puesto un tamaño de {2}. Por favor, dejar vacio para evitar este
warning.",a.Name,a.dataType,a.tam));
}
else if (mostrarWarningFaltaTam)
{
Warning(String.Format("El atributo {0} es de tipo {1} y no tiene tamaño,
se le ha puesto un tamaño de 10 por defecto . Por favor, pon un tamaño
correcto.",a.Name,a.dataType));
}
return (retorno);
}
FixStringORACLE
Esto es útil para poder utilizar nombres de tablas, columnas,...con espacios en
blanco, pero que solo es compatible con ORACLE. Si se superan los 16 caracteres por
nombre, se trunca a 16 para que no falle el script ya que en ORACLE 9i, el máximo
nombre tanto de tabla como de columna viene dado por identificadores de 16 caracteres.
o typeName
Nombre con espacios en blanco, o caracteres raros, que hay que delimitar.
// El tamaño tope para nombres (tanto para tablas como
para columnas) es de 128 caracteres.
if (typeName.Length > 16 )
retorno = typeName.Substring(typeName.Length - 16
,16);
else
retorno = typeName;
return("\"" + retorno + "\"");
}
FixStringSQLServer
Esto es útil para poder utilizar nombres de tablas, columnas,...con espacios en
blanco, pero que solo es compatible con SQL Server. Si se superan los 128 caracteres por
nombre, se trunca a 128 para que no falle el script ya que en SQL Server 2005, el máximo
nombre tanto de tabla como de columna viene dado por identificadores de 128 caracteres.
o typeName
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
147
Nombre con espacios en blanco que hay que delimitar ( o caracteres
Devuelve el tipo de datos de la clave primaria de una columna para el motor de
Base de datos que se especifique. útil para columnas auto incrementadas o claves primarias
de una sola columna.
o Ls
Motor de Base de datos destino para el que se esta generando el script.
o Return Value
devuelve un tipo number si es para oracle o un tipo int para SQL server.
public static string GetTipoDatosClavePrimaria(MotorBBDD ls)
{
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
148
string retorno="";
switch(ls)
{
case(MotorBBDD.ORACLE):
retorno="number";
break;
case(MotorBBDD.SQLServer):
retorno="int";
break;
default:break;
}
return(retorno);
}
PuedeSerAutonumerico
Nos indica si el tipo de datos que se le pasa puede ser auto numérico o no. Los tipos
auto numéricos de SQL Server son: int, bigint, smallint, tinyint, or decimal or numeric with
a scale of 0 El generador de tipos Validacion.BuildSQLDataType(...) solo genera tipos
"int" , luego solo hay que comprara con este.
o tipoDatos
String con el tipo de datos
public static bool PuedeSerAutonumerico(string tipoDatos)
{
bool retorno = false;
if (tipoDatos == "int")
retorno = true;
return(retorno);
}
ValidateStringANSI
Validacion de cadenas para adecuarlas a SQL Standard.
o cadena
String a validar con espacios en blanco o guiones
o Return Value
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
149
Devuelve todos aquellos espacios en blanco que pueda tener el string en "_" para
// Con esta expresion regular le digo que si encuentra
espacios (\s) o signos "-", se use la que le he dicho
string expresionRegular = @"(\s|-)";
Regex regex = new Regex(expresionRegular);
if (regex.IsMatch(cadena) ||
palabrasReservadas.Contains(cadena.ToUpper()))
{
//Generamos un Warning en la lista de errores de
Visual Studio usando el metodo TextTransformation.Warning.
// MostrarWarning(String.Format("La clase \"{0}\"
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
150
contenia caracteres no permitidos, se ha utilizado la sintaxis específica
de ORACLE que puede que no funcione en todos los motores de BBDD.",
cadena));
retorno = FixStringORACLE(cadena);
}
else
{
retorno = cadena;
}
return(retorno);
}
ValidateStringSQLServer
Validacion de cadenas para adecuarlas a SQL Server.
// Con esta expresion regular le digo que si encuentra
espacios (\s) o signos "-", se use la que le he dicho
string expresionRegular = @"(\s|-)";
Regex regex = new Regex(expresionRegular);
if (regex.IsMatch(cadena) ||
palabrasReservadas.Contains(cadena.ToUpper()))
{
//Generamos un Warning en la lista de errores de
Visual Studio usando el metodo TextTransformation.Warning.
MostrarWarning(String.Format("La clase \"{0}\"
contenia caracteres no permitidos, se ha utilizado la sintaxis específica
de SQL Server que puede que no funcione en todos los motores de BBDD.",
cadena));
retorno = FixStringSQLServer(cadena);
}
else
{
retorno = cadena;
}
return(retorno);
}
ValidateString
Validacion de cadenas para adecuarlas al motor de base de datos que se especifique.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
151
o Cadena
String con la cadena a validar
o Ls
Motor de base de datos destino con el que queremos validar la cadena
public static string ValidateString(string cadena, MotorBBDD
ls)
{
string retorno ="";
switch(ls)
{
case(MotorBBDD.SQLServer):
retorno = ValidateStringSQLServer(cadena);
break;
case(MotorBBDD.ORACLE):
retorno = ValidateStringORACLE(cadena);
break;
default:break;
}
return(retorno);
}
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
152
Clase Tcolumna
Tipo de datos Columna. Usada por la clase TTabla Contiene el nombre y tipo de
datos de una determinada columna. Además, como norma se ha establecido guardar como
nombre de la columna, el nombre real que el usuario le ha dado al objeto, sin validar ni
nada. De esta forma podemos construir nombres mas complejos ( como nombres
identificación de restricciones de clave ajena) sin que afecten para nada los métodos de
validación.
Tanto el nombre de la columna como el tipo de datos se definen al crear la instancia
de la clase y ya no se pueden modificar.
El acceso a estas propiedades privadas se realiza mediante las propiedades públicas
NombreColumna y TipoDatos, que tienen implementado únicamente la operación get ,
impidiendo así modificación alguna.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
153
Clase TTabla
Tipo de datos Tabla.
Es la clase principal que usamos para la generación de código. En ella se
especifican las tablas ajenas, las claves primarias, las columnas...que necesitamos conocer
para generar las sentencias SQL. Internamente soporta todo esto mediante tipos de datos
Colas FIFO para que parezca que se genera el código mientras se procesa el archivo
.oomm.
Hay que indicar que las columnas de la tabla se indican por medio de dos métodos
que son AddColumna y AddClavePrimaria. Si nos damos cuenta no existe ninguno para
indicar claves ajenas puesto que eso se indica añadiendo tablas ajenas. De esta forma no
tenemos que saber que columnas de la tabla a añadir forman parte de nuestras columnas ni
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
154
nada. Mediante el funcionamiento interno del TTabla, se detectaran las columnas que han
de formar parte de la tabla resultante y que han de ir como tabla ajena a las tablas marcadas
como tablas ajenas.
Este método es bastante simple porque nosotros si que sabemos en todo momento
qué tablas vamos a tener que apuntar desde donde estamos, pero en un primer momento no
sabemos qué columnas tiene esa tabla y cuales de las nuestras van a apuntar a ella sin tener
que procesar la tabla ajena antes. El proceso de generación de sentencias de foreign key se
realizará en la fase de generación de código y no en la de preprocesamiento del diagrama.
Esto quiere decir que nosotros primero generaremos las estructuras TTabla y cuando
tengamos que generar el código será cuando analicemos las claves ajenas que necesita y si
la tabla a la que apunta existe ya o no.
Campos Privados
clavePrimaria Cola FIFO de objetos TColumna que identifica a la clave primaria. De esta forma tendremos en esa estructura a todas las columnas que formen la clave primaria
columnas Cola FIFO de objetos TColumna que identifica a las columnas de la tabla que no forman parte de la clave primaria.
nombreTabla Nombre de la tabla que se generara si ejecutamos su método GenerarSentenciaCreateTable()
tablasAjenas Cola FIFO con todas las TTabla ajenas (todas las dimensiones a las que apunta un hecho, por ejemplo). útil para que podamos generar las sentencias ALTER TABLE ... FOREIGN KEY fácilmente.
typeClaseDiagrama Almacena el tipo de datos de la clase que ha generado este tipo tabla. (Dimension, Fact,...) útil para generar create tables y demas.
Campos Estáticos
MotorBBDDSalida Propiedad estática que identifica el motor de BBDD para el que va a ir destinado el código que se auto generará.
StringMotorBBDD Propiedad estática con la que obtendremos el string del motor de BBDD para el que va a ir destinado el código que se auto generará.
Propiedades públicas
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
155
Todas las propiedades públicas tienen permisos de lectura únicamente por lo tanto
no se pueden modificar una vez asignadas. De hecho se generan conforme vamos
añadiendo columnas y/o tablas ajenas.
ClavePrimaria Cola FIFO de tipos TColumna con las columnas que forman parte de la clave primaria
Columnas Cola FIFO de tipos TColumna con las columnas de la tabla que no forman parte de la clave primaria
NombreTabla Solo se permite el acceso de lectura. El nombre de la tabla se da en el constructor únicamente.
StringClavePrimaria String con la clave primaria, ya validado. Si es compuesta, ya nos da las columnas separadas por comas y validadas.
Métodos
TTabla – Constructor
Constructor de tipo TTabla.
Unicamente hace falta indicar el nombre de la tabla que va a generar y el tipo de
clase de nuestro diagrama que la ha generado(Fact, Dimension, Base...).
o Nom
Nombre de la tabla en cuestion
o tipoClase
Tipo de datos de la clase que va a generar la tabla ( Fact, Dimension,
Base,…)
public TTabla(string nom, Type tipoClase)
{
this.nombreTabla = nom;
this.typeClaseDiagrama = tipoClase;
clavePrimaria = new Queue();
columnas = new Queue();
tablasAjenas = new Queue();
}
AddClavePrimaria
Añade una columna a nuestra cola fifo de columnas de claves primarias.
o Col
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
156
Tcolumna a añadir como clave primaria de la tabla.
Puesto que puede ser clave primaria compuesta con lo que iríamos llamando a este
método con cada una de las claves que quisiéramos que formaran parte de la clave primaria
de la tabla.
public void AddClavePrimaria(TColumna col)
{
clavePrimaria.Enqueue(col);
}
AddColumna
Añade una columna a nuestra cola fifo de columnas (no forma parte de las claves
primarias).
o Col
Tcolumna a añadir como clave primaria de la tabla
Las columnas que se añadan aquí, no formaran parte de la clave primaria por lo
tanto o se añaden como columna normal, o se añaden como clave primaria.
public void AddColumna(TColumna col)
{
columnas.Enqueue(col);
}
AddTablaAjena
Añade una tabla a nuestra cola fifo de tablas a las que apunta.
Util para generar las sentencias alter table...foreign key...
o tablaAjena
TTabla a la que apunta. No es necesario indicar nada mas como que
columnas las relacionan ni nada
public void AddTablaAjena(TTabla tablaAjena)
{
tablasAjenas.Enqueue(tablaAjena);
}
AñadirAtributosComoTColumnas
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
157
Añade todos los atributos de la clase que se le pase como parámetro, a la lista de
TColumnas columnas.
o clase
Clase ( Fact, Base, DegenerateFact,…) de la cual queremos extraer todos los
TColumnas necesarios y añadírselos a la TTabla que estamos rellenando
actualmente
clase actualmente solo tiene sentido que sea una base, es por ello que esta dentro
de un if, pero se puede extender su funcionalidad si se desea fácilmente añadiendo if´s.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
158
} // cierro el foreach
} // if (clase is Base)
}
DevolverBasesNormalizadas
Extraemos todas las bases que cuelgan y están conectadas de la dimensión Vamos
almacenando las bases visitadas en una cola(FIFO) según las vayamos visitando según un
algoritmo DFS (Recorrido de grafos aciclicos dirigidos en profundidad). Ya se ha
explicado con anterioridad la estructura de COLA DE COLAS TTabla de la que aquí se
hace gala.
o bv
Esta base que se le pasa, ha de ser la base que esta conectada a la
Dimension. Es decir, de la que cuelgan el resto de bases formando una estructura
de Grafo Aciclico Dirigido.
private Queue DevolverBasesNormalizadas(Base bv)
{
Queue retorno = new Queue();
// Ahora extraemos todas las bases que cuelgan y estan conectadas de
la dimension
// Vamos almacenando las bases visitadas en una cola(FIFO) segun las
vayamos visitando segun un algoritmo DFS (Recorrido de grafos aciclicos dirigidos
en profundidad)
Queue colaBasesVisitadas = new Queue();
//Recorro las bases que tiene por debajo la clase "Dimension" y que
siguen una estructura
// de tipo Grafo Aciclico Dirigido.
RecorrerBases(bv,ref colaBasesVisitadas);
// La primera cola que tenemos contiene la base principal (la que
esta conectada a la dmension) ya esta en una tabla con la dimension en su primera
posicion de la cola , por lo que no hay que crear ninguna tabla con ella
colaBasesVisitadas.Dequeue();
//Una vez tengo ya todas las bases en esta estructura, las voy a ir
recorriendo y generando las estructuras TTabla que luego devolvere en un Array
foreach(Queue colaBases in colaBasesVisitadas)
{
// Recordemos que en las colas de bases que obtenemos, la
primera de las bases que hay en cada cola es la que
// nos interesa porque las que hay despues de ella son hijas
Base b = (Base) colaBases.Peek();
//Creo el tipo TTabla
TTabla tablaBase = new TTabla(b.Name,b.GetType());
tablaBase.GenerarClavePrimaria(b);
tablaBase.ObtenerColumnasRestantes(b);
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
159
// Puede ser que esta base tenga hijos, por lo que una vez
definida, vamos a añadirle las columnas que vengan de los hijos (si es que tiene)
Queue colaBasesHijas = new Queue();
RecorrerBasesHijas(b, ref colaBasesHijas);
// Elimino la primera de la cola porque soy yo misma ;)
colaBasesHijas.Dequeue();
foreach(Base beis in colaBasesHijas)
{
tablaBase.AñadirAtributosComoTColumnas(beis);
}
retorno.Enqueue(tablaBase);
}
return(retorno);
}
DevolverColumnasClavePrimariaConTipoDatos
Solo se lanzara si la clave primaria es compuesta. Especial para casos como las
clases Fact. Se llama desde GenerarSentenciaCreateTable(..) Genera la cadena
clavePrimaria útil cuando la clave primaria es compuesta por varias columnas.
ALTER TABLE nombreFact
ADD CONSTRAINT nombreConstraint
FOREIGN KEY ( nombreFK )
REFERENCES nombreTabla ( clavePrimaria )
o Return Value
String con las columnas que necesitamos para definir una sentencia
ALTER TABLE ... PRIMARY KEY...
o Remarks
GenerarSentenciaAlterTablePrimaryKey (desde aquí se llama)
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
160
return(retorno);
}
ExisteDegenerateFact
Con esto miramos si hay alguna clase FactAttribute entre la Dimension y la clase
Fact que queramos. Esto es útil para evitar añadir columnas en Fact de una Dimension
cuando hay una relación FactAttribute de por medio.
o dim
Dimension a la que tendría que haber una clase DegenerateFact conectada.
o clase
Clase Fact a la que tendría que haber una clase DegenerateFact
conectada
o Return Value
true -> si existe degenerate fact conectada a la dimension y a la clase Fact en
cuestión
false -> caso contrario
public bool ExisteDegenerateFact(Dimension dim, Fact clase)
{
bool retorno = false;
if(dim.factClassAssociatesDegenerateFact.Count>0)
{
foreach(DegenerateFact df in
dim.factClassAssociatesDegenerateFact)
{
Fact efe =
df.degenerateFactAssociatesFactClass[0] is Fact ?
(Fact)df.degenerateFactAssociatesFactClass[0] :
(Fact)df.degenerateFactAssociatesFactClass[1];
if( ((Fact)clase).Name == efe.Name )
{
retorno = true;
}
}
}
return(retorno);
}
GenerarClavePrimaria
Genera la clave primaria de una clase que le pasemos de nuestro diagrama.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
161
Simplemente le pasamos la clase Dimension, Fact, DegenerateFact,... y nos genera
la estructura ClavePrimaria que necesitamos.
o Si le pasamos una Dimension, la clave primaria es auto generada con
PK_nombreDimension
o Si le pasamos una Fact, la clave primaria es la que forman todos los
DegenerateDimension mas todas las claves primarias de las dimensiones a las
que apunta.
o Si le pasamos un DegenerateFact, la clave primaria es la unión de las
claves primarias de la clase Fact y Dimension a las que esta unida.
Solo genera la clave primaria, no tiene en cuenta para nada las demas columnas
que deba tener la tabla, para eso ya existe otro método. Una vez ha finalizado el método, ya
tenemos rellena la estructura Queue clavePrimaria de objetos TColumna.
o clase
Objeto clase de nuestro diagrama (Fact,Dimension,DegenerateFact)
public void GenerarClavePrimaria(Clase clase)
{
string nombreTablaSinValidar;
string clavePrimariaSinValidar;
string tipoDatos;
if (typeClaseDiagrama == typeof(Fact) )
{
// Ahora voy a por los atributos "DegenerateDimension"
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
// Generamos la estructura TTabla con las claves primarias de
la Dimension del extremo y luego añadimos sus columnas
Dimension dim = (Dimension)cls;
TTabla tablaDimension = new TTabla(dim.Name,dim.GetType());
tablaDimension.GenerarClavePrimaria(dim);
foreach(TColumna col in tablaDimension.ClavePrimaria)
{
clavePrimaria.Enqueue(col);
}
this.AddTablaAjena(tablaDimension);
}
if (cls is Fact)
{
// Generamos la estructura TTabla con las claves primarias de
la Fact del extremo y luego añadimos sus columnas
Fact fact = (Fact)cls;
TTabla tablaFact= new TTabla(fact.Name,fact.GetType());
tablaFact.GenerarClavePrimaria(fact);
foreach(TColumna col in tablaFact.ClavePrimaria)
{
clavePrimaria.Enqueue(col);
}
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Especial para casos como las clases Fact. Se llama desde
GenerarSentenciaCreateTable(..) Genera la cadena ALTER TABLE ... FOREIGN KEY …
El resultado es el siguiente:
ALTER TABLE nombreTabla
ADD CONSTRAINT nombreConstraint
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
164
FOREIGN KEY ( nombreFK )
REFERENCES nombreTabla ( clavePrimaria )
public string GenerarSentenciaAlterTableForeignKey()
{
string retorno="";
if (tablasAjenas.Count>0)
retorno = GenerarComentario("Creacion de las claves
ajenas a las tablas principales de la tabla " + NombreTabla);
if (typeClaseDiagrama != typeof(Base) && typeClaseDiagrama !=
typeof(Dimension) )
{
/// Recuerda que tanto en la tabla principal como en la
tabla ajena, tenemos el mismo nombre de columna. Por lo que simplemente
/// hay que hacer un alter table de las columas de mi
tabla a la tabla principal para que se hagan foreign key.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
166
GenerarSentenciaCreateTable
Genera toda la Sentencia Create Table.
Genera el create table y si hace falta los alter tables para claves primarias
compuestas y claves ajenas que apuntan a otras tablas.
Se hace uso de los métodos GenerarSentenciaCreateTableSinClavesAjenas en las
que se devuelve la sentencia sin las claves ajenas a otras tablas más el método de
GenerarSentenciaAlterTableForeignKey en la que se añaden las claves ajenas que pueda
tener la tabla ( si no tiene, no se generaran ).
Si nos fijamos tiene el módificador “virtual” para que pueda ser sobrescrito en
cualquier clase que herede de la clase TTabla ( como vamos a ver cuando veamos
TTablaMultidimensional).
public virtual string GenerarSentenciaCreateTable()
// Esto valdra true cuando tengamos que eliminar la coma del
final de alguna columna
bool flagBorrarComaDelFinal = false;
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
168
}
ObtenerColumnasRestantes
Genera las columnas en la estructura Columnas de nuestra TTabla. Simplemente le
pasamos la clase Dimension, Fact, DegenerateFact,... y nos genera la estructura Columnas
que necesitamos.
o Si le pasamos una Fact, las columnas serán los FactAttributes
o Si le pasamos un DegenerateFact, las columnas restantes serán las
DegenerateDimension y los FactAttribute
No tiene en cuenta las claves primarias, para eso ya existe otro método.
Una vez ha finalizado el método, ya tenemos rellena la estructura Columnas de
objetos TColumna.
public void ObtenerColumnasRestantes(Clase clase)
{
string nombreColumna;
string tipoDatos;
if (clase is Fact)
{
// Los atributos DegenerateDimension forman parte de la
clave primaria de la clase Fact, por eso no estan aqui, se generan en la
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
170
tmp.GenerarClavePrimaria(b);
this.AddTablaAjena(tmp);
}
}
}
ObtenerDimensionDesnormalizada
útil para SQLEstrella y para Sowflake si optamos por desnormalizar la dimension
especifica que se le pasa
Obtiene las columnas restantes que debe tener la TTabla si estamos
desnormalizando por esa dimension. Esto quiere decir que vamos a pasarle un objeto tipo
Dimension y va a recorrer el Grafo Aciclico Dirigido de Bases que cuelga de el y nos va a
generar una tabla con todas las columnas que le pertenecen, desnormalizandolo todo.
Una vez ha finalizado el método, ya tendremos rellena la estructura Columnas
de objetos TColumna.
o dim
Dimension que vamos a desnormalizar obteniendo todo como columnas
para la tabla principal.
public virtual void ObtenerDimensionDesnormalizada(Dimension dim)
{
string nombreColumna;
string tipoDatos;
// Solo puede tener una relacion entre base y dimension
, pero como esta puede hacerse en los dos
// sentidos, pues lo controlo con los sentidos Base->
Dimension o Dimension -> Base (esto viene limitado por el DSL que podemos
cola(FIFO) segun las vayamos visitando segun un algoritmo DFS (Recorrido
de grafos aciclicos dirigidos en profundidad)
Queue colaBasesVisitadas = new Queue();
//Recorro las bases que tiene por debajo la clase
"Dimension" y que siguen una estructura
// de tipo Grafo Aciclico Dirigido.
RecorrerBases(b1,ref colaBasesVisitadas);
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
171
// Primero voy a sacar las colas de bases que
tenemos en la cola principal y que estan relacionadas por parentesco.
foreach(Queue colaFamiliaBases in
colaBasesVisitadas)
{
foreach(Base bv in colaFamiliaBases)
{
AñadirAtributosComoTColumnas(bv);
} // cierro el foreach (Base bv in
colaFamiliaBases
}// cierro el foreach de las colas de bases
}// cierro el if (dim.baseAssociatesDim != null)
}
ObtenerDimensionNormalizada
método para Snowflake. Genera la estructura para la dimension y devuelve un
Array con TTablas de las Bases.
o dim
Dimension que queremos normalizar
public Queue ObtenerDimensionNormalizada(Dimension dim)
{
string nombreColumna;
string tipoDatos;
Queue retorno = null;
// Solo puede tener una relacion entre base y dimension
, pero como esta puede hacerse en los dos
// sentidos, pues lo controlo con los sentidos Base->
Dimension o Dimension -> Base (esto viene limitado por el DSL que podemos
crear con las DSL Tools)
if ( dim.baseAssociatesDim.Count == 1 ||
dim.dimAssociatesBase.Count == 1 )
{
// Ahora la dimension al estar normalizada consta de
la clase dimension y la Base que tiene unida a el (si la tiene)
provenientes de las bases hijas que pueda tener la base principal.
// Una vez ya se la base que va unida a la dimension,
tengo que recorrer sus hijas ( puede que tenga bases que hereden de ella)
Queue colaBasesHijas = new Queue();
RecorrerBasesHijas(bv, ref colaBasesHijas);
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
172
foreach(Base bb in colaBasesHijas)
{
AñadirAtributosComoTColumnas(bb);
// Ahora le faltan las claves primarias a las Bases
a las que esta conectada
// Por un lado se hacen columnas para cada
tabla base a la que esta conectada y por otro se añade esa TTabla a la
lista de claves ajenas
foreach(Base b in bb.baseAssociates2)
{
// Creamos columnas que haran referencia a
las otras tablas base a las que pueda estar conectada
nombreColumna = "fk_" + b.Name;
// Su clave primaria viene dada por el
atributo Descriptor, ya que es unico y seguro que tiene uno
// Ahora voy a por el atributo
"Descriptor"
// Como solo hay uno y ademas es
obligatorio:
Descriptor d =
(Descriptor)b.descriptor[0];
tipoDatos = Validacion.BuildSQLDataType(d
, MotorBBDDSalida);
this.AddColumna(new
TColumna(nombreColumna, tipoDatos));
// Añadimos a la lista de claves ajenas
TTabla tmpb = new TTabla(b.Name,
b.GetType());
tmpb.GenerarClavePrimaria(b);
this.AddTablaAjena(tmpb);
}
}
/// Ahora ya tenemos creada la TTabla de la dimension,
lo que vamos a hacer ahora es crearnos un Array donde meter las TTabla de
las Bases que hay por debajo
retorno = DevolverBasesNormalizadas(bv);
}// cierro el if (dim.baseAssociatesDim != null)
return(retorno);
}
SeparadorSentencias
Devuelve el separador de sentencias según el motor de BBDD al que va destinado
o Oracle ;
o SQL Server go
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
173
protected string SeparadorSentencias()
{
string retorno ="NO SE HA DEFINIDO CORRECTAMENTE EL LENGUAJE DE
SALIDA";
switch(MotorBBDDSalida)
{
case MotorBBDD.SQLServer:
retorno = "GO";
break;
case MotorBBDD.ORACLE:
retorno = ";";
break;
default:break;
}
return(retorno);
}
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
174
Clase TTablaMultidimensional
Tipo de datos Tabla. Es la clase principal que usamos para la generación de código
multidimensional. Hereda de la clase TTabla y redefine aquellos métodos necesarios para
generar código multidimensional.
Actualmente solo genera código multidimensional para ORACLE Warehouse
Builder, pero es sencillo añadir código de generación para MDX de SQL Server como se
podrá ver en el apartado “extensión de nuevos motores de BBD destino”.
Campos privados
colaBasesVisitadas
Contiene la cola FIFO de bases que
tiene por debajo la TTabla. Esta estructura
solo estará rellenada en el caso de que
seamos una dimension, porque son las
únicas que tienen el grafo de bases debajo.
La estructura se rellena en
ObtenerDimensionDesnormalizada()
Constructor TTablaMultidimensional
Llama al constructor de su clase base ( TTabla ) e inicializa a null la cola de bases
visitadas para que puedan generarse mas adelante desde el método
ObtenerDimensionDesnormalizada
public TTablaMultidimensional(string nombre, Type
tipo):base(nombre,tipo)
{
/// Sus datos se rellenan en el metodo
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
175
ObtenerDimensionDesnormalizada
colaBasesVisitadas = null;
}
GenerarCadenasAttribute
Genera la cadena ATTRIBUTE nombreAttribute DETERMINES ( ... ) necesaria para
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
176
GenerarCadenasLevel
Genera las cadenas level ... is ... que necesitamos para definir na estructura de
Genera una sentencia que hace que una determinada columna/s se conviertan en
unique.
Esto es necesario puesto que en oracle Warehouse Builder no tenemos claves
primarias en las tablas y con esto definimos las restricciones de unicidad necesarias para lo
que serian las claves primarias en el caso de que estuviéramos generando SQL snowflake o
estrella.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
178
// Primero van las cadenas donde se definen los niveles
de la dimension
retorno += GenerarCadenasLevel();
// Luego se va a definir la cadena de las jerarquias
// La cadena con las jerarquias (todas las que haya) se
devuelve en la variable recorrido
retorno += stringJerarquias;
// Ahora se genera la cadena donde se definen
retorno += GenerarCadenasAttribute();
// Cierro el create table
retorno += "\n";
// Tengo que separar el create table del alter table.
Segun si es oracle o sql server, usaremos uno u otro.
retorno += SeparadorSentencias() + "\n";
}
return(retorno);
}
GenerarSentenciaCreateTable
Genera una sentencia de CREATE TABLE sobrescribiendo el método de
GenerarSentenciaCreateTable de la clase base ( TTabla ). En este caso las tablas no tienen
claves primarias porque van a ser la base de un modelo multidimensional y en este caso
van a tener claves unique.
El resultado de esto será un CREATE TABLE sin claves ajenas y con claves unique
en lugar de claves primarias.
Además se realiza un COMMIT al final para que no de problemas de ejecución el
script en ORACLE cuando se ejecute todo de golpe porque puede que comience un
CREATE DIMENSION sobre esta tabla pero que no se hayan commiteado los cambios y
den error las sentencias posteriormente.
public override string GenerarSentenciaCreateTable()
{
string retorno;
retorno = this.GenerarComentario("Creacion de la tabla " +
NombreTabla);
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
// Le quito la coma del final, solo si tiene mas de una columna
if(Columnas.Count>1)
retorno = retorno.Substring(0,retorno.Length-2);
// Cierro el create table
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
180
retorno += "\n )\n";
// Tengo que separar el create table del alter table. Segun si
es oracle o sql server, usaremos uno u otro.
retorno += SeparadorSentencias() + "\n";
return(retorno);
}
ObtenerDimensionDesnormalizada
Rellena la estructura de "colaBasesVisitadas" que contiene la cola FIFO de bases
que tiene por debajo la ttabla con la que estamos trabajando.
public override void ObtenerDimensionDesnormalizada(Dimension
dim)
{
string nombreColumna;
string tipoDatos;
// Solo puede tener una relacion entre base y dimension
, pero como esta puede hacerse en los dos
// sentidos, pues lo controlo con los sentidos Base->
Dimension o Dimension -> Base (esto viene limitado por el DSL que podemos
cola(FIFO) segun las vayamos visitando segun un algoritmo DFS (Recorrido
de grafos aciclicos dirigidos en profundidad)
colaBasesVisitadas = new Queue();
//Recorro las bases que tiene por debajo la clase
"Dimension" y que siguen una estructura
// de tipo Grafo Aciclico Dirigido.
RecorrerBases(b1,ref colaBasesVisitadas);
// Ahora voy a sacar las bases que tiene por
debajo cada Clase "Dimension" y que han sido obtenidas por visitas
siguiendo el algoritmo DFS.
// Primero voy a sacar las colas de bases que
tenemos en la cola principal y que estan relacionadas por parentesco.
foreach(Queue colaFamiliaBases in
colaBasesVisitadas)
{
foreach(Base bv in colaFamiliaBases)
{
string nombreBase = bv.Name;
// Hemos restringido a que solo exista
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
181
un único OID y no tiene porque estar definido por defecto
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
182
Implementación de un algoritmo DFS de recorrido de grafos dirigidos en
profundidad modificado para generar cadenas hierarchy. Esta función se utiliza para
generar la cadena de las jerarquías de una dimension. Estas clases "Base" se organizan
según un grafo aciclico dirigido por lo que la mejor forma para recorrerlo es utilizando un
algoritmo para ello.
o baseRaiz
Es la base a partir de la cual vamos a ir recorriendo hacia abajo
siguiendo un recorrido en profundidad
o stringJerarquias
Cadena que va a contener texto intermedio para generar la cadena que
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
183
contenido += stringJerarquias;
}
}
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
184
Especificación del motor de BBDD destino de la generación de código
La especificación del motor de Base de Datos destino de la generación de código se
hace mediante una propiedad estática de la clase TTabla , por la cual podremos indicar
para que Motor de BBDD queremos que salga nuestro script.
Esta propiedad estática tiene el tipo de datos enumeración MotorBBDD y existe
implementación para SQLServer y para ORACLE.
Una vez indicado el motor destino del script, se procederá a utilizar la clase TTabla
de la misma forma tanto si deseamos trabajar para oracle, como si deseamos trabajar para
SQL Server y gracias a tratarse de una propiedad estática, podremos generar cualquier
instancia nueva de tipo TTabla o TTablaMultidimensional nueva y podremos usarla con
normalidad sabiendo que el código generado por ella será el esperado.
Ejemplo de uso:
/// Especificacion del motor de Base de Datos para el que va a ir
destinado el script.
/// Por ahora: MotorBBDD.ORACLE
/// MotorBBDD.SQLServer
TTabla.MotorBBDDSalida = MotorBBDD.ORACLE;
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
185
Extensión de nuevos motores de BBDD destino
Si deseamos que nuestros scripts puedan generarse para nuevos motores de BBDD
que no sean los actualmente soportados ( ORACLE y SQL Server ), podemos hacerlo
fácilmente siguiendo los 6 pasos que a continuación describimos:
1. Añadir un identificador de enumeración nuevo para el motor de base
de datos nuevo en la enumeración MotorBBDD
2. Añadir el separador de sentencias que utiliza el motor de Base de
Datos destino para identificar dentro de un mismo script, las distintas ordenes (
“GO” en SQL Server y “;” en Oracle )
Para ello tenemos que añadir en el método SeparadorSentencias de la clase
TTabla, una nueva entrada en el switch-case.
protected string SeparadorSentencias()
{
string retorno ="NO SE HA DEFINIDO CORRECTAMENTE EL
LENGUAJE DE SALIDA";
switch(MotorBBDDSalida)
{
case MotorBBDD.SQLServer:
retorno = "GO";
break;
case MotorBBDD.ORACLE:
retorno = ";";
break;
default:break;
}
return(retorno);
}
3. Añadir un nuevo método de validacion de nombres de objeto para el
nuevo motor de base de datos soportado. Para ello hay que editar el metodo estatico
ValidateString de la clase estatica Validacion, añadiendole una nueva entrada en el
switch-case , asi como el nuevo método de validacion soportado
public static string ValidateString(string cadena, MotorBBDD ls)
{
string retorno ="";
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
186
switch(ls)
{
case(MotorBBDD.SQLServer):
retorno = ValidateStringSQLServer(cadena);
break;
case(MotorBBDD.ORACLE):
retorno = ValidateStringORACLE(cadena);
break;
default:break;
}
return(retorno);
}
* Este método se explicará mas en detalle en el punto “Modelo de validacion del
generador de código”
4. Añadir el tipo de datos por defecto de las columnas que haran de
clave principal en las tablas de la Base de Datos.Para ello basta con añadir una
nueva entrada en la estructura switch-case del método estatico
GetTipoDatosClavePrimaria de la clase estatica Validacion.
Por ejemplo, en SQL Server , las columnas que hacen de clave principal son
de tipo int, mientras que en ORACLE son de tipo number.
public static string GetTipoDatosClavePrimaria(MotorBBDD ls)
{
string retorno="";
switch(ls)
{
case(MotorBBDD.ORACLE):
retorno="number";
break;
case(MotorBBDD.SQLServer):
retorno="int";
break;
default:break;
}
return(retorno);
}
* Este método se explicará mas en detalle en el punto “Modelo de validacion del
generador de código”
5. Por ultimo solo falta añadir la conversion de tipos de datos específica
que se hará de acuerdo al estándar CWM para el nuevo motor de base de datos.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
187
Por ejemplo, para Oracle el tipo de datos booleano se expresa como
boolean, mientras que para SQL Server se expresa como bit.
Para ello, basta con añadir los tipos de datos necesarios para cada uno de los
soportados por el modelo DSL que hemos diseñado y añadirlos a las sentencias
switch-case del método estático BuildSQLDataType de la clase estática Validacion.
GenerarCadenasLevel, GenerarCadenasAttribute y RecorrerJearquias, de
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
188
los cuales el unico expuesto con modificador “publico” es el de
GenerarSentenciaCreateDimension ya que es el que devuelve el string con la
sintaxis para generar la sentencia CREATE DIMENSION especifica de Oracle.
Este ultimo paso por tanto es el único que habria que implementar desde
cero, pero como se podrá comprobar viendo el código ( se vera mas adelante en el
punto “Generacion de código Oracle Warehouse builder” ) que tiene por debajo, no
es una tarea nada dificil.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
189
Modelo de validación del generador de código
El modelo de validación del generador de código se realiza desde una clase estática
denominada Validacion. Esta clase ya esta explicada en detalle en el punto anterior por lo
que nos centraremos únicamente en explicar el por qué hemos realizado la validación de
forma estática y externa a las clases principales como son TTabla.
Hemos realizado esta separación para poder disponer en todo momento de una
validación independiente del objeto que estamos tratando ( tabla, columna, dimension,…)
y del lenguaje de generación de código. El hecho de estar definida como clase estática nos
asegura que cuando estemos generando los scripts de validación, todas las validaciones se
estarán realizando sobre el mismo Motor de Base de datos y además que la detección de
palabras reservadas se realizara de forma eficiente puesto que las palabras reservadas se
cargaran en la estructura de memoria interna de la clase validación una única vez, en su
constructor estático por lo que no necesitaremos entrar a leer a fichero tantas veces como
instancias de validación tengamos.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
190
Generación de código
Una vez explicado todo lo necesario para poder entender la API de generación de
código que hemos implementado, vamos a explicar lo necesario para entender los scripts
de generación de código que hacen uso de ella.
Vamos a comenzar poniendo la descripción del lenguaje de programación de los
scripts, para luego explicar detenidamente y mas en profundidad su funcionamiento.
La generación de código mediante DSL Tools se realiza mediante scripts que son
procesados por el espacio de nombres Microsoft.VisualStudio.TextTemplating propio de
Visual Studio 2005 y que viene con el kit de Visual Studio 2005 SDK.
Tenemos que ver estos scripts como algo que se procesa de forma parecida a los
archivos .aspx de asp.net en los cuales hay una dll que se encarga de producir código html
a partir de los archivos .aspx y codebehind( .cs, .vb,…) que contenga. Esto quiere decir que
el objeto TextTemplatingFileGenerator propio del espacio de nombres citado, tomará el
siguiente código y generará el código de la forma en la que nosotros le digamos, y esto se
lo hemos dicho mediante el API de generación de código que hemos realizado para tal
ocasión.
Primeramente, lo que tenemos que hacer es añadir un nuevo ítem en el proyecto:
Proyect-> Add new ítem -> Template -> Text File. Una vez tengamos el archivo de texto
que va a ser nuestra futura plantilla o script de generación de código, lo renombramos
como queramos, por ejemplo "sqlPlantilla.ReportTemplate"
En la ventana de propiedades, hemos de poner en la celda de "Custom tool" la
palabra: "TextTemplatingFileGenerator", para que el generador de plantillas, utilice esta
plantilla para generar código.
Podemos tener tantas plantillas como queramos.
TAGS PARA LAS PLANTILLAS
Directivas:
Tienen la sintaxis <#@ directiva #> y a continuación pasaremos a describir las
utilizadas
o Directiva output extension: <#@ output extension=".sql" #>
Con esta directiva nos aseguramos que la plantilla, va a generar un archivo
nombrePlantilla.sql con el código generado.
o Directiva include: <#@ include
file="c:\test.txt" #>
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
191
Mediante la directiva include, podemos incluir en la generación de código,
una serie de información externa como copyright, encabezados, pies de pagina...
o Directivas de depuración:
<#@ template debug="true" #>
<#@ import namespace="System.Diagnostics" #>
Con estas dos directivas podemos hacer depuración en la generación del
código, justo mientras se encuentra el TextTemplatingFileGenerator en ejecución,
Para poner breakpoints, basta con poner la siguiente sentencia de código en
el script donde queramos:
<# Debugger.Break(); #>
Sentencias de Código:
Las sentencias de código tienen la siguiente sintaxis: <# SentenciaCodigo #>.
Estas sentencias se tienen que escribir en el lenguaje que hayamos decidido utilizar
para programarlas (por defecto C#) y han de compilarse correctamente, por lo que no
podemos cometer errores de sintaxis, como es de suponer ya que se compilaran antes de su
ejecución.
Bloques Expression:
Los bloques Expression tienen la sintaxis <#= Expression #> y sirven para añadir Strings
al código generado en función de variables y/o propiedades calculadas.
Por ejemplo, esto seria un trozo de código con una sentencia de código que no se
verá y un bloque Expression que si que se verá reflejado en el fichero de código que
generemos.
<#int result = 2*9#>
<#= result #>
Lo que hará esto será ejecutar el 2*9 mientras se encuentra el parser analizando,
compilando y ejecutando nuestro template y escribir el valor de result al fichero de
generación de código. Es decir que en el fichero generado obtendríamos "18" solamente.
Caracteres especiales en generación de código
Para que en nuestros templates de generación de código se nos generen caracteres
especiales como las comillas " o el signo menor que "<" (por ejemplo), hemos de hacer tal
y como hacíamos al programar en C/C++.Es decir con el carácter especial "\".
De esta forma, podremos hacer lo siguiente:
<# string texto = "\"Texto entre comillas"\" #>
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
192
<#= texto #>
Con lo que se nos generara: "Texto entre comillas" (con comillas incluidas) en el
fichero de salida
Crear funciones para el parser
También llamados "ClassFeatures", con su sintaxis <#+ ClassFeature #>, nos
permiten definirnos funciones para que se ejecuten en el parser antes de generar el código
y podamos hacer cambios en el mismo.
Un típico ejemplo es el de el nombre de una tabla de sql. Obviando características
especiales de SQL Server como poner los nombres entre corchetes; si hacemos "create
table Tabla 3", nos dará un error porque no sabe que el nombre de la tabla tiene un espacio.
Pues bien, podemos hacer para que o bien nos genere los corchetes ( quedando "create
table [Tabla 3]") o que nos quite el/los espacio/s en blanco (quedando "create Table
Tabla3").
Optando por la primera forma porque de paso veremos como utilizar la directiva
import y el uso de clases externas, lo que habría que hacer es lo siguiente:
1) Importar el namespace System.Text.RegularExpressions
Esto se hace añadiendo al principio del template la siguiente directiva:
3) Ahora solo falta usarlo, y se usa como cualquier función, pero desde
dentro de un bloque de sentencias de código <#...#>. Por ejemplo, este código es
válido.
<#
foreach(Table table in this.Schema.tables)
{
//Como vemos, cojemos el nombre de la tabla del diagrama
string nombreTabla = table.Name;
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
193
// Si el nombre de la columna contiene espacios en blanco, se los quito
nombreTabla = FixWhiteSpaces(nombreTabla);
#>
Create Table <#=nombreTabla#>
(
)
<#
//Cierro el bucle foreach
}
#>
Esto creara ficheros como el siguiente a partir de un diagrama con dos objetos table
que tengan nombres “Tabla 1” y “Ni NombreTa b l a” que como se puede apreciar, tienen
espacios en blanco:
Create Table Tabla1 (
)
Create Table NiNombreTabla (
)
Comentarios en los Templates
Para poner comentarios dentro de las plantillas de generación de código, es tan
simple como recordar que las Sentencias <#...#> son para delimitar código compilado en
.net y por tanto si creamos una directiva en la cual lo único que tenemos es un comentario,
esta no se vera representada en el fichero generado.
Aquí tenemos un ejemplo de comentario.
<# // Soy un comentario y no voy a verme reflejado en el fichero de salida
#>
El problema viene porque al estar en un estado temprano, el parser de DSLTools
tiene problemas con los comentarios y cree que hay Sentencias donde no las hay.
Por ejemplo:
<# /* Esto lo he comentado porque no consigo depurarlo
<#@ template debug="true" #>
<#@ import namespace="System.Diagnostics" #>
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
194
*/
#>
Aunque es sintacticamente correcto, nos da error el compilador porque el parser del
template se lía con los #> y cree que hemos cerrado la Sentencia cuando realmente tendría
que pasar de largo porque esta dentro de un comentario. Esto hace que lo que le de al
compilador de .net sea un código no valido y por eso nos saca warnings y errores.
La solución es obvia, para salir del paso le podemos decir que son caracteres
especiales; al estar dentro de un comentario no hará nada.
<# /* Esto lo he comentado porque no consigo depurarlo
<\#@ template debug="true" \#>
<\#@ import namespace="System.Diagnostics" \#>
*/
#>
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
195
Generación de código SQL Estrella
A continuación vamos a proceder con la explicación del script de generación SQL Estrella. En la parte izquierda hemos puesto una
serie de comentarios para ayudar aún más a la comprensión del mismo y hemos tenido que realizar algunas separaciones entre bloques de
código mas exageradas para que se puedan seguir los comentarios con mejor facilidad. Esto quiere decir que aunque el script que veamos sea
diferente en cuanto a tabulacion y distancia entre bloques de código y separación entre zonas de código, el script será el mismo que el que se
está usando para generar código, simplemente se ha retocado un poco para mejor comprensión.
Con esto le decimos que es un script a procesar por los objetos de transformación de texto de visual Studio; El poner la marca debug=”true” es para activar la depuración de los templates si se necesita. ---------------------------------------- Importamos los espacios de nombres que se van a usar internamente mediante sentencias <#@ import #> System.Diagnostics es necesario para poder depurar
// Ahora hago import del namespace para utilizar las colas FIFO que voy a usar para el algoritmo DFS
#>
<#@ import namespace = "System.Collections" #>
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
196
estos scripts mediante sentencias Debugger.Break(); ---------------------------------------- RegularExpressions es útil porque la clase validación utiliza expresiones regulares para la detección de caracteres extraños en el nombre de objetos de la BBDD y poder validarlos. --------------------------------------- Con la sentencia <#@ output #> lo que decimos es la extensión del archivo donde irá la salida del script que se va a procesar. ---------------------------------------- $_FICHERO_ENTRADA_$
<#
// Extension del fichero de salida que generará el template
#>
<#@ output extension=".sql" #>
<#
// Aqui es donde especificamos los archivos que va a leer este template y a partir de los cuales va a generar
// Incluimos una cabecera que muestra información para que sepamos que se trata de codigo autogenerado.
#>
<#@ include file="cabecera.comentarios" #>
<#
// Incluyo el archivo con las clases de apoyo que uso para generar código
// Las separo del bucle principal para que quede limpio
#>
<#@ include file="RecursosApoyoGeneracionCodigo.t4" #>
<#@ include file="ClaseValidacion.t4" #>
<#@ include file="ClaseTTabla.t4" #>
<#@ include file="ClaseTColumna.t4" #>
<#@ include file="ClaseTClaveAjena.t4" #>
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
197
será el fichero .oomm del diseño realizado por el usuario y del que obtendremos el código. Se obtiene al hacer clic derecho sobre el diagrama y se realiza de forma transparente al usuario. ---------------------------------------- Con la sentencia <#@ include #> hacemos que se incluya el código del fichero que se indica, como si se hubiera escrito directamente aquí. Es como una substitución de macros en c, donde cuando encuentra esta sentencia, copia todo el texto del fichero indicado en el template, para procesarlo. Los ficheros incluidos pueden ser código de salida como el caso de cabecera.comentarios, que va a ser la cabecera de los
<#@ include file="ClaseTTablaMultidimensional.t4" #>
<#
/// Declaracion de variables que se van a usar
TTabla tablaFact;
TTabla tablaDimension;
TTabla tablaDegenerateFact;
/// Especificacion del motor de Base de Datos para el que va a ir destinado el script.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
198
ficheros autogenerados, como código c#. En el caso de los ficheros .t4, es donde hemos programado la API de generación de código, que por supuesto al procesarse este template, se va a compilar con el compilador de c#2.0 ( mcs ) automáticamente, avisándonos y deteniendo el script en el caso de que el código que en ellos exista no compile. ---------------------------------------- Único lugar donde especificaremos el motor de BBDD destino. La variable
<#
// B U C L E P R I N C I P A L .
// Recuerda que para depurar has de poner un Debugger.Break();
//
foreach(Clase clase in this.Esquema.classRole)
{
if (clase is Fact)
{
Fact fact = (Fact)clase;
/// Creamos la TTabla tablaFact, generamos su clave primaria y sus columnas.
/// No podemos generar aun su sentencia create table, puesto que aun faltan las claves ajenas a las
dimensiones restantes y si lo hicieramos, el script fallaria al estar haciendo claves ajenas a tablas que
todavia no se han creado.
tablaFact = new TTabla(fact.Name,fact.GetType());
tablaFact.GenerarClavePrimaria(fact);
tablaFact.ObtenerColumnasRestantes(fact);
/// Estoy dentro de un "Fact" y voy a recorrer todas las dimensiones del "Fact"
foreach( Dimension dim in fact.dimension)
{
tablaDimension = new TTabla(dim.Name,dim.GetType());
tablaDimension.GenerarClavePrimaria(dim);
// Generamos las columnas que pertenecen a la tabla.
// Como es sql estrella, obtendremos las tablas desnormalizadas por la dimension que se le pase.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
199
$_MOTOR_BASE_DATOS_$ es tomada en tiempo de ejecución de forma transparente cuando nos pregunta si queremos generar código para SQL Server o para Oracle en el formulario que nos sale al pinchar con el botón derecho sobre el diagrama. ---------------------------------------- Comentario que muestra el comienzo del código autogenerado y nos dice el motor de base de datos para el que este script va destinado. ----------------------------------------
/// Solo si no existe un DegenerateFact entre la dimension y la clase Fact, tendran clave ajena
desde la clase Fact a la Dimension.
if (!tablaFact.ExisteDegenerateFact(dim,fact))
{
// Una vez ya tenemos la tabla Dimension guardada como una estructura TTabla, podemos
añadirla a la cola de tablas ajenas de la clase Fact
tablaFact.AddTablaAjena(tablaDimension);
}
#>
<#=tablaDimension.GenerarSentenciaCreateTable()#>
<#
} // foreach( Dimension dim in fact.dimension)
// UNA VEZ CREADAS LAS TABLAS DE LAS DIMENSIONES, AHORA FALTA LA TABLA FACT
#>
<#=tablaFact.GenerarSentenciaCreateTable()#>
--
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
200
Aquí comienza el bucle principal, que empieza recorriendo con un bucle foreach todas y cada una de las clases de tipo Fact (vemos que recorre todas las clases pero solo entra en el if para las clases de tipo Fact) ---------------------------------------- ---------------------------------------- Ahora es cuando recorremos todas las dimensiones de un Fact con este bucle foreach. ----------------------------------------
-- Ahora van las asociaciones de DegenerateFact.
--
<#
// Ahora voy a crear las tablas formadas por las DegenerateFact.
foreach(DegenerateFact df in fact.factClassAssociatesDegenerateFact)
{
tablaDegenerateFact = new TTabla(df.Name,df.GetType());
} // foreach(Clase clase in this.Esquema.classRole) <- B U C L E P R I N C I P A L
#>
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
201
Primero instanciamos la clase tablaDimension ---------------------------------------- Segundo comprobamos si hay DegenerateFact entre ella y la clase Fact, añadiéndola a la cola de tablas ajenas de la clase tablaFact ---------------------------------------- Por último, escribimos a fichero ( el .sql de salida ) el código necesario para crear la tabla de la dimensión que estamos analizando ahora. Esta tabla será de acuerdo al
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
202
código SQL Estrella por lo que será una dimensión desnormalizada. ---------------------------------------- Ahora , puesto que ya tenemos todas las sentencias de create table de las dimensiones escritas en el script, ya podemos generar la sentencia de create table de la tabla fact, que como tiene claves ajenas a las tablas dimensión, hemos de tenerlas creadas antes que la tabla fact para que no fallen las sentencias alter table…foreign key … ---------------------------------------- Para finalizar el diagrama estrella que parte de la clase Fact en la que estamos, faltan
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
203
por último las tablas que originan los DegenerateFact. Esto es así porque estas tablas tienen claves ajenas a dimensiones y a la propia clase Fact, por lo que han de ser incluidas al final del código para evitar problemas con las claves ajenas ---------------------------------------- Ahora para finalizar, ponemos un mensaje de separador de diagramas estrella, porque podemos tener varias clases fact en el mismo diagrama con lo que a continuación del primero, iría el segundo , quedando claramente diferenciados los diagramas y el código resultante mediante este separador
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
204
Generación de código SQL Snowflake
A continuación vamos a detallar mas en profundidad el template de generación de código para SQL Snowflake. Al igual que en el caso
anterior, el script es el mismo que el que esta siendo usado para generar código, solo que están mas abultadas las distancias entre bloques de
código para una mejor comprensión del template.
Dado que el API de generación de código ha sido pensado para facilitar la tarea de programación de este tipo de templates, vamos a
ver que el script es EXACTAMENTE IGUAL que el anterior, salvo que existe un if para distinguir la situación de dimensión normalizada o
no.
Con esto le decimos que es un script a procesar por los objetos de transformación de texto de visual Studio; El poner la marca debug=”true” es para activar la depuración de los templates si se necesita. ---------------------------------------- Importamos los espacios de nombres que se van a usar internamente mediante sentencias <#@ import #> System.Diagnostics es
// Este import es para poder usar la clase Regex para cambiar los nombres con espacio a sin espacio
en blanco
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
205
necesario para poder depurar estos scripts mediante sentencias Debugger.Break(); ---------------------------------------- RegularExpressions es útil porque la clase validación utiliza expresiones regulares para la detección de caracteres extraños en el nombre de objetos de la BBDD y poder validarlos. --------------------------------------- Con la sentencia <#@ output #> lo que decimos es la extensión del archivo donde irá la salida del script que se va a procesar. ----------------------------------------
// Incluimos una cabecera que muestra información para que sepamos que se trata de codigo
autogenerado.
#>
<#@ include file="cabecera.comentarios" #>
<#
// Incluyo el archivo con las clases de apoyo que uso para generar código
// Las separo del bucle principal para que quede mas limpio
#>
<#@ include file="RecursosApoyoGeneracionCodigo.t4" #>
<#@ include file="ClaseValidacion.t4" #>
<#@ include file="ClaseTTabla.t4" #>
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
206
$_FICHERO_ENTRADA_$ será el fichero .oomm del diseño realizado por el usuario y del que obtendremos el código. Se obtiene al hacer clic derecho sobre el diagrama y se realiza de forma transparente al usuario. ---------------------------------------- Con la sentencia <#@ include #> hacemos que se incluya el código del fichero que se indica, como si se hubiera escrito directamente aquí. Es como una substitución de macros en c, donde cuando encuentra esta sentencia, copia todo el texto del fichero indicado en el template, para procesarlo. Los ficheros incluidos pueden ser código de salida como el caso de cabecera.comentarios, que va a ser la cabecera de los
<#@ include file="ClaseTColumna.t4" #>
<#@ include file="ClaseTClaveAjena.t4" #>
<#@ include file="ClaseTTablaMultidimensional.t4" #>
<#
/// Declaracion de variables que se van a usar
TTabla tablaFact;
TTabla tablaDimension;
TTabla tablaDegenerateFact;
Queue tablasBase=null;
/// Especificacion del motor de Base de Datos para el que va a ir destinado el script.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
207
ficheros autogenerados, como código c#. En el caso de los ficheros .t4, es donde hemos programado la API de generación de código, que por supuesto al procesarse este template, se va a compilar con el compilador de c#2.0 ( mcs ) automáticamente, avisándonos y deteniendo el script en el caso de que el código que en ellos exista no compile. ---------------------------------------- Único lugar donde especificaremos el motor de BBDD destino. La variable $_MOTOR_BASE_DATOS_$ es
--
--
-- Script SQL Snowflake autogenerado para el Motor de Base de Datos:
/// Creamos la TTabla tablaFact, generamos su clave primaria y sus columnas.
/// No podemos generar aun su sentencia create table, puesto que aun faltan las claves
ajenas a las dimensiones restantes y si lo hicieramos, el script fallaria al estar haciendo claves
ajenas a tablas que todavia no se han creado.
tablaFact = new TTabla(fact.Name,fact.GetType());
tablaFact.GenerarClavePrimaria(fact);
tablaFact.ObtenerColumnasRestantes(fact);
/// Estoy dentro de un "Fact" y voy a recorrer todas las dimensiones del "Fact"
foreach( Dimension dim in fact.dimension)
{
tablaDimension = new TTabla(dim.Name,dim.GetType());
tablaDimension.GenerarClavePrimaria(dim);
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
208
tomada en tiempo de ejecución de forma transparente cuando nos pregunta si queremos generar código para SQL Server o para Oracle en el formulario que nos sale al pinchar con el botón derecho sobre el diagrama. ---------------------------------------- Comentario que muestra el comienzo del código autogenerado y nos dice el motor de base de datos para el que este script va destinado. ---------------------------------------- Aquí comienza el bucle principal, que empieza
///Caso de las dimensiones normalizadas
if($_CONDICION_DIMS_NORMALIZADAS_$)
{
// Generamos las columnas que pertenecen a la tabla.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
209
recorriendo con un bucle foreach todas y cada una de las clases de tipo Fact (vemos que recorre todas las clases pero solo entra en el if para las clases de tipo Fact) ---------------------------------------- ---------------------------------------- Ahora es cuando recorremos todas las dimensiones de un Fact con este bucle foreach. ---------------------------------------- Primero instanciamos la clase
// Imprimo la sentencia create table, pero sin las claves ajenas,
/// Solo si no existe un DegenerateFact entre la dimension y la clase Fact, tendran
clave ajena desde la clase Fact a la Dimension.
if (!tablaFact.ExisteDegenerateFact(dim,fact))
{
// Una vez ya tenemos la tabla Dimension guardada como una estructura TTabla,
podemos añadirla a la cola de tablas ajenas de la clase Fact
tablaFact.AddTablaAjena(tablaDimension);
}
#>
<#=tablaDimension.GenerarSentenciaCreateTable()#>
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
210
tablaDimension ---------------------------------------- Segundo comprobamos si queremos normalizar la dimensión en cuestión. Esta condición se toma en base a los formularios que se piden por pantalla cuando pinchamos en generar SQL Snowflake desde el entorno de diseño. ---------------------------------------- Si queremos normalizar la dimensión, se llama al método de Normalización de la clase TTabla que nos devuelve por un lado en tablasBase, una cola de TTablas ya rellenadas y listas para generar código con todas las tablas Base que tiene
<#
////Caso de las dimensiones normalizadas
if ( (tablasBase != null) && ($_CONDICION_DIMS_NORMALIZADAS_$))
foreach(TTabla t in tablasBase)
{
// Imprimo la sentencia create table, pero sin las claves ajenas, para que
no de error
#>
<#=t.GenerarSentenciaAlterTableForeignKey()#>
<#
} // (TTabla t in tablasBase)
} // foreach( Dimension dim in fact.dimension)
// UNA VEZ CREADAS LAS TABLAS DE LAS DIMENSIONES, AHORA FALTA LA TABLA FACT
#>
<#=tablaFact.GenerarSentenciaCreateTable()#>
--
-- Ahora van las asociaciones de DegenerateFact.
--
<#
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
211
por debajo la dimensión que estamos tratando; y por otro lado nos rellena la estructura TTabla de la instancia tablaDimension en la que estamos. ---------------------------------------- Ahora lo que vamos haciendo es recorrer todas y cada una de las TTabla de tablasBase e imprimiendo las sentencias de creación de dichas tablas al fichero de salida, pero esto se hace sin las claves ajenas para que no tengamos problemas de dependencias entre ellas puesto que aún no tenemos la tabla dimensión creada. ----------------------------------------
// Ahora voy a crear las tablas formadas por las DegenerateFact.
foreach(DegenerateFact df in fact.factClassAssociatesDegenerateFact)
{
tablaDegenerateFact = new TTabla(df.Name,df.GetType());
} // foreach(Clase clase in this.Esquema.classRole) <- B U C L E P R I N C I P A L
#>
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
212
Si por el contrario, la dimensión que estamos analizando no queremos normalizarla, llamaremos al método de desnormalizacion de la clase TTabla y obtendremos la instancia tablaDimension, como una TTabla desnormalizada y lista para imprimir a fichero. ---------------------------------------- Ahora comprobamos si hay DegenerateFact entre ella y la clase Fact, añadiéndola a la cola de tablas ajenas de la clase tablaFact ----------------------------------------
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
213
Por último, escribimos a fichero ( el .sql de salida ) el código necesario para crear la tabla de la dimensión que estamos analizando ahora. ---------------------------------------- Una vez realizado todo lo anterior solo faltan las claves ajenas de las tablas normalizadas de tablasBase en el caso de que se haya normalizado dicha dimensión ya que sino, no haría falta. ---------------------------------------- Ahora , puesto que ya tenemos
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
214
todas las sentencias de create table de las dimensiones escritas en el script, ya podemos generar la sentencia de create table de la tabla fact, que como tiene claves ajenas a las tablas dimensión, hemos de tenerlas creadas antes que la tabla fact para que no fallen las sentencias alter table…foreign key … ---------------------------------------- Para finalizar el diagrama estrella que parte de la clase Fact en la que estamos, faltan por último las tablas que originan los DegenerateFact. Esto es así porque estas tablas tienen claves ajenas a dimensiones y a la propia clase Fact, por lo que han de ser incluidas al final del código para evitar problemas con las claves ajenas
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
215
---------------------------------------- Ahora para finalizar, ponemos un mensaje de separador de diagramas estrella, porque podemos tener varias clases fact en el mismo diagrama con lo que a continuación del primero, iría el segundo , quedando claramente diferenciados los diagramas y el código resultante mediante este separador
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
216
Generación de código Oracle Warehouse Builder
Ahora es el turno de la plantilla de generación de código para Oracle Multidimensional usando Oracle Warehouse Builder. En este
caso volvemos a tener un script muy similar a los anteriores, salvo que ahora se utilizan objetos TTablaMultidimensional que internamente
funcionan específicamente para Bases de datos multidimensionales.
En este caso no vamos a volver a explicar porciones de código que ya han sido explicadas en las dos plantillas anteriores y vamos a ir
directamente a explicar los bloques de código puramente importantes de esta plantilla.
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
-- Script SQL Multidimensional autogenerado para el Motor de Base de Datos:
<#=TTabla.StringMotorBBDD#>
--
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
218
---------------------------------------- En este caso vamos a generar oracle multidimensional, es por ello que para las dimensiones vamos a utilizar TTablaMultidimensional
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
219
/// Solo si no existe un DegenerateFact entre la dimension y la clase Fact, tendran
clave ajena desde la clase Fact a la Dimension.
if (!tablaFact.ExisteDegenerateFact(dim,fact))
{
// Una vez ya tenemos la tabla Dimension guardada como una estructura TTabla,
podemos añadirla a la cola de tablas ajenas de la clase Fact
// UNA VEZ CREADAS LAS TABLAS DE LAS DIMENSIONES, AHORA FALTA LA TABLA FACT
#>
<#=tablaFact.GenerarSentenciaCreateTable()#>
--
-- Ahora van las asociaciones de DegenerateFact.
--
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
220
---------------------------------------- Aquí es donde instanciamos la tablaDimension como TTablaMultidimensional y generamos su clave primaria, que en realidad no va a obtener claves primarias, sino claves con el modificador unique ---------------------------------------- Puesto que vamos a hacer multidimensional, las dimensiones van a ser desnormalizadas y sobre ellas vamos a obtener los create dimensión ----------------------------------------
<#
// Ahora voy a crear las tablas formadas por las DegenerateFact.
foreach(DegenerateFact df in fact.factClassAssociatesDegenerateFact)
{
tablaDegenerateFact = new TTabla(df.Name,df.GetType());
} // foreach(Clase clase in this.Esquema.classRole) <- B U C L E P R I N C I P A L
#>
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
221
---------------------------------------- Ahora escribimos a fichero la sentencia de create table de la dimensión, así como su sentencia de CREATE DIMENSION. ----------------------------------------
Lenguaje de Especificación del dominio para un Modelo Multidimensional Orientado a Objetos Proyecto de fin de carrera de Enrique Catalá Bañuls y Vicente Soriano Claver
Año académico 2005-2006
222
Una vez ya tenemos todas las dimensiones generadas, generamos la sentencia create table de la tabla Fact ----------------------------------------
Lenguaje de Especificacion del dominio para un Modelo Multidimensional Orientado a Objetos
Proyecto de fin de carrera de Enrique Catala Bañuls y Vicente Soriano Claver
Año académico 2005-2006
223
Detector de palabras reservadas
La detección de palabras reservadas la hemos clasificado como una parte de la
validación de nombres de objetos en los motores de base de datos y por ello lo hemos
introducido como parte fundamental del modelo de validación. Esto quiere decir que
cuando validamos nombres de objetos mediante la clase estática “Validacion”, no solo
validamos que el nombre de objeto sea correcto, sino que validamos que no sea un nombre
de objeto reservado por el motor de base de datos, evitando así que los scripts fallen al ser
lanzados.
El proceso de detección de palabras reservadas se realiza en 2 pasos:
1. El primero se realiza en el constructor de la clase Validacion, donde
iremos leyendo el fichero de PalabrasReservadas.txt de forma que será guardado
como estructura Queue ( cola fifo ) estática para consulta en tiempo de ejecución.
2. El segundo se realiza en los métodos de ValidateStringSQLServer
o ValidateStringORACLE ( de momento solo se soportan esos dos motores )
donde realmente se consulta dicha estructura FIFO para detectar si el nombre de
objeto en cuestión es una palabra reservada y actuar en consecuencia. Esto se
realiza mediante el método Contains de la clase Queue que nos dice si un
Si quisiéramos añadir palabras reservadas de otros motores de bases de datos
distintos tendríamos que seguir estos dos únicos pasos:
1. En el primero lo único que tenemos que hacer es identificar aquellos
nombres de objetos ( palabras reservadas ) del motor de base de datos que no
podemos utilizar para definirnos nuevos objetos. Para ello no tendremos mas
remedio que irnos a los Books On Line o ayudas del motor de base de datos en
cuestión y quedarnos con los nombres de objetos reservados.
Lenguaje de Especificacion del dominio para un Modelo Multidimensional Orientado a Objetos
Proyecto de fin de carrera de Enrique Catala Bañuls y Vicente Soriano Claver
Año académico 2005-2006
224
2. En el segundo paso lo que tendremos que hacer es añadirlos al
fichero PalabrasReservadas.txt que tendremos añadido como recurso en el proyecto
ObjectOrientedMultidimensionalModel y añadir aquellas palabras en una nueva
línea.
Hemos de añadir que el fichero PalabrasReservadas.txt que podemos encontrar
como recurso dentro del proyecto ObjectOrientedMultidimensionalModel y que es la base
del proceso de detección de palabras reservadas de nuestra aplicación, detecta el 100% de
las palabras reservadas de SQL Server 2005.
Lenguaje de Especificacion del dominio para un Modelo Multidimensional Orientado a Objetos
Proyecto de fin de carrera de Enrique Catala Bañuls y Vicente Soriano Claver
Año académico 2005-2006
225
Abstracción de tipos de datos
La abstracción de tipos de datos consiste en aplicar la especificación CWM 1.1 en
la cual mediante la selección de una serie de tipos de datos simples de cara al usuario, los
tipos de datos se adapten al modelo de base de datos destino para el que se ejecutaran los
scripts. De esta forma podemos especificar tipos de datos genéricos que se adapten mejor a
la base de datos destino.
La selección de los tipos de datos se realiza desde el propio IDE del diseñador
gráfico y se exportan 2 zonas claramente diferenciadas para el diseñador.
En la primera se especifica claramente el tipo de datos que deseamos almacenar en
esa futura columna de una tabla de la Base de datos y en la otra se especificaran aquellas
restricciones inherentes a la elección, de forma que si queremos por ejemplo almacenar un
tipo decimal con 3 posiciones a la derecha de la coma, podremos hacerlo fácilmente.
De forma visual, aquí podemos ver los lugares donde especificamos dicha
información.
En un primer momento especificamos en la propiedad “dataType”, el tipo de datos
destino que queremos seleccionar entre la lista que aparece en la figura:
Donde podemos ver y en este orden:
o Booleano
o Carácter fijo ( normalmente char(x) )
o Carácter variable ( normalmente varchar(x) )
o Fechas
o Decimales
o Punto flotante
o Enteros
Lenguaje de Especificacion del dominio para un Modelo Multidimensional Orientado a Objetos
Proyecto de fin de carrera de Enrique Catala Bañuls y Vicente Soriano Claver
Año académico 2005-2006
226
o Reales
Mas tarde, y una vez seleccionado el tipo de datos que queremos, podemos añadirle
las restricciones que consideremos oportunas en la propiedad “Tam”. Hemos de destacar
que estas restricciones no son obligatorias y por tanto son solo necesarias en casos
excepcionales donde requiramos más precisión.
En este caso podemos ver como hemos optado por un tipo de datos de punto
flotante con una precisión 11,3 que queda especificada tal y como se haría en la Base de
datos destino diciendo que queremos una precisión de 11 números, 3 de los cuales van a
ser decimales.
Esta abstracción de tipos se ha realizado en las clases de tipo Attribute ( recordemos
el diseñador gráfico ) de forma que es aplicada a todas las clases que heredan de el.
Lenguaje de Especificacion del dominio para un Modelo Multidimensional Orientado a Objetos
Proyecto de fin de carrera de Enrique Catala Bañuls y Vicente Soriano Claver
Año académico 2005-2006
227
(*)Aquí podemos ver la especificación de la propiedad dataType para la clase Attribute y todas las clases que quedan afectadas por el.
DataType queda definido como un tipo de datos Enum dentro del diseñador, que ha
sido definido de la siguiente forma:
Para terminar, simplemente recordar que se hace uso de esto desde el método
BuildSQLDataType de la clase Validación, que es donde realmente se aplican los tipos de
datos específicos al motor de base de datos destino en base a este estándar.
Lenguaje de Especificacion del dominio para un Modelo Multidimensional Orientado a Objetos
Proyecto de fin de carrera de Enrique Catala Bañuls y Vicente Soriano Claver
Año académico 2005-2006
228
BIBLIOGRAFÍA
A UML Profile for Multidimensional Modeling in Data Warehouses, Sergio Lujan-Mora, Juan Trujillo del Departamento de Lenguajes y Sistemas Informáticos de la Universidad de Alicante.
Utilizado para adaptar el profile de UML a nuestro lenguaje de especificación de dominio.
Blog creado por nosotros mientras desarrollábamos la aplicación:
http://dsltools.blogspot.com
En el hemos ido plasmando durante el proceso de desarrollo del proyecto todos los problemas que nos íbamos encontrando, así como las soluciones adoptadas ante los mismos para salvarlos. Ha tenido bastante aceptación e incluso ha sido publicado en la pagina oficial de INETA-latam (Internet .NET Association – latinoamericano). Podéis acceder a través de http://www.ineta.org/Latam en la sección “nuestros blogs”, aunque nos hacen mención directa en su página principal también..
Common Warehouse Metamodel (CWM) Specification version 1.1 Volumen 1 de marzo de 2003
Esta referencia la hemos empleado para tener en cuenta el apartado referente a los tipos de datos SQL que soporta nuestro modelo. Gracias a esta especificación hemos podido definir unos tipos de datos genéricos que se adaptaran a cada tipo de sintaxis (SQL Server y Oracle en nuestro caso).
Se ha participado activamente en el foro que tienen sobre las DSL, debido aspectos en los que hemos tenido alguna dificultad, tales como el tema de los conectores bidireccionales en las referencias (http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=315160&SiteID=1) o a la hora de acceder a los conectores de las Shapes por código (http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=337873&SiteID=1).
Wiley & Sons - The Data Warehouse Toolkit. Second Edition, Ralph Kimball y Margy Ross.
Utilizado sobre todo el capitulo 1 para conceptos de modelado multidimensional.
Data Warehousing Fundamentals: A Comprehensive Guide for IT Professionals. Paulraj Ponía.
Utilizados como consulta para almacenes de datos los capítulos 10 y 11.