<-- Capítulo

Indice del tutor de Delphi
© Copyright 1998
por David Martínez.

Todos los derechos reservados

Capítulo -->

Capítulo 6. Escribiendo una Aplicación de Base de Datos

En este capítulo escribiremos una aplicacion pequeña de base de datos. Como necesitamos asegurar que todos tengamos los mismos datos, comenzaremos por utilizar los datos que vienen con Delphi, en el alias DbDemos.

Nota: En este ejemplo, aunque estamos utilizando el alias DbDemos (que es un directorio con tablas de dBase), estoy programando como si estuvieramos desarrollando para un servidor SQL (dBase, Paradox, etc). Con esto, mi intención es convencerlo de que: 1. Usted puede (y en mi opinion debería) programar en SQL local para hacer más fácil la migración posterior a bases de datos SQL, y 2. Si usted comprende como funciona Delphi en programación con un TQuery, la programación usando un TTable es sencilla y trivial. Además, usted estará listo más rápido para programación en SQL, y un desarrollador de Cliente/Servidor es mejor pagado que uno de "tablas". El saber y entender SQL es, hoy por hoy, una de las mayores ventajas para un desarrollador, ya que cualquier paquete de base de datos entiende al menos una "especie" de SQL. Si usted quiere usar una versión poderosa de SQL para saber cómo es programar para ella, Delphi Professional y Client/Server cuentan con una versión de desarrollo de Interbase. Pero antes de desarrollar sobre Interbase, asegúrese de entender el contrato de licencia, donde Interbase se cobra "por asiento", como Oracle, Ms SQL Server o Progress. Pero usarlo para aprender SQL es gratis.

Accesando Datos en Delphi

Delphi utiliza una librería llamada BDE (Borland Database Engine) para su acceso a bases de datos. El acceso de datos en Delphi es muy diferente, pero análogo, al acceso de datos en lenguajes como Clipper, Foxpro y dBase. En estos lenguajes, usted tiene "áreas" de trabajo. Dentro de esas areas usted puede tener abierta una tabla, y le puede decir a esa tabla que vaya al principio, al final, o brinque o retroceda. Bueno, en principio, en Delphi puede usted hacer lo mismo:

En Clipper (area) En Delphi (dataset)
GO TOP Dataset.First;
GO BOTTOM Dataset.Last;
Skip Dataset.Next;
Skip -1 Dataset.Prior;

En Delphi usted puede tener un sinnúmero de estas "areas", pero como en Delphi todo es un objeto, obviamente tienen su nombre. Las clases que representan sets de datos navegables (datasets) son llamadas "TDataset".

Nota: Me refiero a "sets de datos navegables" en lugar de especificar tablas o áreas de trabajo. ¿Porqué es esto? Un set de datos navegable en Delphi puede representar virtualmente cualquier cosa. Delphi tiene una clase llamada TCustomDataset, que implementa los conceptos básicos de la navegación de datos (First, Next, Last, etc). Bajo esta clase, customBDEDataset está implementado. Esto es un set de datos abstracto que utiliza el BDE. Una vez implementado BDEDataset, todos los sets de datos (TQuery, TTable) están implementados bajo el mismo. ¿Porqué tanta complicación? ¿Porqué no simplemente hacer acceso de datos directamente? Delphi tiene como concepto básico la implementación de clases y programación por objetos. El uso de estas clases intermedias garantiza que usted puede hacer acceso a datos sin utilizar el BDE, por ejemplo (utilizando CustomDataset en vez de CustomBDEDataset). De hecho, usted puede manejar el acceso de datos de una manera totalmente diferente mientras Delphi cree que está utilizando los mismos datasets. El cambio en su programa se vuelve mínimo.

Vamos a entrar en materia y comenzar nuestra primera aplicación de base de datos. Utilizaremos los datos que vienen con Delphi, ya que son los que nos aseguran que todos veamos las mismas pantallas. Más adelante veremos otros tipos.

Con Delphi recién abierto, busque en la paleta y ponga los siguientes componentes en su forma, ya sea utilizando doble-click (que pone los componentes automáticamente) o haciendo click en uno de los componentes y haciendo click donde lo quiera ver en la forma. Para cambiarle de nombre, seleccione "name" en el object inspector y escriba el nombre nuevo.

De la página.. Inserte el componente... Y Cambie las propiedades:
Data Access TQuery Name: "qryClientes"
Data Access TDataSource Name: "dsClientes"
Data Controls TDBNavigator Name: "dbnNavegador"

