1. Cliente / Servidor
El concepto es el siguiente: un motor de base de datos (MS-SQLServer, Oracle, PostgreSQL,
Informix, etc) ejecutándose
en un servidor con sistema operativo de servidor (Windows NT, Windows 2000 Server, Linux,
Unix, AIX, etc).
La elección de uno u otro depende de lo robusto de la aplicación, seguridad, estabilidad, etc.
Incluso, puede utilizarse la misma base de datos de VFP en el servidor. También puede
utilizarse Access para aplicaciones más pequeñas.
Los ejemplos están preparados para Microsoft SQL Server 7.0 pero, haciendo una migración
posterior a Oracle, me di cuenta que hay muy pocas diferencias.
Yo realizo las transacciones a través de ODBC, pero sé que pueden hacerse a través de
objetos ADO. Me han dicho que es mucho mejor de esta forma, pero aún no la he investigado.
Los orígenes de datos DSN
Se supone que ya está instalada la base de datos en un servidor de la red. Lo primero que hay
que hacer es crear un DSN (Data Source Name). Es decir un "vínculo" entre la aplicación y la
base de datos. Es un nombre para identificar el origen de los datos.
Esto se hace desde el Panel de Control, en el ícono Origenes de Datos ODBC (el icono puede
cambiar según el Windows).
Allí debe elegirse el tipo de base de datos instalada (Access, MSSQLServer, Oracle, etc) y
crear un nuevo nombre de datos que será el que utilizaremos para conectar nuestra aplicación.
En el ejemplo he creado un DNS con el nombre SQLPack, tomando como base el driver de
SQL Server.
Vamos a los ejemplos
La topología cliente/servidor tiene como objetivo minimizar la cantidad de transacciones entre
la PC cliente y la base de datos en el servidor.
Nuestra aplicación debe respetar ese concepto para reducir los tiempos de respuesta, pero
sobre todo es primordial reducir el tráfico en la red, ya que podemos trabajar en una LAN
donde no habrá inconvenientes, pero también podremos hacerlo vía conexión de baja
velocidad (dial-up por ejemplo). Entonces mientras menos información viaje por la red, mejor
para todos.
Para lograr esto, las peticiones del cliente deben ser lo más exactas posible, a fin de que la
respuesta del servidor sea lo más concreta que se pueda.
El lenguaje SQL
Toda la comunicación con la base de datos, se hace a través de un lenguaje conocido como
SQL (Structured Query Language). Este puede variar un poco entre las distintas base de datos,
pero los comando básicos son 4 y son los que utilizaremos para los ejemplos: seleccionar,
insertar, actualizar y eliminar.
La conexión
El primer paso para “hablar” con el motor es crear una conexión. Esta es como un cable que
nos permite acceder a toda la información disponible en la base de datos.
El comando para crear la conexión es:
nHndl = SQLCONNECT([DataSourceName, cUserID, cPassword)
nHndl es el número de conexión con la base de datos (puede existir más de una). Identifica
unívocamente a la conexión y es siempre >0 si la conexión fue exitosa.
2. En caso de error durante el proceso de conexión, tendrá un valor negativo.
DataSourceName: nombre del origen de datos con el que creamos a través del Panel de
Control.
cUserID: nombre del usuario con el que se creó el DSN.
cPassword: clave de acceso del usuario.
En nuestro ejemplo sería:
m.cnx = SQLCONNECT(“SQLPack”, “conexión”, “cnxpwd”)
IF m.cnx < 1
=MESSAGEBOX(“Error de conexión”, 16, “Error”)
RETURN
ENDIF
Ej. 1
La idea es tener una conexión única a la base de datos, que pueda ser compartida por todos
los usuarios.
Yo no generé una conexión por cada nombre de usuario, sino que a través de esta única, una
vez dentro controlo por programa si el usuario está habilitado, si coinciden las claves de
ingreso, los niveles de acceso, etc.
Entonces, podremos tener un formulario de ingreso más o menos así:
Imagen 1
En el método “Click” del botón “Conectar con la Base de Datos”, deberíamos incluir el código
de conexión.
Si la conexión fue exitosa, el próximo paso es verificar los datos introducidos en los campos
Usuario y Contraseña.
Para ello utilizaremos el identificador de conexión que nos devolvió el comando SQLCONNECT
y que se encuentra en la variable m.cnx.
m.hndl=SQLEXEC(m.cnx,'SELECT username, nombre, clave;
FROM usuarios,
WHERE username= ?Thisform.Text1.Value',
'cu_usuarios')
Ej. 2
3. El comando ejecutado es el SQLEXEC, cuya sintaxis es la siguiente:
SQLEXEC(nConnectionHandle, [cSQLCommand, [cCursorName]])
nConnectionHandle es el número de conexión devuelto por SQLCONNECT. En nuestro
ejemplo, se encuentra en la variable m.cnx.
cSQLCommand es el comando SQL que enviamos al servidor.
cCursorName este campo no es obligatorio, pero lo utilizo para alojar el resultado de la petición
en un cursor local y luego usarlo como cualquier tabla Fox.
Veamos por partes el Ejemplo 2:
Aparece una nueva variable llamada m.hndl donde se almacenará el resultado del comando. Si
es < 1 el comando falló y deberá controlarse a través de alguna rutina de error desde el VFP.
m.cnx es la variable que contiene la identificación de la conexión con la base de datos.
Con el comando SQL solicitamos que nos devuelva un set de resultados con los registros de la
base de datos que cumplen con la condición de la cláusula WHERE.
Es decir, seleccionamos aquellos usuarios, su nombre y clave cuyo nombre de usuario sea
igual al ingresado en el campo Text1 del formulario. El resultado (sólo un registro) quedará en
un cursor (tabla temporaria) llamado cu_usuarios.
Nótese que a los nombres de las variables debe anteponerse el signo ? dentro de la sentencia
SQL.
El comando SQLEXEC es el que se utiliza para enviar peticiones al servidor y lo utilizaremos
para todas las funciones de acceso a base de datos. Hay formas de programación más
avanzadas que permiten generar una sentencia SQL, compilarla y alojarla en el servidor para
ejecutarla cuando se necesite, ganando tiempo en la ejecución. Pero, por ahora, para tener los
fundamentos básicos y lograr una aplicación cliente/servidor que funciones muy bien, con estos
comandos basta y sobra.
Como decíamos con SQLEXEC podemos seleccionar datos, tal como vimos en el ejemplo
anterior, pero también podemos insertar nuevos registros en la base de datos:
m.hndl = SQLEXEC(m.cnx, “INSERT INTO usuarios;
VALUES (?m.username, ?m.nombre, ?m.clave)”)
Ej. 3
Nuevamente, el resultado de la transacción lo almacenamos en una variable de control llamada
m.hndl y si su valor es < 1 indica que la operación ha fallado.
En este ejemplo insertamos en la tabla usuarios un registro con el contenido de las variables de
memoria m.username, m.nombre y m.clave.
Los registros existentes en una tabla de base de datos pueden ser modificados mediante el
comando UPDATE.
m.hndl = SQLEXEC(m.cnx, “UPDATE usuarios;
SET clave = ?m.clave;
WHERE username = ?m.username”)
Ej. 4
Este ejemplo nos muestra cómo modificar un registro de la tabla usuarios, cambiando el valor
del campo clave solamente para aquel que cumpla con la condición (WHERE) de que el
nombre de usuario username sea igual al de la variable m.username.
Obviamente, también podremos eliminar uno o más registros que cumplan con una condición
dada. El comando para esto es DELETE.
4. m.hndl = SQLEXEC(m.cnx, “DELETE FROM usuarios ;
WHERE username = ?m.username”)
Ej. 5
Para finalizar una conexión con la base de datos, debemos cerrar la que está actualmente
activa. Esto se realiza con el comando SQLDISCONNECT.
m.hndl = SQLDISCONNECT(m.cnx)
Ej. 6
Si colocamos como parámetro el número 0, cerrará todas las conexiones activas. Por ej.:
m.hndl = SQLDISCONNECT(0)
Existen otros comandos relacionados con las propiedades de la conexión que pueden ser
modificados, pero sólo los mencionaré ya que dependen de cada instalación para hacer el
“ajuste fino”.
SQLSETPROP: especifica los parámetros para una conexión.
SQLGETPROP: permite conocer los parámetros de una conexión activa.
SQLCOMMIT: “baja” la transacción al disco, es decir copia las modificaciones efectivamente en
la base de datos. Debe estar ajustado el parámetro de Transacción en Manual.
SQLROLLBACK: cancela cualquier cambio realizado en la última transacción. Para ello
deberá estar ajustado el parámetro de Transacción Manual (con SQLSETPROP).
Si el parámetro de Transacción está en automático, estos dos últimos comandos no se utilizan
y cada transacción efectuada será reflejada inmediatamente en la base de datos.
La ayuda de Visual Fox, es muy clara en cuanto a estos comandos y otros más relacionados
con las operaciones C/S. Lo que falta es verlo en forma efectiva en ejemplos.
Para ello, adjunto un ejemplo para ver como aplicar lo visto en estas páginas.
Espero les sirva a todos.
Un saludo desde Mendoza, Argentina.
Alejandro Beorlegui
abeorlegui@sinectis.com.ar