Professional Documents
Culture Documents
13
Acceso a Bases de Datos remotas mediante el motor Jet
ODBCDirect
Acceso a Bases de Datos remotas mediante objetos RDO
Hasta ahora todos los accesos realizados a una base de datos los hemos realizado
directamente a través del Motor de bases de Datos Microsoft JET. Este motor de bases de
datos abre, lee y graba el fichero .MDB (o el dBase, FoxPro, Paradox, etc.) de la misma forma
que un editor de textos puede abrir, leer o escribir un fichero creado por el mismo o por otros
editores conocidos.
Las bases de datos (las buenas) tienen unas herramientas comunes para manejarlas. Estas
herramientas son, por una parte el lenguaje SQL que puede dar instrucciones para leer o
escribir una base abierta, mediante un lenguaje común para todas las bases, y por otra, la
herramienta que abre esa base de datos y nos hace verla, desde el exterior, bajo una forma
única para todas las bases: el ODBC.
El ODBC es una herramienta que nos permite ver a todas las bases de una forma única. No es
un lenguaje común a todas las Bases de datos. Ese es el SQL. Es la interface que adapta a
una base de datos para que nos podamos entender con ella en SQL. Por lo tanto es fácil
pensar que esa interface deberá fabricarla el mismo fabricante que ha realizado la base de
datos. El lenguaje SQL es conocido por todo el mundo, pero la forma interna de trabajar una
base de datos solamente la conoce su fabricante. Por eso, el Driver ODBC que es el que nos
permite adaptar las particularidades de esa base de datos al lenguaje común, deberá
suministrarlo el fabricante de la base.
Microsoft desarrolló varios drivers para otras tantas bases de datos y hojas de cálculo. Entre
ellas para Access y Excel, dBase y FoxPro. También lo desarrolló para bases de datos tan
populares como Oracle. Ese driver hay que instalarlo en el ordenador, aunque Windows instala
algunos por defecto.
Veamos ahora otro elemento fundamental para el trabajo con ODBC: la conexión. La conexión
ODBC es el conjunto de datos que hay que aportarle a Windows para que pueda enlazar
nuestra aplicación con la base de datos. Estos datos son, al menos:
La conexión ODBC no la realiza Visual Basic. La realizará Windows. Veamos como podemos
establecerla.
Vaya a Inicio | Configuración | Panel de Control | ODBC de 32 Bits. Haga doble click y le
aparecerá un cuadro como el de la figura 13-1. En este cuadro figuran todos los enlaces que
están establecidos. Estos enlaces puede establecerlos para un usuario (DSN de usuario), de
sistema o de archivo. La elección de uno u otro dependerá de los permisos de acceso que
quiera establecer (y eso es, de momento, para nota). En cualquier caso, todas los enlaces
ODBC que establezca funcionarán del mismo modo, exceptuando que puede otorgar unas
prerrogativas distintas de uso, dependiendo de como lo haya abierto.
Observe uno que figura en la lista: Luki. En esa línea figura otro dato: Microsoft Access
Driver.(*.mdb) Esto significa que el enlace de nombre Luki está usando el driver ODBC de
Access. Y significa también que si queremos llamar a esa conexión deberemos llamarla por su
nombre : Luki
Sigamos con la creación del enlace ODBC. Para crear uno nuevo, haga click en el botón
Agregar de la figura 13-1. Le aparecerá un cuadro donde le pide el driver que quiere utilizar.
Haciendo click en Finalizar, le pedirá el nombre del nuevo enlace, un comentario, (no es
necesario introducirlo), y la base de datos con la que quiere enlazar
Haciendo click en Base de Datos | Seleccionar nos muestra un cuadro de diálogo donde
`podemos buscar la base de datos. Se elige la base de datos deseada. Hacemos click en
ACEPTAR y ya está creada la nueva conexión.
La base de datos del sistema deberá elegirla para poder introducir usuarios con distintas
atribuciones de acceso a la base de datos. Si no introduce esta base de datos de sistema,
deberá trabajar sin restricción de acceso.
Una vez creada la conexión podemos utilizarla para conectar nuestra aplicación con la base de
datos. El proceso para ello consiste en algo parecido a lo que hacíamos trabajando con el
motor Jet en el espacio de trabajo Microsoft Jet, pero de distinta forma. En ese entorno se
manejaba la base de datos creando un objeto Database, que manipulaba el fichero de la base
de datos directamente. En este caso, la base de datos se maneja mediante un objeto
Connection.
El trabajar sobre una conexión nos aporta mayor versatilidad a las aplicaciones. Piense por
ejemplo un caso en el que se emplea una base de datos Access. Si quisiésemos ampliar las
prestaciones de la base de datos de esa aplicación posiblemente pensaríamos en migrar la BD
a Oracle o SQLServer. Si atacamos a la base de datos a través de ODBC solamente
deberíamos cambiar la conexión, tal como vimos más atrás. Nuestro programa seguiría
llamando a la misma conexión ODBC, pero esta conexión, ahora, abriría una base Oracle o
SQLServer en vez de la Access que abría originalmente. No necesitaríamos realizar ninguna
modificación en nuestro programa.
Este razonamiento es válido para cualquier sistema de acceso a bases de datos a través de
ODBC. (RDO ó ADO) Sin embargo el ODBCDirect tiene una ventaja `para los que trabajamos
normalmente con DAO: usa los mismos nombres para casi todos los métodos y funciones, por
lo que el cambio de código es mínimo. El cambio se limita prácticamente a crear el objeto
Connection en vez del objeto Database. Comencemos a ver esto con u ejemplo. Es un
ejemplo uy simple, en el que abrimos una base de datos Access llamada Alumnos.Mdb que
tiene una tabla llamada Personas. Creamos la conexión Luki tal como se describió mas
atrás. La tabla personas tiene solamente tres campos: ID_Alumno, Nombre y Apellidos.
Creamos una interface gráfica sencilla
Mediante esta sencilla aplicación queremos visualizar los datos existentes, añadir nuevos
registros y borrar el registro actual. Veamos el código con los comentarios oportunos.
General/Declaraciones
Option Explicit 'Declaramos las variables tipo objeto
Dim MiSesion As Workspace
Dim MiConexion As Connection
Dim RsODBC As Recordset
Observe que casi todo el código es igual que el que escribiríamos si hubiésemos utilizado el
espacio de trabajo Microsoft Jet. Solamente hemos utilizado código distinto el procedimiento
BCrearConexion_Click. Vamos a analizar las instrucciones de ese procedimiento que son
distintas a las que estamos acostumbrados a manejar
DBEngine.DefaultType = dbUseODBC
Vea la propiedad DefaultType en el Capítulo 20. Tenga en cuenta que el ODBCDirect lo
ejecuta el motor Jet (que como recordará es el objeto DBEngiine). La propiedad DefaulType
debemos igualarla a dbUseODBC para que trabaje en el espacio de trabajo ODBCDirect. Si
no le diésemos ningún valor a esa propiedad, tomaría el otro valor posible (dbUseJet) que es
su valor por defecto. Por eso, cuando utilizábamos los métodos CreateDataBase u
OpenDatabase no necesitábamos darle ningún valor a esa propiedad.
Vea mas abajo la información de OpenConnection para ver los parámetros que hay que
pasarle a este método.
Método OpenConnection
Es un método del Workspace que solamente es aplicable cuando el DBEngine está trabajando
en el espacio de trabajo ODBCDirect. Abre un objeto Connection usando un origen de datos
ODBC ya creado.
En el ejemplo:
Set MiConexion = MiSesion.OpenConnection("Conexion1", dbDriverNoPrompt, False,
"ODBC;DSN=Luki")
Nombre es el nombre de la conexión (no se debe confundir con el nombre del objeto
Connection que es MiConexion, y que es el nombre por el que nos tendremos que referir a esa
conexión en toda la aplicación. Nombre no lo usará normalmente)
El parámetros Nombre puede ser una cadena cualquiera, o el nombre del enlace ODBC
establecido en Windows (que en nuestro ejemplo sería Luki). Si opta por poner una cadena
cualquiera (como hicimos en el ejemplo, Conexión1) deberá poner el nombre del enlace
ODBC en el parámetro Conectar. Si opta por poner el nombre del enlace ODBC, Visual Basic
Opciones Este parámetro es para definir que tipo de respuesta va a dar el administrador del
controlador de ODBC para solicitar al usuario información sobre la conexión (Nombre del
origen de datos (DSN), nombre del usuario y contraseña). Puede tomar uno de los siguientes
valores:
Una vez seleccionada la conexión, aparecerá otro cuadro solicitando el nombre de inicio de
sesión y la contraseña. En resumen, con este parámetro DbDriverPrompt forzamos al
programa a que utilice los recursos Windows para seleccionar el enlace ODBC
Sólolectura (Opcional). True si la conexión se va a abrir con acceso de sólo lectura y False si
la conexión se va a abrir para acceso de lectura/escritura (predeterminado)
Si omite los parámetros UID y/o el PWD, estos datos se obtendrán de las propiedades
UserName y Password del objeto Workspace.
Método OpenRecordset
Este método ya se estudió en el capítulo anterior, pero se van a ver ciertas peculiaridades que
tiene cuando se abre un recordset en el espacio de trabajo ODBCDirect
Set MiRecordset =
= MiConexion.OpenRecordset (Origen, Tipo, Opciones, Bloquearmodificaciones)
Origen Puede ser un nombre de tabla, de una consulta o una instrucción SQL que devuelva
registros.
Tipo Indica el tipo de recordset que queremos crear. El espacio de trabajo ODBCDirect no
permite recordsets tipo Tabla. Los tipos que se pueden elegir son:
Opciones Debe indicar uno de estos dos valores (si no pone alguno de ellos da error):
DbRunAsync Ejecuta una consulta asíncrona, que es la forma normal de trabajar del
ODBC. Esto permite a su aplicación seguir procesando otras instrucciones mientras se
ejecuta la consulta en segundo plano (Vea mas adelante la propiedad StillExecuting
dbExecDirect Ejecuta una consulta saltando el método SQLPrepare y llamando
directamente al método SQLExecDirect. Utilice esta opción sólo cuando no se abra un
objeto Recordset basándose en una consulta de parámetros. Para obtener más
información, consulte la "Referencia del programador de Microsoft ODBC 3.0."
Actualización por lotes. Modelo de cursor para clientes que trabajan con cursores, pero no
mantienen bloqueos en el servidor o ejecutan actualizaciones por fila. En su lugar, el cliente
actualiza muchas filas que están almacenadas en el búfer local y después ejecuta una
actualización por lotes. Este modelo de cursor también permite al cliente cancelar la
conexión con el servidor y volverla a establecerla con el mismo servidor o con otro diferente.
Para utilizar la actualización por lotes en DAO 3.5, debe utilizar un espacio de trabajo de
ODBCDirect, la propiedad DefaultCursorDriver se debe establecer a
dbUseClientBatchCursor en el momento de abrir la conexión y se debe abrir el Recordset
con el argumento de tipo de bloqueo del método OpenRecordset establecido a
dbOptimisticBatch.
Propiedad StillExecuting
Cuando abrimos una conexión mediante OpenConnection, un QueryDef o creamos un
recordset y le ponemos en Opciones DbRunAsync, la operación se realiza de forma
asíncrona, por lo tanto no sabemos cuando tendremos disponible el objeto a crear o los datos
de la consulta. Para poder controlar si la operación se está realizando todavía leeremos la
propiedad StillExecuting, que devolverá True si todavía se está ejecutando, y False si ha
terminado. Basta con hacer un bucle del tipo
Mientras la propiedad StillExecuting sea True, no se puede tener acceso a ningún objeto
devuelto. Por ejemplo, no pretenda crear un recordset con MiConexion Mientras que
StillExecuting sea True, pues MiConexión no existe aún.
Esta propiedad puede ser muy útil cuando tiene consultas encadenadas y necesita esperar a
que termine una para comenzar con la siguiente.
Objeto Connection, para controlar que aún se está ejecutando uno de los métodos Execute
u OpenConnection
Objeto QueryDef, para comprobar su método Execute
Recordset, donde podrá comprobar si aún se están realizando los métodos Move,
NextRecordset u OpenRecordset
Método Cancel
Cancela la ejecución de un método asícrono de llamada. Sólo funciona espacios de trabajo
ODBCDirect.
Sintaxis objeto.Cancel
El método Cancel solamente sirve para cancelar la ejecución de una llamada asíncrona de los
métodos Execute, OpenConnection u OpenRecordset que se hayan invocado con la opción
dbRunAsync. Cancel devolverá un error de tiempo de ejecución si en el método que está
intentando finalizar no se utilizó dbRunAsync.
DBEngine.DefaultType = dbUseODBC
Set MiSesion = Workspaces(0)
Set MiConexion = MiSesion.OpenConnection("Conexion1", dbDriverNoPrompt, False,
"ODBC;DSN=Luki")
Set MiConsulta = MiConexion.CreateQueryDef ("Pepito", "Select * From Personal Where
Apellidos = "Alvarez Pérez")
Set RsODBC = MiConsulta.OpenRecordset(dbOpenDynaset, dbRunAsync, dbOptimistic)
If RsODBC.AbsolutePosition <> -1 Then
RsODBC.MoveLast
RsODBC.MoveFirst
LNumRegs = RsODBC.RecordCount
LNumReg = RsODBC.AbsolutePosition + 1
PresentaDatos
Else
MsgBox "El recordset no tienen ningún registro"
End If
Para indicarle el enlace ODBC que debe usar puede hacerlo de las dos formas que venimos
viendo para los parámetros Nombre y Conexión. Si indica el nombre del enlace en el
parámetro Nombre lo aceptará y será necesario poner el parámetro Conexión. Si `pone un
nombre cualquiera en el parámetro Nombre deberá indicar el nombre del enlace en el
parámetro Conexión.
Esta posibilidad de crear un objeto Database nos aproxima aún más al código empleado en el
espacio de trabajo Microsoft Jet. Por lo tanto puede ser muy útil usar este objeto en aquellos
casos en los que ya se había escrito el código, y pasamos posteriormente a usar ODBC.
DBEngine.DefaultType = dbUseODBC
Set MiSesion = Workspaces(0)
'En la siguiente línea le pasamos el nombre del enlace ODBC en el parámetro Nombre
Set MiBaseDatos = MiSesion.OpenDatabase("Luki", dbDriverNoPrompt)
'Pero podríamos haberselo pasado en el parámetro Conexión y ponerle como parámetro
'nombre cualquier cadena de caracteres
Set MiBaseDatos =
MiSesion.OpenDatabase("BaseDatos1", dbDriverNoPrompt, False, "ODBC;DSN=Luki")
'Ahora creamos el recordset, como en los otros casos
Set RsODBC = MiBaseDatos.OpenRecordset("Personal", dbOpenDynaset, dbRunAsync,
dbOptimistic)
If RsODBC.AbsolutePosition <> -1 Then
RsODBC.MoveLast
RsODBC.MoveFirst
LNumRegs = RsODBC.RecordCount
LNumReg = RsODBC.AbsolutePosition + 1
PresentaDatos
Else
MsgBox "La base de datos no tiene ningún registro"
End If
Mediante los ejemplos expuestos en este capítulo espero que el alumno comprenda como
trabaja DAO a través de ODBC, mediante el ODBCDirect.
No olvide que sigue tratándose de DAO, y que por lo tanto deberá poner la misma referencia
(En Proyecto | referencia) que en el caso del DAO trabajando en el espacio de trabajo
Microsoft Jet. En la siguiente parte de este capítulo se estudiarán los objetos RDO, objetos
que trabajan exclusivamente a través de ODBC. Con las ideas captadas hasta aquí verá que
es sencillo abordar estos nuevos objetos.
Visual Basic - Guía del Estudiante Cap. 13 Continuación
Acceso a Bases de Datos remotas mediante objetos RDO
En la primera parte de esta capítulo hemos visto como acceder a bases de datos a través de
ODBC usando el motor JET. El acceso se realizaba mediante ODBCDirect, modo de
operación del motor JET, y podíamos usar la misma sintaxis y objetos que habíamos visto con
los objetos DAO. También vimos como crear un enlace ODBC, enlace que vamos a utilizar en
Los objetos RDO se crearon para cubrir el hueco que tenía VB para conectar con bases de
datos distintas a las que trabaja el motor JET. (Access, dBase, FoxPro, etc.). Esta forma de
trabajar nos permite enlazar con bases de datos tipo Oracle o SQLServer, pero también nos
permite trabajar con Access, dBase o FoxPro, que también tienen su propio driver ODBC.
Lo primero que nos encontramos al trabajar con RDO es que es más lento que DAO. Si
creamos dos aplicaciones que trabajen sobre una base Access, una directamente a través de
DAO y otra a través de RDO, observaremos que la primera accede a la BD con una rapidez
mayor que la segunda. Normal, no es lo mismo abrir un fichero y leerlo (que es lo que hace
DAO) que pasar unos parámetros a otro programa (Driver ODBC de Access) para que este
abra el fichero, obtenga los datos y nos los pase. Lo mismo podemos decir cuando tenemos
que contar registros, movernos de un registro a otro, editar o añadir nuevos registros. Esa falta
de rapidez es el coste de la tecnología de bases abiertas.
Lo segundo que nos va a llamar la atención es el nombre de los objetos de acceso a datos.
Una vez que nos habíamos familiarizado con palabras como Recordset, DataBase o Dynaset,
nos las cambian por rdoResultset, rdoConnection o Keyset respectivamente. Y lo peor no es
solamente tener que aprender sus nombres, sino que en una aplicación hecha en DAO que
sea necesaria cambiarla a RDO, nos vemos obligados a retocar la mayor parte de las líneas
de código (Cosa que no ocurría con ODBCDirect)
Y lo tercero, RDO no tiene la posibilidad de crear bases de datos como hacíamos en DAO.
Normal, ya que en este caso no trabajamos directamente sobre la BD sino sobre la conexión
ODBC que Windows realizó a una base de datos. Podemos añadir mas desventajas de RDO:
no puede contar los registros que tiene, tiene un comportamiento muy irregular con la
propiedad AbsolutePosition, y varios detalles que procuraremos explicar en este capítulo para
ahorrar al alumno el trabajo de tener que experimentarlos por sí mismo. (Aunque, consejo de
viejo profesor, es la forma más segura de aprenderlos).
Tras estos inconvenientes parece lógico encontrar alguna contrapartida positiva. Por ejemplo
poder conectar con cualquier tipo de base de datos, pudiendo incluso realizar la aplicación
atacando una base Access, para luego trabajar con una base SQLServer u Oracle sin variar ni
una línea de código. Esa debería ser la gran ventaja de RDO. Pero lamentablemente, y en
contra de toda teoría de ODBC, no es cierto. Si preparamos una aplicación en RDO trabajando
con una base Access y pretendemos cambiar la base por otra SQLServer, observaremos que
lo que funciona perfectamente en la primera no funciona en la segunda. (Y esto no es teoría.
Es simplemente experiencia del autor). ¡Y Access y SQLServer son del mismo fabricante!. La
razón está en que los drivers de una base y otra no trabajan exactamente igual. Tampoco son
iguales las protecciones y los permisos de acceso. Consejo de viejo profesor: Si va a trabajar
con una determinada base de datos a través de RDO comience el proyecto usando esa base
de datos. Y puestos a dar consejos, si piensa usar SQLServer u Oracle y si la aplicación va a
escribir datos en la base no use RDO. Si solamente los va a leer no tendrá problemas. Y si
tiene problemas nadie se los va a resolver, argumentando que deje RDO y use ADO. De hecho
RDO ya se ha quedado obsoleto al nacer ADO. Pero eso será objeto de otro capítulo de esta
Guía del Estudiante y hoy nos toca aprender RDO. Comencemos.
Al igual que DAO, RDO tiene objetos de acceso a datos, que deberemos declarar y crear.
Mediante estos objetos podemos leer y escribir datos en una BD mediante código. También, al
igual que en DAO existía el Control Data, con el que podíamos acceder a la base de datos sin
escribir ni una línea de código, en RDO existe un control similar: el Control RemoteData. El
funcionamiento es similar, pero las propiedades son distintas y tienen distintos nombres.
Mediante el control RemoteData podemos enlazar una base de datos a los típicos controles
enlazados a datos (Label, TextBox, DBGrid), pero en este caso se enlazan a través de una
conexión ODBC, por lo que es fácil pensar que las propiedades de este control y los valores
que deben tomar son distintas a los del control Data. Como es mucho más sencillo (sencillo no
Pero antes vamos adelantar la equivalencia entre los objetos DAO y los objetos RDO. La lista
siguiente está copiada literalmente de la información de Microsoft MSDN Library Visual Studio,
información que merece la pena instalarla en su ordenador pese a lo que ocupa.
(*) En RDO, los usuarios y grupos de usuarios son precisamente los que lleve implícitos la
conexión ODBC.
(**) Al no trabajar directamente sobre la base de datos, no se pueden crear relaciones en ella.
DatasourceName
Devuelve o establece el nombre del origen de datos (DSN). El DSN No es más que el nombre
de la conexión ODBC.
Esta propiedad se puede dejar en blanco si la propiedad Connect del control identifica un
nombre de origen de datos (DSN) registrado en el Registro de Windows.
Puede leer el valor de esta propiedad. Le devolverá precisamente el DNS que está utilizando.
Esta propiedad sólo le devolverá un valor si ha introducido previamente algún valor en la
propiedad DatasourceName. No le devolverá valor alguno si ha introducido la conexión a
través de la propiedad Connect.
Propiedad Connect
Esta propiedad cumple la misma función que la anterior, pero por otro camino. Mediante la
propiedad Connect le introducimos al control RemoteData la información necesaria para abrir
la conexión, incluyendo en esta información, no solamente el nombre de la conexión, como
hacíamos con la propiedad DatasourceName, sino ampliarla con otros datos de la conexión, tal
como el nombre del usuario, su contraseña, nombre del controlador ODBC a usar, el nombre
de la base de datos, el servidor donde se ubica esta base de datos, nombre de la estación de
trabajo desde la que vamos a trabajar e incluso el nombre de la aplicación en la que vamos a
usar los datos de esa base. Esta propiedad es mucho más completa que la anterior, pero un
poco más complicada de usar.
Para introducir los datos de la propiedad Connect deberá usar una palabra para definir el dato,
seguido del signo = y del dato a introducir. Como final del dato debe introducir necesariamente
el signo punto y coma ;
NOTA - Si conoce SQLServer, DATABASE es el nombre de la base de datos que quiere utilizar
una vez realizada la conexión. Para los que no conocen SQLServer, dentro de un fichero de
esta base de datos pueden existir varias bases de datos. Y cada una de ellas puede tener
varias tablas. Es decir, la configuración de esta BD no es tan simple como la de Access. Cada
una de estas bases de datos tiene un propietario y varios usuarios. Cada usuario tiene
habilitadas unas funciones (p.e. un usuario puede leer y escribir y otro solamente leer) Este
parámetro le indica cual de esas bases de datos que contiene el fichero de SQLServer (para
hablar con mas propiedad, el sistema de ficheros de SQLServer)
Observe que tras cada parámetro existe un separador ; No es necesario introducir todos los
datos. Dependerá del driver, de cómo haya creado la base de datos, los atributos que le dio a
cada uno de los usuarios. Y como no, dependerá del tipo de base de datos que esté usando
(SQLServer, Oracle, etc.). Recuerde lo mencionado más atrás. No se fíe nunca de que su
aplicación trabaja perfectamente sobre una base de datos. Lo más probable es que si cambia
de BD ya no le trabajará tan perfectamente.
El hecho de que podamos abrir una base de datos mediante DatasourceName o Connect
tiene su explicación. Si tenemos creada una conexión ODBC con todos los datos necesarios
para que pueda abrir una base de datos, es mucho más simple usar la propiedad
DatasourceName y el Control RemoteData le abrirá perfectamente la BD. Pero cuando
Puede utilizar el control, RemoteData incluso sin tener una conexión preestablecida. Pero
deberá establecer mediante el programa, utilizando los métodos OpenConnection o
EstablishConnection. Se sale del contenido deseado para este curso comentar estos
métodos, pero el alumno aventajado puede intentar obtener información en la escasa
bibliografía existente. No le recomiendo que se complique la vida rizando el rizo, pudiendo
establecer previamente la conexión ODBC.
Propiedad SQL
Mediante las dos propiedades estudiadas, DatasourceName y Connect hacemos que el
control RemoteData sepa la conexión sobre la que va a trabajar - y por lo tanto la base de
datos que utilizará. Ahora nos falta indicarle los datos que deseamos leer o escribir. Nos falta
lo que sería en DAO, darle los datos para crear el Recordset (Por ejemplo el nombre de una
tabla o una sentencia SQL, tal como hacíamos en la propiedad RecordSource del control
Data). Para el control RemoteData esta información se le introduce en la propiedad SQL
La propiedad SQL establece o devuelve una instrucción SQL válida para crear un conjunto de
registros a partir del origen de datos establecido en las propiedades DatasourceName o
Connect. Esta instrucción SQL debe comenzar necesariamente por SELECT, En tiempo de
ejecución, podemos asignar a esta propiedad el nombre de una Consulta ya almacenada en la
BD, pero en este caso, debemos anteponer la palabra EXECUTE. También podemos introducir
en esta propiedad un rdoQuery, un rdoResultset o un rdoTable. Eso lo veremos más
adelante.
Para establecer esta propiedad en tiempo de diseño, basta con escribir la instrucción SQL en
la ventana de propiedades. Una instrucción típica sería
Si la BD tiene una consulta (la típica consulta de Access) llamada C_Suarez, donde hemos
seleccionado todos los registros cuyo campo Apellido1 sea Suárez, podemos poner:
(No intente hacer esto mismo con el nombre de una tabla. Solamente sirve para consultas)
Con los registros seleccionados por la propiedad SQL, formamos lo que en DAO era un
recordset, pero en este caso adopta otro nombre: rdoResultset. En RDO se ha buscado otra
terminología, posiblemente para diferenciarlo claramente de DAO. Por ejemplo, en vez de
registros es habitual hablar de Filas, y en vez de campos, hablamos de Columnas.
Propiedad Connection
Veamos previamente que es un objeto rdoConnection. Un Objeto rdoConnection es un objeto
de acceso a datos remotos. Es el equivalente al objeto Database en DAO (Vea cuadro página
2) El control RemoteData tiene un objeto rdoConnection subyacente y podemos "verlo"
mediante esta propiedad. El poner verlo entre comillas no significa otra cosa que, al igual que
ocurría con el objeto Database, el objeto rdoConnection es un objeto de acceso a datos del
que podemos ver sus propiedades y ejecutar sus métodos. Por ejemplo, si queremos ver la
cadena de conexión completa podemos analizar la propiedad Connect del Objeto Connection:
Label1 = MSRDC1.Connection.Connect
Si deseamos saber si el control RemoteData sigue conectado para realizar una determinada
operación:
If MSRDC1.Connection.StillConnecting Then ….
MSRDC1.Connection.Close
MSRDC1.BOFAction = valor
MSRDC1.EOFAction = valor
Los valores (o constantes) que puede tomar son los siguientes:
La propiedad EOFAction sólo tiene efecto cuando se manipula el cambio de filas mediante el
ratón, sobre los botones del control RemoteData. No tiene efecto si se llega a la fila posterior a
la última mediante código. (Por ejemplo, mediante la instrucción MSRDC1.resultset.MoveNext)
Propiedad CursorDriver
Devuelve o establece un valor que especifica el tipo de cursor que se va a crear. Veamos
primero qué es un cursor. Según la definición de Microsoft:
El crear un cursor de lado cliente o de lado servidor puede hacer que su código funciones o
no funcione. Los cursores lado cliente suelen ser de lectura / escritura, que permiten avanzar
hacia a delante y hacia atrás. Los cursores lado servidor suelen ser solamente de lectura y
de avance solamente hacia delante. Hemos empleado una palabra no muy exacta: suelen
ser. Y es que eso dependerá de la base de datos (Oracle no se comporta como SQLServer,
y ninguna de ellas se comporta como Access) y depende también del controlador ODBC que
utilice (Hay controladores de varias marcas para la misma base de datos) Es muy frecuente
realizar un código que funciona perfectamente con un controlador ODBC, y cuando se
cambia de controlador – o de versión – ya no funciona. Le recomiendo mucho cuidado.
Método UpdateRow
Es equivalente al método UpdateRecord del Control Data. Guarda los valores actuales de los
controles enlazados en la base de datos. El método UpdateRow tiene el mismo efecto que
ejecutar el método Edit, modificar una columna y después ejecutar el método Update, excepto
que no ocurre ningún evento.
Nota Cuando usa una biblioteca de cursores ClientBatch, todas las actualizaciones a las tablas
base se retrasan hasta que use el método BatchUpdate. En este caso, el método UpdateRow
actualiza el rdoResultset local, pero no actualiza las tablas base. Estos cambios pueden
perderse si la aplicación termina antes de que se haya completado el método BatchUpdate.
De igual forma que un control data tenía asociado un recordset, un RemoteData tiene asociado
un Resultset. El Resultset es el objeto rdoResultset del control RemoteData (Colección de
registros, o si lo prefiere, de filas ya que estamos en RDO), y que como cualquier objeto de
acceso a datos, tiene sus métodos, y este es uno.
Este método es un método del rdoResultset. Si tenemos un rdoResultset creado con código
(Ahora veremos como se hace) la sintaxis sería
Con esta introducción ya podemos pensar que el alumno tiene cierta idea respecto a lo que es
el control RemoteData. Vamos a comenzar a explicar lo que son los objetos de acceso remoto
a datos (Objetos RDO) y podremos seguir viendo cosas acerca del control RemoteData como
aplicación de estos nuevos objetos.
Como ya conocemos los objetos de acceso a datos DAO, veremos los objetos RDO
basándonos un poco en este conocimiento.
Los objetos de datos remotos nos permiten manipular componentes de un sistema de base de
datos ODBC remoto. Lo de remoto no implica que la base de datos deba estar en un
ordenador distinto al que tiene la aplicación. (Aunque esta sea la disposición más usual en
aplicaciones que usan RDO). El significado de RDO es que se accede a la base de datos a
través de una conexión ODBC.
Al igual que en DAO, los objetos RDO tienen una estructura jerárquica que se puede ver en la
siguiente figura:
Los objetos RDO siguen la misma regla para su creación que los objetos DAO: el objeto
jerárquicamente superior crea al objeto inferior.
El Objeto rdoEngine
El objeto rdoEngine representa el origen de datos remoto. Es el equivalente al dbEngine de
DAO, es decir, el motor de bases de datos. Es el objeto de nivel jerárquico superior, por lo
tanto no se crea por otro objeto, sino que está creado simplemente al introducir la referencia.
El objeto rdoErrors contiene todos los mensajes de error enviados desde el origen de datos
remoto. Cada vez que se recibe uno de estos mensajes, se produce el evento InfoMessage del
rdoEngine
Por defecto, esta propiedad toma el valor 0, que pone la configuración establecida en
Windows.
Si el archivo DLL del idioma especificado no está presente en el equipo del usuario, RDO se
establece como rdLocaleEnglish, lo cual no requiere un archivo DLL independiente. Cuando
esto ocurre, se coloca un mensaje informativo en la colección rdoErrors para indicar que RDO
no pudo cargar el archivo DLL de recursos para la configuración regional especificada.
Cuando distribuya la aplicación, asegúrese de incluir el archivo DLL del lenguaje apropiado.
Donde:
Nombre es la propiedad Name del nuevo objeto rdoEnvironment. (En el código, para nombrar
a este rdoEnvironment debemos hacerlo con MiSesion). Debe suministrar un nombre, ya que
si no lo hace, este rdoEnvironment creado no se suma a la colección rdoEnvironments.
Usuario es el nombre del usuario.
Contraseña es la contraseña usada en esa sesión. Puede tener hasta 14 caracteres.
Hasta aquí las propiedades y métodos del rdoEngine. Vamos a bajar un nivel jerárquico y ver
el siguiente objeto RDO
El Objeto rdoEnvironment
Un objeto rdoEnvironment es una sesión de trabajo en RDO. Equivale al Workspace de
DAO. En un rdoEnvironment podemos tener varios objetos Connection (varias conexiones)
de la misma forma que en un Workspace podíamos tener varias objetos Database.
Propiedad hEnv
Esta propiedad es el Handle de la conexión ODBC. Es similar a la propiedad hDC (para
controles) o hWnd (para formularios) que ya hemos visto en capítulos anteriores. Esta
propiedad es sólo de lectura y devuelve un Long. Este valor lo usan las APIs de Windows para
trabajar. Alguna instrucción nos pedirá el hEnv como parámetro.
Propiedad LoginTimeout
Devuelve o establece el número de segundos que el Administrador de controladores ODBC
espera antes de que se produzca un error de espera al abrir una conexión.
Si establece un valor para esta misma propiedad en uno de sus objetos rdoConnection, este
valor es prioritario al establecido en el objeto rdoEnvironment.
Método OpenConnection
Abre una conexión con un origen de datos ODBC. En otras palabras, crea un objeto
rdoConnection, objeto que deberá declarar antes de abrirlo:
Nombre puede ser una conexión ya creada, en cuyo caso se abrirá esa conexión. Si este
parámetro es una cadena vacía, deberá obtener los datos de la conexión, o bien del
argumento Conectar, o mediante el cuadro de dialogo de abrir la conexión.
SóloLectura Determina si la conexión se abre como sólo lectura o para lectura / escritura. Si
no se especifica nada, se abre para lectura / escritura.
Para introducir los datos de la propiedad Connect deberá usar una palabra para definir el dato,
seguido del signo = y del dato a introducir. Como final del dato debe introducir necesariamente
el signo punto y coma ;
Método Close
Cierra un el rdoEnvironment y todas las conexiones que tenía abiertas. Las modificaciones
pendientes de los objetos RDO inferiores que estuviesen abiertos se deshacen.
Sintaxis MiSesion.Close
Un objeto rdoConnection (es decir, una conexión a una base de datos a trvés de ODBC) se
crea o con un control RemoteData o mediante el método OpenConnection del objeto
rdoEnvironment.
Puede también crear un nuevo objeto rdoConnection que no esté vinculado de forma
inmediata con una conexión física específica a un origen de datos. Por ejemplo, el siguiente
código crea un objeto rdoConnection independiente:
Posteriormente puede introducir las características que desee y establecer la conexión real con
la base de datos. No es normal hacer esto, por lo que le remito en caso necesario, a la ayuda
de VB de este objeto.
No es necesario aportar estos datos para crear la conexión, ya que son los que se han
introducido en Windows al crear la conexión ODBC. Estos datos solamente son necesarios si
la conexión ODBC se creó sin aportarle datos acerca de la base de datos.
Propiedad hDbc
Devuelve el controlador de conexión ODBC.
Sintaxis MiConexion.hDbc
La propiedad hDbc devuelve un valor de tipo Long. Este valor lo utilizan las APIs de Windows.
Y es similar a hDc o hWnd
Sintaxis
Dim MiRs as rdoResultset
Set MiRs = MiConexion.LastQueryResults
Propiedad QueryTimeout
Devuelve o establece un valor que especifica el número de segundos que espera el
Administrador de controladores ODBC antes de que se produzca un error de tiempo de espera
al ejecutarse una consulta. El valor predeterminado es de 30 segundos.
Propiedad StillConnecting
Devuelve un valor que indica si la conexión se está estableciendo todavía.
Sintaxis MiConexion.StillConnecting
Esta propiedad devuelve True si la conexión no ha terminado de establecerse, y False si ya
está establecida. Es fundamental saber que la conexión ya está establecida antes de realizar
ninguna operación con ella, por ejemplo, crear un Resultset
Propiedad StillExecuting
Devuelve un valor que indica si una consulta está aún ejecutándose. Esta propiedad se usa
cuando creamos un rdoResultset o un rdoQuery, para conocer si ya se ha finalizado el proceso
de selección de filas que esa operación implica. Esta propiedad puede aplicarse al
rdoConnection, rdoQuery y rdoResultset. Devuelve True cuando la consulta está ejecutándose
todavía, False si ya se ha finalizado.
Sintaxis objeto.StillExecuting
Propiedad Transactions
Devuelve un valor que indica si se pueden realizar transacciones con un objeto rdoConnection
ó rdoResultset. Esta propiedad le permite asegurarse de esta circunstancia antes de ejecutar la
instrucción BeginTrans.
La propiedad Transactions llama a la función SQLGetInfo de ODBC para determinar si el
controlador ODBC es capaz de permitir transacciones, no si el conjunto de resultados actual es
actualizable.
Propiedad AsyncCheckInterval
Devuelve o establece un valor que especifica el número de milisegundos que espera RDO
entre dos comprobaciones para ver si se ha completado una consulta asíncrona.
Propiedad UpdateOperation
Esta propiedad afecta a la forma en la que se realiza la modificación de una fila en una
actualización optimista por lotes. Si a esta propiedad se le pone el valor 0 (Predeterminado) la
modificación de la fila se realiza mediante una instrucción Update. Si el valor es 1, la
operación de modificación se realiza mediante dos instrucciones, primero una instrucción
Delete (borra la fila) y a continuación otra instrucción Insert (Crea la fila con los nuevos
valores).
El Objeto rdoResultset
El Objeto rdoResultset es el conjunto de filas que devuelve la ejecución de una consulta. Es
Ejemplo:
‘Creamos el objeto rdoEnvironment utilizando el objeto creado automáticamente por VB
Set GepaWs = rdoEnvironments(0)
‘El objeto rdoEnvironment crea el objeto rdoConnection
Set GepaConex = GepaWs.OpenConnection(“Gepa”, rdDriverNoPrompt, False)
‘(Gepa es el nombre de la conexión ODBC creada en el ordenador)
‘El objeto rdoConnection crea el objeto rdoResultset
Donde
MirdoResultset = variable tipo rdoResultset que debe estar declarada.
MiConexión = Objeto Connection con el que se crea el rdoRsultset
Nombre = Nombre de una tabla o consulta de la base de datos, o una sentencia
SQL que pueda devolver filas.
Tipo = Tipo de cursor que se va a crear
TipoBloq = Tipo de bloqueo de la base de datos. Por defecto, lo crea solo lectura.
Opciones = Opciones que puede tener el rdoResultset
El objeto rdoResultset tiene algunas particularidades que no tienen los recordsets de DAO, por
ejemplo, poder obtener resultados múltiples, es decir, se pueden introducir varias sentencias
SELECT y cada una de ellas crea un conjunto de registros. Esto no significa que haya mas de
un rdoResultset, sino que existe un único rdoResultset con resultados múltiples. Se puede ir
accediendo a cada uno de los conjuntos de registros mediante el método MoreResults.
AbsolutePosition. Igual que en RDO, pero no siempre funciona, ya que depende del tipo de
cursor.
BatchCollisionRows
Devuelve una matriz de marcadores que indica las filas que han provocado colisiones en la
última operación de actualización por lotes. Devuelve un Variant con una matriz de las filas
que han provocado una colisión la última vez que se invocó el método BatchUpdate. El
número de elementos de esta matriz es el que indica la propiedad BatchCollisionCount
BatchSize (Propiedad)
Devuelve o establece un valor que especifica el número de instrucciones enviadas al servidor
en cada lote. De forma predeterminada se envían 15 instrucciones al servidor en cada lote.
Esta propiedad puede modificarse en cualquier momento. Si un DBMS no admite lotes de
instrucciones, puede establecer esta propiedad a 1, con lo que cada instrucción se enviará por
separado.
BOF, EOF Son idénticas a las mismas propiedades del Recordset de DAO
Bookmark Funciona igual que en el Recordset de DAO. Pero en RDO es posible que esa
propiedad no se pueda usar. Depende del tipo de cursor. Para asegurarse de que el objeto
rdoResultset admite marcadores, examine el valor de su propiedad Bookmarkable antes de
usar su propiedad Bookmark. Si Bookmarkable es False, el objeto rdoResultset no admite
marcadores y el uso de Bookmark producirá un error
La propiedad Bookmark no se aplica a los objetos rdoResultset de tipo forward-only.
EditMode Devuelve un valor que indica el estado de edición de la fila actual. Devuelve un
integer o una constante de acuerdo con la tabla siguiente:
LastModified Devuelve un marcador que indica la última fila modificada o agregada más
recientemente. Este marcador es el Bookmark de esa fila. Devuelve un Variant.
LockEdits Devuelve un valor de tipo Booleano que indica el tipo de bloqueo en vigor. Si
devuelve True utiliza bloqueo pesimista. Si devuelve False utiliza bloqueo optimista.
PercentPosition
Devuelve o establece un valor que indica o modifica la ubicación aproximada de la fila actual
en el objeto rdoResultset, basándose en el porcentaje con respecto al total de filas de dicho
objeto. El valor devuelto es un Single entre 0,0 y 100,0
Status Devuelve o establece el estado de la fila o columna actual. El valor de esta propiedad
indica si la fila o la columna estarán implicadas en la próxima actualización optimista por lotes
y de qué modo lo estarán.
Método AddNew
Crea una nueva fila para un objeto rdoResultset actualizable.
Sintaxis MirdoResultset..AddNew
Funciona igual que el mismo método de DAO, se ejecuta el método AddNew, se introducen
los datos en los campos y se termina la operación con el método Update, que es cuando los
datos entran en la base de datos. Si se está usando cursores de tipo Client Batch los datos se
escribitrán en la BD cuando se ejecute el método BatchUpdate.
Hay que tener cuidado, pues el método AddNew no devuelve ningún error si se intenta añadir
una nueva fila a un rdoResultset no actualizable. Ese error va a salir cuando ejecutemos el
método Update. Para evitar este error hay que comprobar la propiedad Updatable del
rdoResultset.
Debe tener cuidado también con asegurarse que tras el método AddNew ejecuta el método
Update antes de cambiar de fila, ya que de no hacerlo se pierden los cambios realizados y VB
no avisa de ese error.
MirdoResultset. CancelUpdate
La fila recién añadida no pasa a ser la fila actual. Sigue siendo fila actual la que era
anteriormente. Para que sea la nueva la fila actual basta con poner el siguiente código:
MirdoResultset.BookMark = MirdoResultset.LastModified
Pero eso sí, el rdoResultset debe aceptar marcadores. Para comprobarlo, se usa la propiedad
Bookmarkable.
Método BatchUpdate
Realiza una actualización optimista por lotes. Veamos que significa esto.
Este método solamente se puede aplicar a un rdoResultset del tipo Client Batch (Cuando se
crea el rdoResultset usando como tercer parámetro rdUseClientBatch) El tipo de rdoResultset
puede ser Keyset o Dynamic. En estas condiciones, cuando usamos el método Update para
guardar los datos, solamente se guardan en el rdoResultset local, pero no se meten en la base
de datos. Cuando se ejecuta este método, se envían a la base de datos todos los cambios
pendientes.
El parámetro filaÚnica es un Booleano que si es True, hace que la actualización sea solamente
de la fila actual. Si es False, se actualizan todas las filas pendientes.
forzar es tambiénun Booleano que si es True fuerza a escribir los valores, aunque puedan
causar colisiones.
Método Close
Cierra un rdoResultset abierto. Es igual al método Close del Recordset de DAO
Sintaxis MirdoResultset.Close
Método Delete
Elimina la fila actual de un objeto rdoResultset actualizable.
Sintaxis MirdoResultset.Delete
Sintaxis MirdoResultset.Edit
Si cambia la fila actual antes de ejecutar el método Update, se perderán los cambios. Si desea
anular el cambio que está realizando, basta con ejecutar el método CancelUpdate.
Cuando la propiedad LockEdits del objeto rdoResultset es True (bloqueo pesimista), todas
las filas del conjunto de filas del objeto rdoResultset se bloquean en cuanto se ejecuta Edit, y
se mantienen bloqueadas hasta que se ejecuta Update.
Método GetRows
Recupera múltiples filas de un rdoResultset y las introduce en una matriz.
Método Move
Cambia la posición de la fila actual en un objeto rdoResultset. Funciona igual que el mismo
método del Recordset de DAO
Método Requery
Actualiza los datos de un objeto rdoResultset volviendo a ejecutar la consulta en la que está
basado el objeto.
Método Update
Termina una operación de modificación de datos o de añadir una nueva fila. Ya se ha
comentado su funcionamiento con los métodos AddNew y Update.
Pero si usa Access con la base de datos instalada en el mismo ordenador que el programa,
use directamente DAO. Si usa Access olvídese de nuevas tecnologías. Con Access DAO
significa: Rapidez, sencillez, eficacia, control sobre el programa, independencia de drivers.