Los componentes Query y DataSource que acabamos de insertar representan las partes "no visuales" del acceso a base de datos. TQuery es una representación de un Query de SQL, mientras que TDataSource nos permite conectar controles "data aware" a su aplicación. Si todo esto suena un tanto confuso no se preocupe, se volverá muy claro cuando el programa esté corriendo.

Estándares, comentarios y notación.- Como programador profesional, tarde o temprano se dará cuenta de que las "convenciónes de código" (los estándares que usted utiliza para nombrar sus objetos, indentar y estilo en general) es muy importante. Aunque esta convención es algo que es un tanto personal, es importante tener en cuenta que es importante tener una. Cualquier programador veterano te dirá que aunque la convención sea muy diferente, es más fácil leer el código de alguien que tiene una (aunque sea muy diferente a la nuestra) que el de alguien que no tiene ninguna. Así que aquí van dos de mis primeros estándares de programación: Primero, SIEMPRE póngale nombre a todo. Cualquier control que ponga en la forma debe tener un nombre puesto por usted, no por Windows o Delphi. Eso hace su programa mucho más legible cuando regresa después de un año y necesita saber que hacía su programa.

¿Como nombrar sus objetos y variables? La mayoría de los programadores utilizan una de las miles de variaciones de la "notación húngara", creada por Charles Simonyi en Microsoft. La notación húngara especifica un prefijo que nos dice qué a clase de objeto o variable el nombre se refiere, y después el nombre, primero mayúscula y después minúsculas. Lo más usual es usar "i" para Integer, "b" para Boolean (lógico), "s" para string o "c" para caracter, etcétera. Yo utilizo ciertas extensiones para especificar objetos de Delphi como "qry" para Query, "ds" para DataSource, o "dbn" para DBNavigator. Esto hace el código más legible y fácil de seguir.

También es muy importante poner comentarios en el código. No existe programa con demasiados comentarios, así que explique todo lo que Ud. quiera. Mientras escribe, imagíne que usted es un maestro que quiere enseñar el código a sus alumnos para algún ejercicio.

Ahora, héchele una ojeada a su código. Delphi ha insertado declaraciones dentro de su declaración de la forma especificando el nombre de la variable y el tipo de objeto que representa:

  TForm1 = class(TForm)
    qryClientes: TQuery;
    dsClientes: TDataSource;
    dbnNavegador: TDBNavigator;
  private
    { Private declarations }
  public
    { Public declarations }
  end;

Ahora, vaya al TQuery y cambie la propiedad "Databasename" a DBDemos. Lo puede escribir textualmente o seleccionarlo de la lista. DBDemos es un alias local que apunta a su directorio de Demos de Delphi. Lo puede ver utilizando el programa BDE Administrator que viene con Delphi. Ya que tenga especificado el contenedor de base de datos que desee usar por medio del alias, puede usted lanzar comandos de base de datos a cualquier tabla que se encuentre dentro del contenedor. Si usted en esta propiedad especifica un alias que esté configurado a una base de datos SQL, entonces Delphi hará una conexión a la base de datos y mostrará la caja de "login" para que usted escriba su nombre de usuario y clave de acceso en la base de datos.

Ahora seleccione el TDatasource. En la propiedad Dataset, seleccione qryClientes. Tal como en el párrafo anterior, puede seleccionarlo de la lista. Esto quiere decir que, la "fuente" de los datos va a tomar la información del set de datos qryClientes. Finalmente, en la propiedad DataSource de su TDBNavigator, seleccione dsClients. De inmediato podrá notar que los botones del navegador se desactivan, volviéndose grises y opacos. Esto es porque los componentes "data-aware" de Delphi son dinámicos, es decir, se comportan en modo de diseño tal como se comportarán en modo de ejecución. Como su Query está vacío y cerrado, el navegador está desactivado.

El TDbNavigator se desactiva cuando el query está cerrado.

¿Como le hacemos para que se active el Query? Lo que vamos a hacer es aprovechar al máximo las capacidades de diseño de Delphi. Primero, necesitamos hacer un Query en SQL que Delphi pueda utilizar en el alias DbDemos para que Delphi sepa la información de la tabla que podemos utilizar para diseñar.

Seleccione el Query, y haga doble-click en su propiedad "SQL". A continuación verá el "Editor de listas de textos" (String List Editor). Este editor es un editor de textos muy simple y chiquito que simplemente permite escribir más de una línea de texto a la vez. Escriba lo siguiente y después presione OK

