Introducción al Modelo de Datos (I)
Llevo tiempo pensando en lo útil que resultaría contar con un modelo de datos cómodo que permita facilitar la labor de programación y posterior mantenimiento de nuestras aplicaciones. Coincido con mucha gente que la construcción de un modelo de datos es una tarea pesada que requiere mucha abstracción mental y escribir mucho código, pero también he de admitir que un modelo de datos bien construido ahorra muchas horas de trabajo.
He dividido el artículo en dos para hacerlo menos pesado, aunque al terminar este creo que todos los lectores sabrán por donde van los tiros y que va a pasar en la segunda parte.
Todo el código que pongo aquí está escrito con el único objetivo de ejemplificar un modelo de datos y, desde luego, puede ser mejorado; he suprimido a propósito controles de errores y otras cosas a fin de que se vea claramente como funcionan las clases que lo componen.
El ejemplo que vamos a usar para construir nuestro modelo de datos es una sencilla facturación:
- Tabla de familias de artículos (id, nombre)
- Tabla de artículos ( Id, Id_familia, nombre, pvp )
- Tabla de clientes( Id, nombre, domicilio, telefono )
- Tabla de cabecera de facturas ( Id, fecha, Id_cliente, iva )
- Tabla de lineas de facturas ( Id_factura, linea, Id_articulo, cantidad, precio )
Comencemos por identificas las clases que van a constituir nuestro modelo de datos:
- Clase TFamilia
- Clase TArticulo
- Clase TCliente
- Clase TFactura
- Clase TLineasFactura
Para el código de los ejemplos usaré xHarbour y Xailer. Todas las clases heredarán de una clase principal y abstracta llamanda TQuery, que es una clase que simula un datasource. La clase TQuery está programada por mí basándome el los wrappers que construyó Manu Expósito en Eagle 1 para acceder de forma nativa a MySQL. Creo que no existen problemas para poder heredar del sistema de datasource de cualquier otro producto. Quien lo desee puede contactarme para que le envíe el código fuente de TQuery.
Las primeras clases que vamos a definir son las relacionadas con las tablas maestras, empezando por las que no contienen referencias a claves foráneas de otras tablas, en nuestro caso, las clases TFamilia y TCliente.
CLASS TFamilia FROM Tquery
DATA cConsulta
METHOD Init( cQuery )
METHOD Delete( nId_Familia )
END CLASS
METHOD Init( cQuery ) CLASS TFamilia
DEFAULT cQuery TO “SELECT * FROM famila”
::New()
::cConsulta := cQuery
::Query( ::cConsulta )
RETURN Self
METHOD Delete( nId_Familia ) CLASS TFamilia
IF !Empty( nId_Familia )
::Command( “DELETE FROM familia “ + ;
“WHERE id = “ + Str( nId_Familia ) + “ “ + ;
“LIMIT 1” )
END IF
RETURN Nil
//——————————————————————//
CLASS TCliente FROM Tquery
DATA cConsulta
METHOD Init( cQuery )
METHOD Delete( nId_Cliente )
END CLASS
METHOD Init( cQuery ) CLASS TCliente
DEFAULT cQuery TO “SELECT * FROM cliente”
::New()
::cConsulta := cQuery
::Query( ::cConsulta )
RETURN Self
METHOD Delete( nId_Cliente ) CLASS TCliente
IF !Empty( nId_Cliente)
::Command( “DELETE FROM cliente “ + ;
“WHERE id = “ + Str( nId_Cliente ) + “ “ + ;
“LIMIT 1” )
END IF
RETURN Nil
//——————————————————————//
Constituiremos ahora la clase para controlar la tabla de artículos, que como podemos observar, contiene una clave foránea a la tabla de familias (Id_familia); por lo tanto, desde nuestro modelo de datos, un objeto oArtículo de la clase TArtículo tendrá que poder acceder a los datos de la familia de cada artículo, facilitando posteriormente las labores de programación de nuestra aplicación.
CLASS TArticulo FROM TQuery
DATA cConsulta
DATA oFam
METHOD Init( cQuery )
METHOD Delete( nId_Articulo )
METHOD Change( oSender )
ACCESS oFamilia
END CLASS
METHOD Init( cQuery ) CLASS TArticulo
DEFAULT cQuery TO “SELECT * FROM articulo”
::New()
::OnChange := { | oSender | Change( oSender ) }
::cConsulta := cQuery
::Query( ::cConsulta )
RETURN Self
METHOD Delete( nId_Articulo ) CLASS TArticulo
IF !Empty( nId_Articulo)
::Command( “DELETE FROM articulo “ + ;
“WHERE id = “ + Str( nId_Articulo ) + “ “ + ;
“LIMIT 1” )
::Change()
END IF
RETURN Nil
METHOD Change( oSender ) CLASS TArticulo
::oFam := NIL
RETURN Nil
METHOD oFamilia CLASS TArticulo
IF Empty( ::oFam )
::oFam := Tfamilia():Init( “SELECT * FROM familia “ + ;
“WHERE id = “ + Str( ::Id_Familia ) )
END IF
RETURN ::oFam
Vamos a detenernos un instante a estudiar que tienen estas clases dentro. De forma general, todas las clases llevan una DATA que contiene la consulta efectuada (cConsulta) y los MÉTODOS Init() y Delete().
El método Init() es el encargado de construir y retornar el objeto correspondiente. En su interior nos encontramos instrucciones que, a parte de establecer un valor por defecto para la consulta, también realizan:
-
Llamar al método New() de la superclase para la construcción del objeto.
-
Llamar al método Query() de la superclase para ejecutar la consulta y cargar los datos correspondientes.
El método Delete() es el encargado de eliminar una fila de la tabla correspondiente. En caso de usar bases de datos SQL recomiendo tener bien definida la integridad referencial. En otro tipo de almacenes de datos, en este método habrá que incluir el código necesario para eliminar información de las tablas que contengan información de la fila que estamos eliminando.
Estudiando la clase TArticulo podemos observar algunas diferencias muy significativas: aparece una DATA aFam, el método Change() y el método especial ACCESS oFamilia.
Mediante la palabra reservasa ACCESS de xHarbour se define un método especial que se comportará como una DATA y que además ejecuta su código cada vez que se instancia.
La DATA oFam contendrá un objeto de la clase TFamilia descrita anteriormente.
El método Change() se ejecutará cada vez que dispare el evento OnChange() de la clase TQuery. Este evento responde cada vez que se produce un cambio al añadir, actualizar, borrar, navegar o recargar datos de la consulta. Este método pone a NIL la data oFam para controlar un tipo de recursividad que veremos más adelante.
El método ACCESS oFamilia se ejecutará cada vez que accedamos a él, ejecutando la consulta que carga los datos de la familia relacionada con el artículo actual. Para evitar la recursividad y que se ejecuten consultas constantes (perdida de velocidad :-(), miramos si está vacío.
Con lo visto hasta este momento creo que ya habréis podido adivinar que el modelo de datos perimite acceder de forma automática a los datos de tablas relacionadas sin necesidad de escribir código adicional. Comparemos:
-
Forma tradicional sin modelo de datos:
oArticulo := TQuery():New( “SELECT * FROM articulo” )
WHILE !oArticulo:Eof()
oFamilia := Tquery():New( “SELECT * FROM familia “ + ;
“WHERE id = “ + Str( oArticulo:Id_Familia ) )
MsgInfo( oFamilia:Nombre )
oArticulo:Skip()
END DO
-
Usando el modelo de datos:
oArticulo := TArticulo():New( “SELECT * FROM articulo” )
WHILE !oArticulo:Eof()
MsgInfo( oArticulo:oFamilia:Nombre )
oArticulo:Skip()
END DO
Es obvio que usando un modelo de datos conseguimos claridad y automatización en la mayoría de los procesos que tenemos que realizar dentro de nuestros programas.
En la segunda parte de este artículo veremos como se automatiza la clase Tfactura.
Tags: automatizacion, clases, datasource, modelo de datos, objetos, tquery
October 17th, 2008 at 09:38
Gracias por el aporte Jose A.!
October 17th, 2008 at 23:02
Hola Rafa,
Espero te haya gustado, que se que a tí te gustan estas cosas.
Si me da tiempo prepararlo, espero publicar la segunda parte este fin de semana.
Saludos,
Alf+.
October 18th, 2008 at 09:50
Hola Jose Alfonso,
Saludos desde Cádiz. Espero que te vaya bien por tu cuenta y que tpvsoft siga funcionando como mereces.
October 19th, 2008 at 12:53
Jose…
Muy bueno, espero las siguientes entregas con auténtica ansiedad…
Saludos
March 22nd, 2010 at 15:12
Interesante artículo. Hace poco que estoy en Xailer y me interesaría leer la clase TQuery que comentás. Si pudieses hacermela conocer estaría muy agradecido.
May 27th, 2010 at 20:54
Me encontre con tu archiculo de MVC y me parecio muy interesante yo actualmente trabajo con oohg + harbour y al igual que todos estoy interasado en que me facilites el codigo de la clase TQuery para poner en practica el modelo MVC. Te antemano de agradezco tu colaboracion y ayuda.