SELECT * FROM "CLIENTS.DBF" CLIENTES
WHERE CLIENTES.ACCT_NBR = :Cuenta

La palabra ":Cuenta" le dice a Delphi que este query necesitará un parámetro llamado Cuenta, para el número de cuenta. Ahora, haga Doble-click en la propiedad "Params" del Query. Seleccione tipo de datos Integer y valor 1023495 por ahora. Después le daremos al usuario oportunidad de cambiarlo.

Asegúrese de que el número de cuenta sea el correcto (consulte la tabla usando Database Explorer si tiene dudas) para que su query devuelva un registro. Si su query no devuelve nada, todavía podrá diseñar (Delphi devuelve la información de los campos sin registros), pero no verá el registro en tiempo de diseño.

El diseñar especificando siempre un número de cuenta (o la "clave primaria") es algo que SIEMPRE debemos de hacer en ambientes SQL, a menos que estemos SEGUROS de que la tabla está vacía o no tiene muchos registros. Delphi ejecutará este SQL cuando activemos el query para elegir campos, preparar relaciones o cualquier cosa. Aunque Delphi nunca abre un query dos veces si no es necesario, si usted no pone una sentencia WHERE en una base de datos grande, tendrá que esperar a que el SELECT completo ejecute antes de continuar con su diseño. Tenga esto en mente cada vez que haga un Select sin WHERE, ya sea en diseño o en tiempo de ejecución.

A continuación, vaya a la propiedad "RequestLive" de su Query y póngala en "True". Esto es importante porque SQL siempre devuelve resultados "Read-Only", o "muertos" (dead) a menos que especifiquemos que nuestro query debe ser "vivo" (live). Esto querría decir que nuestro usuario no podría editar el registro! Hay otras condiciones que podrían no permitirnos el recibir un query "vivo", pero las veremos más adelante. Cualquier manual de SQL le explicará qué clase de queries pueden ser modificados y cuales no.

Ahora lo que queremos hacer es diseñar usando todas las ayudas de Delphi, así que, con el Query todavía cerrado, haga doble-click en el query. A continuación verá una ventana vacía que dice Form1.qryClientes. Ésta es la lista de registros existentes en el resultado de nuestro query "Clientes". Presione Control-A (o haga click con el boton derecho del mouse y seleccione "Add Fields"). Delphi ejecuta el Query internamente y nos proporciona la lista de las "columnas" (campos) del resultado del Query. Todos los campos están preseleccionados (Delphi asume que usted quiere añadir todos los campos a la forma). Así que simplemente presione {Enter} para aceptar el añadir todos los campos a su definición.

La información que Delphi recupera para saber la estructura del archivo se llama Metadata. Esto quiere decir a groso modo "datos acerca de los datos"; es decir, la estructura física de la información resultante del Query. Para extraer el Metadata, Delphi ejecuta el SQL en su Query y extrae la información a partir de los datos recibidos. Si el query no devuelve nada, pero es sintacticamente correcto, Delphi también recibe el metadata, pero sin registros.

Ahora usted tiene una definicion de campos como parte de la definición de su forma. Puede usted comenzar a diseñar. Cuando usted selecciona uno de los campos, el Object Inspector muestra las propiedades de los campos. Mientras no cambie propiedades importantes como Largo y Nombre del campo, puede usted cambiar la apariencia, el "display name", y el formato de edición (Edit Mask) del campo en tiempo de diseño. Por ejemplo, seleccione el campo Last_Name y trate de cambiar su "DisplayName a "Apellido". El nombre del campo para efectos de diseño sigue siendo el mismo, pero ahora desplegará "Apellido" en el TLabel cuando lo pongamos en la forma. Además, programáticamente, el objeto qryClientesLAST_NAME, de tipo TStringField, tiene como propiedad "DisplayName" el texto "Apellido". Esto será útil para hacer mensajes de error para nuestros usuarios...

Nota: Aunque es muy bonito el poder hacer esto en tiempo de diseño, el atar su forma a los datos de esta manera quiere decir que, cuando usted cambie los nombres, añada o cambie el tamaño de las columnas de su tabla, deberá volver a esta forma y hacer que los cambios se reflejen correctamente. El diseñar visualmente de esta manera, aunque conveniente, "ata" su diseño al formato de la tabla. Más tarde veremos maneras de evitar esto hasta cierto punto (pero todo tiene su precio).

Cambie la propiedad "DisplayName" en todos sus campos y ponga títulos convenientes en cada uno de ellos (¡y por favor en Español, Chihuahua!)... Una vez que termine de "amasar sus datos", estará usted listo para diseñar...

Para diseñar su forma, simplemente "jale" cada uno de los campos con el mouse, desde la lista de campos "Form1.qryClientes", hasta la forma, en el orden que desee que el usuario los escriba, y en la posición deseada en la forma. Cuando "suelte" cada campo, Delphi creará un componente TLabel y un DbEdit por usted, listos para recibir los datos adecuados.

Delphi es versatil también. Examine las propiedades de los "DbEdit"s que ha estado soltando en la forma. Para hacer esto manualmente, usted seleccionaría un dbEdit de "Data Controls", lo pondría en la forma, y manipularía sus propiedades "DataSource" y "DataField" para mencionar el DataSource en su forma y el campo deseado, respectivamente. No hay "gran misterio" en cuanto a la manera en que Delphi lo está ayudando a programar. Como dicen por ahí los "Borlanderos": Delphi está escrito en Delphi. A continuación presento un ejemplo de la manera en que probablemente se ve su forma:

"Dijimos que Delphi nos permitía diseñar visualmente.... ¿Donde están los datos?" Ah, pues es muy sencillo: Nuestro Query todavía no está abierto. Aunque Delphi lo ejecutó para averiguar la lista de campos necesarios para el diseño, nuestro query, para propósitos prácticos, está cerrado. Vamos a abrirlo y veamos que obtenemos:

Nuestros campos han sido activados. El dbNavigator ya nos dá algunas opciones. Pues sí, esa es la cuenta que especificamos en los parámetros... Y fijate, la Señorita Davis es una muchacha muy guapa, de Wellesley, Massachusets. Y es programadora, además... Con esa sonrisa, seguro programa en Delphi.

Si usted quiere, puede correr ahora mismo su programa y hacer cambios, pero solo a ese registro (porque nuestro query especifica un registro únicamente). Si Delphi no le permite editar mientras ejecuta, asegúrese de que su Query tiene el RequestLive en "True".

Ahora que sabemos como se hacen las cosas, para experimentar un rato vaya al SQL en su Query y elimine la sección "WHERE" de la sentencia SELECT. Su SQL quedará como SELECT * FROM "CLIENTS.DBF" CLIENTES

Recordando todas las precauciones que vimos al principio de nuestro capítulo, sabemos que esta tabla en particular sólo tiene cinco registros, así que el tiempo de espera del select no será catastrófico (pero recuerde lo que dije antes; más tarde veremos varias técnicas para manejar esto). Después, abra su query de nuevo (cambie la propiedad "Active" del Query a "True", y ejecute el programa.

Felicidades! Tiene su primer programa de acceso de datos de Delphi. Todavía no hemos escrito una palabra en Pascal, pero funciona muy bien! El Navegador (La barra de botones de la parte superior) le permite editar, grabar, cancelar, refrescar los datos y moverse entre los registros. Todos sus registros funcionan, y usted puede comenzar a editar y añadir registros al archivo de Clientes de inmediato.

Finalmente, grabe su ejemplo; lo utilizaremos en otros capítulos para no tener que comenzar de nuevo cada vez. Cuando le pregunte el nombre de "unit1", teclee forma_clientes. Cuando le pregunte el nombre para el proyecto, teclee "ManejodeClientes".

En los siguientes subcapítulos de la sección "base de datos", aprenderemos mucho acerca de las muy diversas maneras en que podemos desarrollar aplicaciones de manejo de datos usando Delphi. Además nos quitaremos de algunos de los "vicios" que tuve a bien introducir en este capítulo para hacerlo más sencillo y obtener resultados más rápido, como el mantener las tablas abiertas en modo de diseño, usar SQL sin sentencias WHERE, etcétera. Siendo Delphi tan poderoso como lo es para el manejo de bases de datos, es dificil abarcar todo. Pero al menos les daré una "probadita" de varias de las capacidades de Delphi en cuanto al manejo de información, que son muchas. A partir de ese punto, usted tendrá las herramientas suficientes para experimentar y extender sus conocimientos.

Por ahora, dése unas palmaditas en la espalda, porque ya terminó una de las secciones más largas de el curso! Ha usted hecho bastante, y todavía ni siquiera hablamos del lenguaje en sí, un área fascinante que veremos más a fondo mientras viajamos por los ejemplos...

Capitulo -->