ACTIVE X DATA OBJECT (ADO) |
ADO es lo último de Microsoft en acceso a bases de datos. No
se porqué, pero desde su inicio, ADO está como metido en una aureola de
dificultad a la que solamente pueden acceder informáticos especialmente
elegidos. Quizás sea el uso de palabras de argot muy rebuscadas, que más que
facilitar el estudio, atemorizan al principiante. La Guía del Estudiante
pretende quitar esos velos que ocultan la sencillez de lo cotidiano y mostrar la
facilidad de esta técnica. Con el estilo didáctico que caracteriza a este
libro, pasaremos de las definiciones gloriosas e iremos a lo verdaderamente
importante: saber programar con ADO
ADO permite crear aplicaciones capaces de manipular
bases de datos a través de un proveedor OLE DB (Object Linking and Embedding
for DataBase). El objetivo de OLE DB es poner a disposición del programador una
herramienta de nivel inferior que le de acceso universal a los datos con independencia del origen de datos, ya sea
un servidor de correo electrónico, una hoja de cálculo u otro tipo de
almacenamiento de datos. Debido a la complejidad de los elementos de OLE DB, no
se puede acceder a ellos directamente desde Visual Basic; para ello
utilizaremos los objetos ADO que permiten acceder a la práctica totalidad de
las funciones de OLE DB.
Las características generales de ADO son:
Las características específicas que proporciona ADO
para entornos de Cliente/Servidor (C/S) son:
Hay que tener en cuenta que todas estas
características están limitadas por el servidor de los datos. Es decir, si el
servidor de datos no soporta procedimientos almacenados, no podremos utilizar
con él las características de ADO que se refieren a dichos tipos de
procedimientos.
Fig 72.1 Jerarquía de Objetos ADO.
* Todos los objetos
marcados con un asterisco contienen la colección Properties con un subconjunto
de objetos Property.
Como puede verse en la figura, existen tres objetos
principales dentro de ADO: El objeto Connection, el objeto Command y el objeto
recordset. Luego veremos algunas de las características principales de cada uno
de estos objetos.
Antes de proseguir con estos objetos vamos a explicar
donde y porqué se deben utilizar objetos ADO en vez de objetos DAO u objetos
RDO
Hasta ahora habíamos utilizado bases de datos Access,
y también otras bases de datos sencillas como dBase. Acceder a Access es
extremadamente fácil. Y ello es debido a que Access es una base de datos sin
grandes aspiraciones en cuanto a seguridad. Es una gran base de datos, y tiene
sus dispositivos de seguridad en cuanto a permisos de acceso (Vea El dbEngine.
Visión desde DAO y la propiedad SystemDB en el Capítulo 12) sin embargo estas
posibilidades se usan en muy pocas ocasiones, y estos mecanismos de seguridad
de Access tampoco son una maravilla. Por lo tanto Access se ha quedado como una
gran base de datos para aplicaciones
que no pasen de algunos centenares de miles de registros y con pocos puestos de
operación. En esta base de datos, el método ideal de acceso es DAO, bien
directamente o a través de ODBC Direct. Cuando se accede directamente, la BD se
suele buscar bien mapeando el disco del servidor como una unidad más del puesto
cliente, o bien accediendo a través de la dirección IP del servidor.
Cuando queremos empezar a tener una seguridad en los
accesos, disponer de privilegios distintos para cada usuario, trabajar en una
red de área local con muchos usuarios, hay que recurrir a bases de datos tipo
Oracle o SQLServer. Ya empezamos a tener
problemas: Visual Basic no puede acceder directamente a abrir estas bases de
datos. Podemos acceder a través de ODBC, pero como ya se dijo en el, capítulo
correspondiente, ODBC se ha quedado obsoleto. Y Microsoft ha sacado para ello
ADO. Y ADO permite abrir la base de datos usando para ello un dispositivo
intermedio que es el proveedor OLE DB. Este no es más que una DLL. Mejor dicho, un juego de DLLs que puede ver
en la carpeta:
C:\Archivos
de Programa\Archivos Comunes\System\Ado
Estas DLLs permiten conectar con las bases de datos
más conocidas (Oracle, SQLServer, Access y las demás BD controladas por el
motor Jet). ADO funciona de forma diferente a ODBC. Con ODBC se preparan
conexiones permanentes en el ordenador, y cualquier programa puede acceder a la
BD a través de esas conexiones. Con ADO no hay que preparar previamente ninguna
conexión. Es el propio programa el que llama al proveedor de datos OLE DB y le
pasa como parámetros los datos necesarios para que este realice la conexión y
abra la BD. Si hubiese dos programas ejecutándose simultáneamente y accediendo
a la misma base de datos a través de ADO, cada programa prepara una conexión a
esa BD. En ODBC podríamos ver las
conexiones existentes en el PC a través del Panel de Control | Fuentes de Datos ODBC.
En ADO no existe esa posibilidad ya que, como se ha dicho, es el propio
programa quien crea esa conexión al ajecutarse.
Para que VB pueda acceder a ADO es necesario
introducir en el programa la referencia a
Microsoft ActiveX Data Objets 2.1 Library (Proyecto|Referencias)
Una particularidad de ADO frente a lo ya visto con DAO o RDO
es que ADO se salta la jerarquía a la hora de crear nuevos objetos. En DAO, el
objeto DAO superior creaba al objeto DAO inferior (Recuerde aquello del juego
de niños). En ADO podemos crear cada
objeto sin que exista el objeto inmediatamente superior. Por ejemplo podemos crear un recordset sin
que exista el objeto Connection. Claro que en este caso, a la hora de crear el
objeto recordset deberemos indicarle, mediante los parámetros que debemos
aportar en la sintaxis de creación del recordset, todos aquellos datos que le
aportaríamos a la creación del objeto Connection. Como ve no tiene ventajas.
Solamente que nos desentendemos un poco de abrir y cerrar el objeto Connection.
Veamos como se crea la conexión: Mediante el Objeto
Connection
El objeto Connection representa una sesión con el
origen de los datos. Dependiendo de la funcionalidad del proveedor de los datos
podremos utilizar determinadas propiedades, métodos y colecciones de este
objeto. La función de este objeto es recoger toda la información del proveedor
de los datos que se va a utilizar para crear un objeto recordset.
Para crear un objeto Connection, previamente debemos
declararlo como variable objeto Connection:
Dim MiConexion as
ADODB.Connection
El sitio donde se debe declarar depende como siempre,
del ámbito que deseamos que tenga ese objeto.
Para crear el objeto Connection deberemos utilizar la
siguiente sintaxis:
Set MiConexion = New
ADODB.Connection
Nota: En el caso de que ejecutemos la aplicación y nos salga un error
diciendo que el tipo no está definido por el usuario, es que no hemos añadido
la referencia de “Microsoft Actives Data Objects Library x.x”
La conexión ¿está creada?. Sí, pero de momento es completamente inútil ya que no sabe ni
siquiera que base de datos debe abrir, ni con que usuario, ni las condiciones
en las que debe abrir esa base (Solo lectura, etc.) Esta información se la pasamos mediante la propiedad ConnectionString
(Cadena de conexión)
Es la propiedad más importante del objeto Connection.
Se basa en encadenar una serie de argumentos en una cadena de caracteres. Los
diferentes argumentos son (dependiendo del proveedor OLE DB y de la
configuración de la red, se necesitarán todos o parte de ellos)
Provider
Especifica el nombre del
proveedor que se usa en la conexión. (Oracle,
SQLServer, Jet, etc)
Data Source Especifica el nombre de la fuente de datos
para la conexión. (Nombre de la base de datos a la que se va a acceder.
User Id Especifica el nombre de usuario que
abre la conexión. Debe ser un usuario ya declarado en la base de datos.
Password Especifica la clave utilizada por el
usuario para abrir la conexión. Debe coincidir con el que tiene ese usuario
registrado en la Base de datos.
File Name Especifica el nombre del fichero
específico de proveedor, que contiene la información de configuración de la
conexión. Este fichero es útil en instalaciones en red que requieran modificaciones
de conexión frecuentes.
Remote Provider Especifica
el nombre de un proveedor de datos remoto cuando se utiliza una conexión
cliente/servidor
Remote Server Especifica el nombre del camino al
servidor que se va a usar cuando se establece una conexión cliente/servidor
Como ejemplo para la conexión a una base de datos Oracle, con el usuario que esa BD tiene
por defecto (scott) y el Password de este usuario (tiger) tendremos que especificar en el ConnectionString la siguiente cadena de caracteres.
‘Provider=MSDAORA.1;Password=tiger;User ID=scott;Data
Source=MADRID;’
donde el valor de Source es la cadena de conexión de
Oracle que previamente tiene que estar configurada con el SQL*Net o Net8 de
Oracle.
Si lo que queremos es crear una conexión con una base
de datos Access 2000
Si la base de datos es de Access 97 entonces
tendremos que especificar otro provider:
‘Provider=Microsoft.Jet.OLEDB.3.5;Data Source=C:\GuiadelEstudiante\db1.mdb;’
Para una base de datos SQLServer
"Provider=SQLOLEDB.1;Password=ayudas01;
User ID=ayudas01; Initial Catalog=Ayudas_M; Data Source=ayudas_sql" (en una línea única)
Como puede comprobar, resulta una tanto complicado
construir la cadena de conexión y mientras que seamos novatos en ADO podemos
tener problemas para crear esta cadena. ¿Pero es que no existe una manera más
fácil de construir esta cadena? Efectivamente. Hay un pequeño truco mediante el
cual no solo podemos crearla con un asistente, sino que además probaremos si la
conexión es satisfactoria o no.
Truco para construir la cadena de conexión.
1)
Primero tenemos que incluir el componente “Microsoft ADO data control 6.0
(OLEDB)”. Podemos hacerlo pulsando Ctrl.-T o en el menú Proyecto à Componentes.
2)
Metemos en nuestro formulario el control y pulsamos F4 para ver sus
propiedades.
3) Hacemos Click en la
propiedad ConnectionString y nos aparecerá el botón de puntos suspensivos.
Hacemos Click en el botón.
4)
Ahora nos aparece el asistente que nos mostrará 3 opciones. Utilizar un
DSN de archivo, utilizar un controlador ODBC o utilizar una cadena de conexión.
En todos los casos, a la derecha de la opción hay una opción que nos permite
seleccionar o generar el origen de los datos. Usaremos la cadena de conexión
(opción por defecto) y pulsaremos el botón generar.
5)
Al pulsar el botón generar, nos aparece otra ventana en la que tenemos
cuatro pestañas aunque únicamente necesitaremos dos de ellas para crear una
cadena de conexión correcta y probada. El resto de las pestañas forman parte de
otro capítulo exclusivo del control data de ADO, aunque le invito a que
curiosee por ellas. Seleccionaremos el proveedor de datos que queramos utilizar
y pulsaremos el botón siguiente para
pasar a la siguiente pestaña.
6)
En la Pestaña conexión, tenemos que proporcionar los datos
correspondientes al proveedor de la base de datos a la que queremos conectar.
Por ejemplo para conectar con una base de datos de tipo MS Access (MS Jet 4.0 OLEDB Provider para la versión 2000 de
Access, MS Jet 3.5 OLEDB Provider para la versión 97 de Access), tenemos que
decirle el nombre y path de la BD. Para ello podemos utilizar el botón de los
puntos suspensivos, que abrirá una ventana que permitirá seleccionar el archivo
.mdb . Si utilizamos el proveedor de datos de Oracle, tendremos que indicarle como nombre de servidor la cadena
de conexión utilizada en el SQL Net o en el Net8 de Oracle (la misma cadena que
especifica cuando se conecta a través de SQL*Plus).
En esta pestaña existen dos
opciones interesantes:
·
“Contraseña en Blanco”, si la marcamos no nos permitirá teclear la
contraseña.
·
“Permitir guardar la contraseña”, dependiendo de si está o no
seleccionada, incluirá o no en la cadena de conexión la clave del usuario. Para
la primera prueba le recomiendo que la marque. No obstante, haga diferentes
pruebas con ellas para ver los resultados.
Después de haber dado esta
información, pulsaremos el botón Probar conexión. En el caso de que haya algún
error, el asistente nos lo indicará con un mensaje.
Prueba de conexión (fallida) con Proveedor de datos de Oracle
Prueba
satisfactoria
7)
Una vez que hemos probado satisfactoriamente la conexión, pulsaremos
aceptar y volveremos a la pantalla inicial, la de las 3 opciones. La diferencia
es que ahora tenemos la cadena de conexión rellenada por el asistente. Ahora
podemos copiarla con ctrl.-C y llevarla a la parte del código donde queremos
establecer la conexión. No se olvide de que es una cadena y que cuando se
asigne a la propiedad ConnectionString debe ir entre comillas dobles.
8)
Una vez que hemos probado que funciona al abrir el objeto Connection, No
debemos olvidarnos de eliminar el control data de ADO y de quitar el componente
de nuestro proyecto, salvo que lo vayamos a utilizar para otra cosa.
Ya conocemos el truco para formar la cadena de
conexión y se la hemos introducido en la propiedad ConnectionString ¿Ya
está creada la conexión? Sí, pero todavía no sirve para obtener datos de la
base de datos. Pero ya hemos avanzado mucho. Ahora nuestro programa ya sabe al
menos, como poder abrir esa base de datos, pues conoce su nombre, usuario que
la abre y Password. Solamente queda
aplicar un método del objeto Connection: el método Open con una sintaxis que no es excesivamente difícil:
Miconexión.Open
La
conexión se va a realizar a una base de datos que está en un servidor. Este
servidor puede definirse, bien por su dirección IP o por su nombre. Lo normal
es definirlo por su nombre (Server_SQL_Mae) y no por su dirección IP. Obviamente el nombre del servidor
corresponderá a una dirección IP (Vamos a considerar una red IP estática, pues
si pretendemos entrar a explicar lo que es una red con direcciones IP asignadas
dinámicamente se nos complica la explicación). Esa dirección IP debemos indicársela
al PC en el fichero Hosts (o Lmhosts) que están en la carpeta Windows o en una
de sus subcarpetas. En estos ficheros explica como hacerlo. No se extrañe si,
una vez indicado en ese fichero, sigue sin encontrarlo. La primera conexión con
el servidor la busca mediante llamadas broadcast en la red que no siempre son
bien tratadas por los routers. En muchas ocasiones he tenido que buscar el
servidor a mano (entorno de red) y, milagros de Windows, a partir de esa
operación ya lo encuentra sin problemas.
Para seguir un poco el ejemplo que acompaña a este
capítulo, vamos a ver el código utilizado para crear la conexión. En el ejemplo
usamos una base de datos Access (No es la mejor para demostrar como funciona
ADO, pero es la que los alumnos van a tener con mayor facilidad. Una base
Oracle o SQL no se instala fácilmente en un ordenador personal)
Set
MiConexion = New ADODB.Connection
'MiConexion.ConnectionString
= "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\GuiaDelEstudiante\ADO\PruebaADO.mdb;Persist Security Info=False"
'MiConexion.Open
Ahora nuestro programa ya está en contacto con la
base de datos. Lo que falta ya lo puede suponer: crear un recordset.
Aquí vamos a ver la primera diferencia con DAO. El
recordset no lo crea el objeto Connection. Se crea él a sí mismo. Para que pueda existir un objeto Recordset
primero hay que declararlo:
Dim MiRecordset As ADODB.Recordset
(Hay que declararlo en
el sitio adecuado dependiendo del ámbito que necesite)
En el procedimiento donde se vaya a crear el recordset,
para crearlo utilizaremos la siguiente sintaxis:
Set MiRecordset = New ADODB.Recordset (Ya está creado. Pero no está abierto, ahora hay
que abrirlo)
MiRecordset.Open
"Alumnos", MiConexion, adOpenDynamic, adLockOptimistic
Ya tenemos abierto el recordset. En este caso el
recordset está formado por todos los registros con todos sus campos de la tabla
Alumnos, que está en la base de datos definida en la conexión MiConexion, es
del tipo Dynamic y el bloqueo de escritura es optimista.
Podríamos elegir ciertos registros, y solamente
unos campos. Utilizaríamos una sentencia SQL
MiRecordset.Open
"Select Alumno_Nombre, Alumno_Ape1, Alumno_Ape2 From Alumnos " _
& “Where Alumno_Nombre =
‘Luis’”, MiConexion, adOpenDynamic, adLockOptimistic
Si no hubiésemos creado previamente el objeto
Connection, podríamos crear y abrir igualmente este objeto recordset, pero, en
vez de pasarle el nombre de la conexión (MiConexion) le pasaríamos la cadena de
conexión usada para crear ese objeto Connection.
Set
MiRecordset = New ADODB.Recordset
MiRecordset.Open "Alumnos",
"Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\GuiaDelEstudiante\ADO\PruebaADO.mdb;Persist Security
Info=False", adOpenDynamic, adLockOptimistic
(Es solamente una línea. Ha sido Word quien la ha troceado)
Ahora ya podemos presentar los
campos del recordset, usando la sintaxis que ya conocemos de DAO
TbNombre = “” &
MiRecordset!Alumno_Nombre
TbApe1 = “” &
MiRecordset!Alumno_Ape1
TbApe2 = “” &
MiRecordset!Alumno_Ape2
Hagamos una pequeña pausa. Observe que hay
diferencias de trabajar con ADO o hacerlo con DAO.
Con DAO.
Declarar MiSesion, MiBase y
MiRecordset
Dim MiSesion as Workspace
Dim MiBase As DataBase
Dim MiRecordset as Recordset
Crear el objeto Workspace, el
objeto DataBase y el objeto Recordset
Set MiSesion = Workspaces(0)
Set MiBase =
MiSesion.OpenDatabase (“C:\GuiadelEstudiante\Alumnos.Mdb”)
Set MiRecordset = MiBase.OpenRecordset (“Alumnos, dbOpenDynaset)
Con ADO (Creando
el objeto Connection)
Declarar MiConexion y
MiRecordset
Dim MiConexion As
ADODB.Connection
Dim MiRecordset As ADODB.Recordset
Crear la conexión y ponerle la
cadena de conexión en su propiedad ConnectionString
Set
MiConexion = New ADODB.Connection
MiConexion.ConnectionString
= "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\GuiaDelEstudiante\ADO\PruebaADO.mdb;Persist
Security Info=False"
Abrir el objeto Connection
MiConexion.Open
Crear el objeto recordset
Set MiRecordset = New ADODB.Recordset
Abrir el objeto Recordset
MiRecordset.Open
"Alumnos", MiConexion, adOpenDynamic, adLockOptimistic
Con ADO (Sin
crear el objeto Connection)
Declarar MiRecordset
Dim MiRecordset As ADODB.Recordset
Crear el Recordset
Set
MiRecordset = New ADODB.Recordset
Abrir
el Recordset
MiRecordset.Open "Alumnos", "Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=C:\GuiaDelEstudiante\ADO\PruebaADO.mdb;Persist Security
Info=False", adOpenDynamic, adLockOptimistic
Observe siempre que tanto en las declaraciones del
objeto Connection y del objeto Recordset, como en su creación, debemos anteponer siempre la palabra ADODB
Tanto el objeto Recordset como el objeto
Connection se deberán cerrar cuando ya no se utilicen, o al menos, al cerrar la
aplicación. Esto es tanto más necesario cuanto mayor sea la seguridad de la
base de datos que vamos a utilizar. En algunas bases de datos, dejar una sesión
abierta significa dejar una aplicación zombie ejecutándose en el servidor, que
habrá que cerrar desde su propio sistema operativo. Este problema no le va a
ocurrir utilizando Access, pero como ya se dijo al principio, Access no es el
mejor ejemplo de utilización de ADO. Para cerrar una sesión y un recordset
utilizaremos el método Close
MiRecordset.Close
MiSesion.Close (Recuerde
que debe cerrar antes el recordset que la conexión)
¿Qué pasa
con el equivalente del Workspace?
Cuando resumíamos en la página anterior el código
a usar si usábamos DAO o ADO, parecía (aunque no fuese cierto) que podíamos
asimilar estos objetos
DAO ADO
Recordset Recordset
DataBase Connection
WorkSpace ¿
Efectivamente el Workspace no tiene algo que
pudiésemos decir “equivalente” en
ADO. Esto es debido a que ADO ya
considera que el acceso desde los usuarios lo gestiona directamente la base de
datos. Recuerde que el Workspace en DAO era una “sesión de trabajo” de la base
de datos, donde podíamos asociar un Workspace a cada usuario. ADO ya le pasa a
la BD el nombre del usuario y su Password para que la propia base de datos
quien autorice a ese usuario.
Algunas
cosas que le van a ocurrir cuando ya haya creado el recordset.
El empleo de bases de datos complejas en cuanto a
seguridad nos va a obsequiar con limitaciones a los recordsets que vamos a
abrir en ADO. Y además esas sorpresas
van a ser distintas si usa uno u otro tipo de base de datos. (nos centraremos
solamente en Oracle y SQLServer.
Access, con la modestia que le
caracteriza, no va a dar ningún problema.)
Los recordsets abiertos mediante una consulta SQL
(aquellos en los que seleccionamos parte de los registros mediante Select
… Where van a crearse solo de lectura. Independientemente de los parámetros
que le pasemos a la hora de crearlos. La descripción del error va a ser algo
así como que el cursor es solamente de lectura. También observará con frecuencia, cuando intente ir a un registro
anterior al actual, MiRecordset.MoveFirst, p.e.) que le enviará un error
diciendo que el cursor es solamente de avance hacia a delante. Estos efectos
los observará también cuando use la instrucción SQL Order By. No hay que arrojar la toalla solamente por esto. Cuando
eso ocurra, lo que hay que hacer es volver a crear el recordset de forma que
acepte escritura y movimiento hacia atrás.
Eso generalmente se logra abriendo el recordset con todos los registros
de la tabla, e incluyendo en él todos
los campos.
En vez de :
MiRecordset.Open "Select Alumno_Nombre,
Alumno_Ape1, Alumno_Ape2 From Alumnos " _
& “Where Alumno_Nombre =
‘Luis’”, MiConexion, adOpenDynamic, adLockOptimistic
usar esta otra alternativa:
MiRecordset.Open "Alumnos", MiConexion,
adOpenDynamic, adLockOptimistic
Posiblemente necesitemos crear dos recordsets en
un mismo procedimiento. Por ejemplo, es muy típico tener que buscar el último
registro para ver el último número de un identificador de registro (Alumno_ID)
y poner en este campo, al registro que vamos a crear, un número igual a ese más
1. En ese caso, abriríamos el recordset usando la sentencia Order By
Alumno_ID. Cuando queramos introducir
un nuevo registro mediante:
MiRecordset.AddNew nos
dirá que el cursor (el recordset, para entendernos) es solamente de lectura. La
solución es, abrir el recordset con la sintaxis anterior, leer el número de
Alunmo_ID, cerrar el recordset, crear otro recordset con el mismo nombre, usando la sintaxis:
MiRecordset.Open
"Alumnos", MiConexion, adOpenDynamic, adLockOptimistic
Ahora ya nos permitirá usar el método AddNew. Basta con añadir las líneas de código
adecuado para introducir los valores en cada campo:
Mirecordset.AddNew
MiRecordset!Alumno_ID = Valor numérico
MiRecordset!Alumno_Nombre = Valor string
Etc.
….
MiRecordset.Update
No renuncie nunca a intentar hacer esto. No
siempre funciona. Pero esto es mucho más sencillo que introducir los datos “a
capón” utilizando la instrucción SQL Insert que ya veremos más
adelante. SQLServer es bastante más
dócil que Oracle para usar el método AddNew.
A este respecto, hay que citar
la propiedad CursorLocation que veremos más adelante. Si creamos un cursor lado
cliente, seguramente nos permitirá utilizar más opciones (entre ellas AddNew)
que si lo establecemos de lado servidor. Tenga en cuenta que si usa un cursor
lado cliente, el recordset no se actualiza cuando otro usuario realiza
modificaciones en la base.
Modificar
datos mediante EDIT
En ADO no hace falta usar Edit para modificar los datos del registro actual. Edit
no existe en ADO. Para modificar un dato basta con poner el mismo
código que utilizábamos en DAO, pero sin comenzar por la línea
Mirecordset.Edit. Colocándonos en el registro a modificar pondremos:
MiRecordset!Alumno_Nombre = “Pedro”
MiRecordset!Alumno_Ape1 = “Perez”
MiRecordset.Update
De cualquier forma, esto tampoco tiene porque
funcionar en todas las bases de datos. En ese caso tendremos que recurrir, al
igual que para un registro nuevo, a las instrucciones SQL, que en este caso
será Update. Pero ya lo veremos
más adelante. Hasta ahora solamente he
querido usar el código más simple para que pueda empezar con ADO, y sobre todo,
para que vea que esta es una técnica completamente accesible, aunque, dadas las
grandes prestaciones que tiene, un poco más adelante se va a complicar algo.
Ya ha visto que podemos trabajar perfectamente con
recordsets, tal como lo hemos hecho con el DAO de toda la vida. Pero ya lo comentábamos al principio, parece
que hay que adornar lo obvio para que no lo parezca tanto. Y ahí viene el Objeto
Command, que como habrá podido ver en la figura de la Jerarquía de los objetos
ADO, es un objeto que aún no sabemos lo que hace.
El objeto
Command lo que va a hacer es crear un recordset. O también, meter “a capón” un nuevo registro, o borrarlo,
utilizando directamente instrucciones SQL.
Hay que darse cuenta que ADO trabaja con una gran diversidad de bases de
datos, y no todas trabajan igual. Por eso, muchas veces fallan operaciones tan
sencilla como añadir un nuevo registro con el método AddNew del recordset
MiRecordset.AddNew
Y hay que emplear una instrucción SQL: INSERT
En estos casos, en ADO utilizamos el método
EXECUTE sobre el objeto Connection.
Creamos una variable, StrIntroducir, con el contenido de la instrucción
SQL y ejecutábamos esa instrucción mediante Execute
StrIntroducir
= "Insert Into INT_DOCUMENTOS " _
&
"(CL_DOC,NOM_DOC,TITULO_DOC,AUTOR_DOC,CL_TEMA_DOC,CL_DPT_DOC,” _
&
“L_TIPO_DOC,FICH_DOC,FECHA_EMISION_DOC,ULTIMA_HORA_DOC,VISIBLE_DOC)"_
& "Values (" & NumeroDocumento & ",'" &
TbTitulo & "','" & TbTitulo & "','" &
TbTitulo.Tag _
&
"',19,2,1,'" & HRefPrensa & "/" & TbNombFichTIF
& "','" & Date & "',0,1)"
ConexBDPrensa.Execute StrIntroducir
Esta línea (StrIntroducir) es el contenido de la
propiedad CommandText de un objeto Command
de ADO. Ni más ni menos que una instrucción que queremos realizar sobre la
BD. Un objeto Command tiene pocas cosas
más. Como objeto ADO que es tiene sus
propiedades y métodos. Pero en esencia es lo que acaba de ver con la
instrucción EXECUTE del objeto Connection. Lo que pasa, que ADO lo han hecho
muy organizado, y por eso tiene la categoría de Objeto. Es hacer lo mismo, utilizando las mismas
expresiones, pero dándole más cuerpo.
Con la instrucción anterior, lo que hacíamos era
añadir un registro. Si lo que queremos
hacer es crear un recordset, la instrucción SQL comenzaría por “Select * From
….” Y el método EXECUTE devolvería un Recordset
StrIntroducir = “Select * From Alumnos Where
Apellido1 = ‘Suarez’”
Podemos crear un recordset (MiRecordset,
previamente declarado como tal) con esta instrucción
MiRecordset = ConexBDPrensa.Execute StrIntroducir
O con estas otras
Set MiComando as New
ADODB.Command
MiComando.ActiveConnection =
ConexBDPrensa
MiComando.CommandText =
“Select * From Alumnos Where Apellido1 = ‘Suarez’”
MiRecordset =
MiComando.Execute
Verá el ejemplo completo al final del capítulo.
Ahora, tras la explicación informal de cómo se
crea una conexión y un recordset en ADO, y que es un Command, vamos a entrar a
conocer sus propiedades y métodos. Al
final, y con un buen ejemplo realizado de varias formas, entenderá
perfectamente la forma de trabajar con ADO.
ADO. El Objeto Connection
Un
objeto Connection representa una
conexión abierta con un origen de datos. Ya hemos visto como crear un objeto
Connection, por lo que vamos a pasar directamente a ver sus objetos,
colecciones, propiedades y métodos.
Como puede verse en la figura, el Objeto Connection
tienen los objetos Command y Recordset, y la colección Errors.
El Objeto
Recordset es el recordset de toda la vida: un conjunto de registros que
contienen datos. El Objeto Recordset, aunque pertenece al objeto Connection,
puede crearse sin que exista previamente un objeto Connection. Esta es una de
las propiedades de los objetos ADO: no necesita cumplir estrictamente con la
jerarquía.
El Objeto
Command es una definición de un comando específico que se piensa ejecutar
contra un origen de datos. Los objetos Command sirven para tener almacenadas
operaciones de acceso a datos y usarlas en el momento adecuado, simplemente
citándolas. Lo que obtenemos de un objeto Command es, o un recordset (verá que
no merece la pena usar un objeto Command para crear un recordset, puesto que se
pueden crear directamente) o una operación que afecte a los registros de la
base de datos (añadir registros, borrarlos, si es que no se deja hacer eso
mediante recordsets)
La Colección
Errors es el conjunto de errores generados por el proveedor de datos ante
el fallo de una operación de acceso. La colección Errors se refiere únicamente
a los errores generados por el proveedor, no a los fallos interceptables
producidos por el programa, que deben ser tratados de la forma habitual:
mediante Err
Propiedades
del Objeto Connection (Lea
esto de las propiedades sin complicarse demasiado la vida. Las realmente
importantes verá que están advertidas debidamente)
Las propiedades del objeto Connection
dependen de cada proveedor. No todos se comportan de igual forma, por lo que
cada propiedad debe condicionarse a si el proveedor es capaz de ofrecerla.
Propiedad Attributes
Es un Long. Acepta dos valores o la suma
de los dos:
adXactCommitRetaining
adXactAbortRetaining
Estos atributos condicionan el modo de
operación de la conexión con los métodos CommitTrans y RollBackTrans.
Propiedad CommandTimeout
Indica, en segundos, el intervalo de
espera para que se ejecute un comando (Objeto Command) antes de que finalice el
intento y se genere un error. Es un Long. El valor predeterminado es 30.
Propiedad ConnectionTimeout
Indica, en
segundos, el intervalo de espera para establecer una conexión antes de que
finalice el intento y se genere un error. Es un Long y el valor predeterminado
es 15.
Propiedad ConnectionString (IMPORTANTE)
Es una cadena de caracteres que contiene
la información que se utiliza para establecer una conexión a un origen de
datos. (Vea la explicación amplia más
atrás)
La cadena de conexión tiene varios argumentos,
todos ellos separados por un punto y coma (;) de la forma
argumento1 = valor; argumento2 = valor; argumento3 =
valor etc.
ADO procesa solamente cuatro argumentos:
Provider, File Name, Remote Provider y Remote Server. Los demás argumentos los pasa al proveedor para que el los
procese (Usuario, Password, etc)
Si al emplear el método Open se utiliza el
parámetro Connection String, este parámetro utilizado en el método Open
sustituirá a cualquier otro existente anteriormente. Una vez abierta la
conexión, esta propiedad no se puede cambiar puesto que es solamente de
lectura.
Los
argumentos File Name y Provider son excluyentes.
Propiedad CursorLocation (IMPORTANTE)
Establece o devuelve la posición de un
servicio de cursores. Es un Long, y acepta las siguientes constantes:
AdUseNone No se usan
servicios de cursor. (Esta constante es obsoleta y aparece únicamente por
compatibilidad con versiones anteriores.)
AdUseClient Usa
cursores del lado del cliente.
AdUseServer Predeterminado.
Usa cursores del lado servidor.
Esta propiedad parece que no dice nada. Y es
sumamente importante.
Los cursores son, por decirlo de alguna manera, los
mecanismos de la base de datos donde se crean los recordsets. Se estará dando
cuenta que las bases de datos que tienen cursores son ya bases de datos con
mecanismos propios para la creación de recordsets. (SQL Server u Oracle, p.e.)
Estas bases de datos trabajan como aplicaciones cliente – servidor. Tienen en
el servidor, aparte de los datos, la mayoría de sus recursos. En el cliente
tienen prácticamente los recursos de conectividad, y poco más. Esta
conectividad permite enviar desde el cliente una petición a la base de datos
alojada en el servidor. Esa petición será el resultado por ejemplo, de una
sentencia SQL. Al recibirla el servidor, gestionará la obtención de los
resultados y una vez que los haya conseguido viene su primera duda: ¿Dónde los
almaceno? Puede almacenarlos en el servidor, y cada vez que necesitemos un
nuevo registro, por ejemplo al ejecutar la sentencia MiRecordset.MoveNext, el
cliente se lo indica al servidor y este le envía el nuevo registro. También puede almacenar los datos obtenidos
en el cliente, y de esta forma el cliente puede moverse con entera libertad a
lo largo de los registros del recordset. Puede hasta contarlos y saber en que
posición está. La diferencia entre uno y otro sistema es que en el primer caso
el tráfico por la red es mínimo (solamente se envía la información
estrictamente necesaria) y en el segundo caso, se envía mucha información de un
golpe, la correspondiente a todos los registros del recordset,
independientemente de si se va a usar en el servidor o no.
Considerando el tráfico generado, parece que es mejor
crear los cursores en el lado servidor. Pero esto trae también sus
dificultades. Nos priva de muchas propiedades del recordset. Una propiedad muy
usada, AbsolutePosition, no la tienen los cursores de lado servidor,
circunstancia que no nos debe sorprender, ya que al no estar todos los
registros en el cliente, éste, aunque disponga de todos los datos guardados en
todos los campos de un determinado registro, no puede saber que posición ocupa
ese registro dentro de la totalidad de registros del recordset. Por lo tanto,
usar cursores de lado cliente o lado servidor será siempre una decisión a tomar
dependiendo de la velocidad de la red, de la memoria disponible en el cliente, de
la complejidad del programa, etc.
Recuerde que por defecto, ADO crea cursores de lado
servidor. Para que la conexión le cree todos los cursores de lado cliente basta
ejecutar la instrucción:
MiConexion.CursorLocation
= adUseClient
Si desea hacer transacciones, deberá crear cursores
del lado servidor, ya que los de lado cliente no las admiten. Comprenderá según
vaya programando y encontrándose con problemas, que esta propiedad es
absolutamente importante.
Este valor debe establecerlo antes de
crear la conexión. De esta forma, todos los cursores creados con esa conexión
serán de lado cliente o lado servidor, según haya elegido. Pero muchas veces
sería ideal que unos recordsets tuvieran el cursor de un tipo y otros de otro. Los recordsets también tienen esta
propiedad, por lo que puede elegir el lado deseado para cada recordset
utilizando esta propiedad aplicada no a la conexión, sino al recordset.
El número
de registros que el servidor envía al cliente, cuando el cursor es de lado
servidor, se controla mediante la propiedad CacheSize del recordset. Lo verá más adelante.
Propiedad DefaultDatabase
Establece la base de datos predeterminada para un
objeto Connection. Es un string con el nombre de la base de datos por defecto
de esa conexión. Solamente es válida con aquellos proveedores que permiten
varias bases de datos por conexión.
IsolationLevel
Esta propiedad afecta al comportamiento de
un objeto Connection durante una transacción. Una vez establecida esta
propiedad, solamente será efectiva cuando se invoque el método
BeguinTrans. Vea la ayuda para mayor
información de los valores posibles.
Propiedad Mode,
Establece
los permisos disponibles para modificar datos en un objeto Connection.
Los
valores aceptados son:
AdModeUnknown Predeterminada.
Indica que los permisos no se han establecido aún o que no se pueden determinar.
AdModeRead Indica
que son permisos de sólo lectura.
AdModeReadWrite Indica que son permisos de lectura/escritura.
AdModeShareDenyRead Impide
que otros abran una conexión con permisos de lectura.
AdModeShareDenyWrite Impide
que otros abran una conexión con permisos de escritura.
AdModeShareExclusive Impide
que otros abran una conexión.
AdModeShareDenyNone Impide que otros abran una conexión con
cualquier tipo de permiso.
Sólo puede establecer la propiedad Mode cuando el objeto Connection está cerrado. Cuando se usa
en un objeto Connection del lado del
cliente, la propiedad Mode sólo se
puede establecer a adModeUnknown.
Propiedad Provider
Es un string que indica el nombre del
proveedor de un objeto Connection. Si no se especifica ningún proveedor, la
propiedad tendrá el valor predeterminado MSDASQL (Proveedor de Microsoft OLE DB
para ODBC).
Propiedad State
Devuelve
el estado del objeto Connection: abierto (adStateOpen = 1) o cerrado
(adStateClosed = 0).
Propiedad Version
Devuelve
el número de versión de ADO. Es un
String.
Métodos del Objeto Connection
Métodos BeginTrans, CommitTrans y
RollbackTrans
Estos métodos
de transacción administran el proceso de la transacción dentro de un objeto
Connection de la forma siguiente:
·
BeginTrans:
inicia una nueva transacción.
·
CommitTrans:
guarda las modificaciones y termina la transacción actual. También puede
iniciar una nueva transacción.
·
RollbackTrans:
cancela las modificaciones efectuadas durante la transacción actual y termina
la transacción. También puede iniciar una nueva transacción.
Después de invocar el método BeginTrans, el proveedor ya no aplicará inmediatamente las modificaciones hasta que invoque CommitTrans o RollbackTrans para terminar la transacción. Los métodos BeginTrans, CommitTrans y RollbackTrans
no están disponibles en los objetos Connection
del lado del cliente.
Método Cancel
Cancela la
ejecución de una llamada asíncrona pendiente a un método Execute u Open.
Sintaxis NombreConection.Cancel
El método Cancel
se utiliza para terminar la ejecución de una llamada asíncrona a un método Execute o Open (es decir, el método fue invocado con la opción adAsyncConnect, adAsyncExecute o adAsyncFetch).
Cancel devolverá un error de
ejecución si no se utilizó adAsyncExecute
en el método que quiere terminar.
Close, método
Cierra el
objeto Connection.
Sintaxis NombredelObjetoConnection.Close
El cierre de un objeto Connection mientras hay objetos Recordset abiertos en la conexión cancela las modificaciones
pendientes en todos los objetos
Recordset. El cierre explícito de un objeto Connection (llamando a su método Close) mientras una transacción está en progreso genera un error.
Si un objeto Connection cae fuera
del alcance mientras la transacción está en progreso, ADO cancela
automáticamente la transacción.
El cierre de un objeto Connection no lo elimina de la
memoria; puede modificar los valores de sus propiedades y volver a abrirlo más
tarde. Para eliminar completamente un objeto de la memoria, establezca la
variable de objeto a Nothing.
Set NombredelObjetoConnection = Nothing
Método Execute (Vea
también Método Execute para el objeto Command)
Ejecuta una consulta, instrucción SQL,
procedimiento almacenado especificados o texto específico del proveedor.
Sintaxis (Para una cadena de comando que no
devuelva filas):
conexión.Execute CommandText, RecordsAffected, Options
(Para una
cadena de comando que devuelva filas):
Set MiRecordset = connection.Execute (CommandText, RecordsAffected,
Options)
(MiRecordset
debe ser una variable declarada tipo ADODB.Recordset)
CommandText Es un String que contiene la
instrucción SQL, el nombre de la tabla, el procedimiento almacenado o el texto
específico del proveedor que se va a ejecutar.
RecordsAffected Opcional.
Una variable Long en la que el proveedor
devuelve el número de registros afectados por la operación.
Options Opcional. Una constante o
valor Long que indica cómo debe evaluar el proveedor el argumento
CommandText. Puede ser uno de los siguientes valores.
Constante |
Descripción |
adCmdText |
Indica
que el proveedor tiene que evaluar CommandText como definición
textual de un comando, como una instrucción SQL. |
adCmdTable |
Indica
que ADO tiene que generar una consulta SQL para devolver todas las filas de
la tabla mencionada en CommandText. |
adCmdTableDirect |
Indica
que el proveedor tiene que devolver todas las filas de la tabla mencionada en
CommandText.
|
adCmdTable |
Indica
que ADO tiene que generar una consulta SQL para devolver todas las filas de
la tabla mencionada en CommandText. |
adCmdStoredProc |
Indica
que el proveedor tiene que evaluar CommandText como procedimiento
almacenado. |
adCmdUnknown |
Indica
que el tipo de comando en CommandText es desconocido. |
adAsyncExecute |
Indica
que el comando se tiene que ejecutar de forma asíncrona. |
adAsyncFetch |
Indica
que el resto de las filas siguientes a la cantidad inicial especificada en la
propiedad CacheSize tiene que ser
recuperada de forma asíncrona. |
Cuando
esta operación termina se genera el evento ExecuteComplete.
Método Open (IMPORTANTE)
Abre una
conexión a un origen de datos.
Sintaxis MiConnection.Open ConnectionSTring, UserID, Password, Options
MiConnection.Open
Los parámetros ConnectionSTring, UserID,
Password, Options puede introducirlos
previamente a abrir la conexión, y utilizar la segunda sintaxis cuando desee
abrirla realmente. Estos parámetros se le pasan en la cadena de conexión:
ConexBDPrensa.ConnectionString
= "Provider=MSDAORA.1;User ID=INTRANET;” & _
“Password=INTRANET;Data
Source=intranet;Persist Security Info=False"
Options Opcional.
Puede ser una de las constantes siguientes:
AdConnectUnspecified Abre la conexión de forma sincronía
AdAsyncConnect Abre la conexión de forma asíncrona
Cuando se usa un objeto Connection del
lado del cliente, el método Open no establece realmente una conexión con el
servidor hasta que se abre un Recordset del objeto Connection.
Colecciones
del Objeto Connection
Colección Errors
Contiene todos los objetos Error creados en respuesta a un único fallo relacionado con el
proveedor. Cada objeto Error
representa un error específico del proveedor, no un error ADO. Los errores ADO
se exponen al mecanismo de control de excepciones en tiempo de ejecución. Por
ejemplo, en Microsoft Visual Basic, cuando ocurre un error específico de ADO
dispara un evento On Error y aparece
en el objeto Err.
Cuando otra operación ADO genera un error, se borra
la colección Errors y el nuevo
conjunto de objetos Error se coloca
en la colección Errors. Las
operaciones ADO que no generan un error no tienen ningún efecto sobre la
colección Errors. Para borrar
manualmente la colección Errors
utilice el método Clear.
Cada objeto Error
de la colección, nos dará información sobre un error producido en la conexión.
Sus propiedades son las siguientes:
Debido a que este objeto será de gran utilidad a
continuación se incluye un ejemplo de su uso.
Ejemplo
del tratamiento de errores:
El resultado de la ejecución es el
siguiente:
Como puede observarse, algunas de las propiedades no
devuelven los valores esperados: NativeError vale 0 cuando debería valer –1017,
que es el error asociado de Oracle. Aún así podemos capturar el código del
error desde la cadena de caracteres description.
Con este comentario se pretende sugerir que se realicen pruebas con el
proveedor de datos que vayamos a utilizar para conocer su comportamiento respecto
a este objeto error y dónde nos devuelve los códigos.
Observese en el código que la declaración de MiError
se hace con ADODB.Error
Es el conjunto de objetos
Property
Objeto Property
Un objeto Property
representa una característica dinámica de un objeto ADO que está definida
por el proveedor.
Los
objetos ADO tienen dos tipos de propiedades: intrínsecas y dinámicas.
Las propiedades intrínsecas son aquellas propiedades
implementadas en ADO e inmediatamente disponibles para cualquier nuevo objeto,
utilizando la sintaxis Objeto.Propiedad. No aparecen
como objetos Property en la
colección Properties de un objeto, de forma que aunque puede modificar sus
valores, no puede modificar sus características.
Las propiedades dinámicas están definidas por el
proveedor de los datos y aparecen en la colección Properties del objeto ADO apropiado. Por ejemplo, una propiedad
específica del proveedor puede indicar si un objeto Recordset acepta
transacciones o actualizaciones. Estas propiedades adicionales aparecerán como
objetos Property en la colección Propiedades de dicho objeto Recordset. A las propiedades dinámicas
se les puede hacer referencia sólo a través de la colección, utilizando la
sintaxis Objeto.Properties(0)
u Objeto.Properties("Name").
Un objeto Property dinámico tiene cuatro
propiedades incorporadas propias:
·
La propiedad Name
es una cadena que identifica la propiedad.
·
La propiedad Type
es un entero que especifica el tipo de datos de la propiedad.
·
La propiedad Value
es un variant que contiene el valor de la propiedad.
·
La propiedad Attributes
es un valor Long que indica características de la propiedad específicas del
proveedor.
El objeto Recordset
representa un conjunto de registros. El recordset en ADO puede crearse
abriéndolo, tomando todos los registros de una tabla o seleccionándolos con una
consulta SQL, o ejecutando un comando que contienen el nombre de esa tabla o la
consulta. En un momento determinado, el objeto Recordset sólo hace referencia a un único registro dentro del
conjunto de registros, llamado registro actual.
El recordset de ADO tiene propiedades
iguales al recordset de DAO, pero tienen otras que no tienen el de DAO. Se van
a estudiar todas, profundizando más en las que son particulares del recordset
ADO.
Propiedad AbsolutePosition (ADO)
Especifica la posición ordinal del
registro actual de un objeto Recordset. Esta propiedad devuelve un Long con el
número de orden del registro. Es posible que el recordset no acepte esta
propiedad, dependiendo del proveedor de datos, y del tipo de cursor (lado cliente o lado servidor. El cursor tipo lado servidor no permite esta
propiedad) Esta propiedad devolverá 1
cuando el registro actual sea el primer registro del recordset.
Propiedades BOF y EOF
Indican si la posición del puntero del Recordset está
apuntando a un registro anterior al primero (BOF = True) o posterior al último
(EOF = True). Esta propiedad siempre la podremos mirar, independientemente si
el cursor es lado cliente o lado servidor.
Propiedad ActiveConnection (ADO)
Indica a qué objeto Connection pertenece
actualmente el objeto Recordset especificado. Devuelve un string con el nombre
del objeto Connection.
Propiedad Bookmark
Devuelve un marcador que identifica unívocamente al
registro actual de un objeto Recordset o establece el registro actual de un
objeto Recordset al registro
identificado por un marcador válido. El valor del Bookmark hay que introducirlo
en una variable tipo Variant.
La propiedad Bookmark solo podrá establecerse cuando
el proveedor lo permita. Puede utilizarse el método Supports para averiguarlo.
Cuando el recordset es de lado cliente, siempre está disponible el
Bookmark.
Propiedad CacheSize
Indica el
número de registros del objeto Recordset que están en la memoria caché local.
Es un Long de lectura y escritura. El valor predeterminado es 1.
Esta propiedad nos permite conocer cuantos registros
están en la memoria local. Si ponemos esta propiedad por ejemplo a 10, al abrir
la primera vez el objeto Recordset,
el proveedor recupera los 10 primeros registros en la memoria local. A medida
que se desplaza por el objeto Recordset,
el proveedor devuelve los datos desde el búfer de memoria local. Tan pronto
como pasa del último registro de la memoria caché, el proveedor recupera los 10
registros siguientes desde el origen de datos y los carga en la memoria caché.
Los registros recuperados desde la memoria
caché no reflejan los cambios concurrentes que hagan otros usuarios en el
origen de datos. Para forzar una actualización de todos los datos en la memoria
caché, debe usarse el método Resync.
Propiedad MaxRecords
Indica el número máximo de registros que
se devuelven a un Recordset desde una consulta. Es un Long y el valor
predeterminado es 0, que significa sin límite (Obtienen todos los registros).
Esta propiedad es de lectura y escritura cuando el recordset está cerrado, y
solamente de lectura cuando está abierto.
Esta propiedad debe usarse solamente cuando se prevé
que se pueden obtener un número muy grande de registros. Es prudente tomar
medidas frente a aquellas operaciones en las que el ordenador pueda meterse en
un proceso excesivamente largo o que ocupe más recursos de los disponibles.
Estas cosas son las que suelen “colgar” al ordenador y en las que es muy
frecuente echarle luego la culpa a Windows
Si estamos frente a una base de datos con todos los datos de los
afiliados a la Seguridad Social, no es del todo prudente crear un recordset mediante
esta sentencia:
SELECT
* From Afiliados Where Apellido1 = ‘Fernandez’
Incluso las hay peores:
SELECT
* From Afiliados
A nadie se le ocurriría, pero puede surgir
involuntariamente cuando ese acceso se realiza desde un puesto de operación
público (Acceso desde Internet por ejemplo). Con la propiedad MaxRecords
puede limitar el número de registros obtenidos. Posiblemente no llegue a
obtener el dato deseado, y se vea en la obligación de realizar la misma
consulta sucesivas veces hasta encontrarlo.
Propiedad CursorLocation
Establece
o devuelve la posición de un servicio de cursores. Es idéntica a la propiedad del mismo nombre vista más atrás con
todo detalle para el objeto Connection.
Propiedad CursorType
Indica el
tipo de cursor que se usa en un objeto Recordset. Es de lectura y escritura si
el recordset está cerrado, y solo de lectura si está abierto. Puede tomar uno
de los siguientes valores:
AdOpenForwardOnly Predeterminado.
Idéntico a un cursor estático, excepto sólo permite desplazarse hacia delante
en los registros. Esto mejora el rendimiento en situaciones en las que sólo se
quiere pasar una vez por cada registro.
En muchas ocasiones es
necesario moverse por el recordset hacia delante y hacia atrás. Este tipo de
cursor solamente permite moverse hacia delante. Tenga presente que este es el
tipo predeterminado.
AdOpenKeyset Cursor
de conjunto de claves. Igual que un cursor dinámico, excepto que no se pueden
ver los registros que agregan otros usuarios, aunque los registros que otros
usuarios eliminan son inaccesibles desde su conjunto de registros. Los cambios
que otros usuarios hacen en los datos permanecen visibles.
AdOpenDynamic Cursor
dinámico. Las incorporaciones, cambios y eliminaciones que hacen otros usuarios
permanecen visibles, y se admiten todo tipo de movimientos entre registros, a
excepción de los marcadores si el proveedor no los admite. Es el equivalente en DAO al tipo Dynaset
AdOpenStatic Cursor
estático. Una copia estática de un conjunto de registros que se puede usar para
buscar datos o generar informes. Las incorporaciones, cambios o eliminaciones
que hacen otros usuarios no son visibles.
Es el equivalente en DAO al tipo Snapshot
NOTA.
Si un proveedor no admite el tipo de cursor solicitado, el proveedor
puede que devuelva otro tipo de cursor. La propiedad CursorType cambiará para coincidir con el tipo de cursor en uso
cuando el objeto Recordset se abra.
Para comprobar la funcionalidad específica del cursor devuelto, use el método
Supports. Cuando cierre el Recordset,
la propiedad CursorType volverá a su
configuración original.
Propiedad LockType
Indica el tipo de bloqueo que se pone en
los registros durante el proceso de edición. Establece también si el recordset
se actualiza registro a registro o por lotes. Este último sistema permite
realizar varios cambios en el recordset y mantenerlos en la caché durante
cierto tiempo, y proceder a la actualización de todos los cambios pendientes en
una sola operación. Esto es muy importante cuando se está trabajando con una
base de datos situada en un servidor con un acceso lento (conexión vía
Internet, por ejemplo)
Los
valores de la propiedad LockType pueden ser:
AdLockReadOnly Predeterminado. Sólo lectura—no puede modificar los datos
AdLockPessimistic Bloqueo pesimista, registro a registro:
el proveedor hace lo necesario para
asegurar la modificación correcta de los registros, generalmente bloqueando registros
en el origen de datos durante todo el proceso de modificación. Este valor solamente
es válido si el cursor (Propiedad CursorLocation) esta establecido
a lado servidor.
AdLockOptimistic Bloqueo optimista, registro a registro:
el proveedor usa bloqueo optimista,
bloqueando registros sólo cuando llama al método Update.
AdLockBatchOptimistic Actualizaciones optimistas por
lotes: requerido para el modo de actualización por lotes como
contraposición al modo de actualización
inmediata.
Propiedad EditMode
Indica el
estado de modificación del registro actual. Es solamente de lectura. Devuelve
uno de las siguientes constantes:
AdEditNone Indica que no hay ninguna operación
de modificación en ejecución.
AdEditInProgress Indica
que los datos del registro actual se han modificado pero que no se han guardado.
AdEditAdd Indica
que se ha invocado el método AddNew y que el registro situado actualmente en el búfer de copia es un nuevo registro que
no se ha guardado
en la base de datos.
AdEditDelete Indica que el registro actual se ha
eliminado.
Propiedad Filter
Esta propiedad solamente la tienen los
recordset ADO. Y es que ADO presupone que está obteniendo datos de una base de
datos alojada en un servidor y que la comunicación entre servidor y cliente
puede ser especialmente lenta. Mediante Filter puede descartar registros que no
cumplan una determinada condición. En realidad lo que hacemos mediante Filter
es crear un nuevo Recordset a partir de otro Recordset.
La propiedad Filter se utiliza también
para actuar sobre determinados registros en varios métodos del recordset
(Resync, Save, …) pero no se va a explicar en este manual la explicación de la
utilización de esta propiedad en esos métodos, ya que el nivel del programador
que utiliza esos recursos debe ser elevado. Le reservamos por tanto la
posibilidad de conocerlo directamente desde la ayuda de Visual Basic, que en
este caso es bastante buena.
De momento lo que vamos a hacer con Filter
es crear un nuevo recordset ¿Por qué no creamos directamente el nuevo recordset
utilizando una sentencia SQL que lleve implícito ese filtro?
Personalmente no me gusta utilizar la
propiedad Filter, y prefiero crear un nuevo recordset. Creo que solamente lo he
usado para rellenar un MSHFlexGrid con parte de los datos del recordset que uso
en una parte de la aplicación. Veamos
un ejemplo:
(MiConexion
es una conexión ya creada)
Dim RsInicial As ADODB.Recordset
Dim RsFiltrado As ADODB.Recordset
Set RsInicial = New ADODB.Recordset
Set RsFiltrado = New ADODB.Recordset
RsInicial.Open "Autores", MiConexion, adOpenDynamic,
adLockOptimistic
‘Este es el recordset que uso para muchas
cosas dentro de la aplicación. Ahora quiero presentar en un MSHFlexGrid
solamente los datos de los autores de nacionalidad española. Filtro el
recordset anterior utilizando un criterio de igualdad de un campo: Nacionalidad
RsFiltrado = RsInicial.Filter
(“Nacionalidad = ‘Española’”)
‘Ahora ya
podemos aplicar este recordset al MSHFlexGrid:
Set MSHFlexG1.Recordset = RsFiltrado
‘Y cuando
queremos presentar todos los autores, basta con poner la línea:
Set MSHFlexG1.Recordset = RsInicial
Este es el único ejemplo que puedo sacar de todas mis
aplicaciones. Seguro que el alumno va a ver más aplicaciones de esta propiedad.
La propiedad Filter puede mostrar
también aquellos registros que han sido manipulados recientemente, mediante las
constantes siguientes:
AdFilterNone Quita
el filtro actual y vuelve a poner todos los registros a la
vista.
AdFilterPendingRecords Permite
ver sólo los registros que han cambiado, pero que no han sido enviados aún al
servidor. Aplicable sólo para el modo de
actualización por lotes.
AdFilterAffectedRecords Permite
ver sólo los registros afectados por la última llamada a Delete, Resync, UpdateBatch o
CancelBatch
AdFilterFetchedRecords Permite
ver los registros de la caché actual, es decir, los resultados de la última llamada
para recuperar registros de la base
de datos
AdFilterConflictingRecords Permite
ver los registros que fallaron en el último intento de actualización
por lotes.
Propiedad Index
Indica el
nombre del índice que se utiliza actualmente en el Recordset. Es un String con
el nombre del índice.
El índice
se utiliza para moverse a lo largo del recordset mediante el método Move. El
índice ya debe estar creado en la tabla de la base de datos.
Al
utilizar un índice, el orden de los registros se cambia al orden establecido en
ese índice. Por lo tanto, los valores obtenidos anteriormente por la propiedad
AbsolutePosition cambiarán completamente.
No todos
los proveedores de datos aceptan la propiedad Index. Puede comprobarlo mediante
el método Supports.
Propiedad MarshalOptions
Esta propiedad se usa cuando estamos
trabajando con cursores lado cliente.
En este caso, como vimos más atrás, los registros del recordset están en el
equipo cliente. Todas las operaciones realizadas sobre el recordset se realizan
en el cliente, por lo tanto llegará el momento en que habrá que actualizar en
el servidor los datos que hayamos modificado en el recordset que está en el
equipo cliente. Mediante esta propiedad podemos hacer que se envíen al servidor
todos los registros (filas) o solamente los que han cambiado. Acepta estas dos
constantes:
AdMarshalAll Predeterminada. Indica que todos los
registros se devuelven al servidor.
AdMarshalModifiedOnly Indica que
sólo los registros modificados se devuelven al servidor.
Esta propiedad puede mejorar el
rendimiento de la aplicación para aquellos casos en los que se use un canal de
comunicación lento.
Propiedad PageSize
Indica cuántos registros constituyen una
página del objeto Recordset. Es de lectura y escritura. Devuelve un Long y su
valor predeterminado es 10.
Esta propiedad permite
determinar cuántos registros componen una página lógica de datos. Al
establecer un tamaño de página, puede utilizar la propiedad AbsolutePage y se moverá al primer
registro de una página específica. Esto es útil en las situaciones de servidor
Web cuando se desea permitir que el usuario pase páginas de datos y vea cierto
número de registros al mismo tiempo. Esta propiedad se puede establecer en
cualquier momento y su valor se utilizará para calcular la ubicación del primer
registro de una página específica.
Propiedad PageCount
Indica cuántas páginas de datos contiene el objeto
Recordset. Es solamente de lectura. Devuelve un Long. Si el objeto Recordset no admite esta propiedad, el
valor será -1 para indicar que no se puede determinar el valor de PageCount.
Propiedad AbsolutePage
Especifica
en qué página reside el registro actual. Es de lectura y escritura. Devuelve un
Long o una de las siguientes constantes:
AdPosUnknown El
objeto Recordset está vacío, la
posición actual se desconoce o el proveedor
no admite la propiedad AbsolutePage.
AdPosBOF El
puntero del registro actual está al comienzo del archivo (es decir, la propiedad BOF tiene el valor True).
AdPosEOF El
puntero del registro actual está al final del archivo (es decir, la propiedad EOF tiene el valor True).
Propiedad RecordCount
Indica el número actual de
registros de un objeto Recordset.
Devuelve un Long
Es posible que esta propiedad no la
permita el proveedor de datos, o que no pueda llegar a averiguarse, ya que
dependiendo del tipo de cursor utilizado puede que no suministre ese dato.
Propiedad Source
Devuelve
la tabla, consulta o sentencia SQL utilizado en el método Open para crear el
recordset. Es un String.
Propiedad State
Indica el estado
(abierto, cerrado, proceso de ejecución) en el que se encuentra el recordset.
Devuelve uno de los siguientes valores:
Constante |
Descripción |
adStateClosed |
Valor
predeterminado. Indica que el objeto está cerrado. |
adStateOpen |
Indica
que el objeto está abierto. |
adStateConnecting |
Indica
que el objeto Recordset se está
conectando. |
adStateExecuting |
Indica
que el objeto Recordset está
ejecutando un comando. |
adStateFetching |
Indica
que se está obteniendo el conjunto de filas del objeto Recordset. |
Puede tener una combinación de valores. Por ejemplo,
si se está ejecutando una instrucción, esta propiedad tendrá un valor combinado
de adStateOpen y adStateExecuting.
Propiedad Status
Esta propiedad se refiere al registro
actual. Indica el estado de este registro respecto a las operaciones de
actualización por lotes u otras operaciones masivas. No es una propiedad que se
use todos los días. Vea la ayuda para
mas detalles.
Las propiedades anteriores se refieren a
propiedades del recordset que se refieren a unas características propias del
recordset una vez creado. Son estas:
Unique Table, Unique Schema y Unique Catalog
Unique
Table especifica la tabla
sobre la que se permite realizar modificaciones de datos (Insertar o
actualizar), en el caso de que el recordset se haya creado mediante una
operación JOIN
Unique
Catalog indica el nombre de la base de datos a la que
pertenece la tabla. Estas dos últimas propiedades deben tener un valor para
poder poner valor a la propiedad Unique
Table. Estas propiedades son tipo String
Estas propiedades dinámicas se anexan a la colección Properties del objeto Recordset al asignar el valor adUseClient a la propiedad Cursor
Location.
METODO Supports
Este método es muy útil para ver si un
recordset acepta una determinada funcionalidad. Devuelve un Booleano y es
solamente de lectura. De esta forma puede consultar si un recordset admite el
método MoveFirst, la propiedad AbsolutePosition, Bookmark, etc., antes de
invocar ese método o leer esa propiedad, y evitar de esta forma un error en la
ejecución. Esto es muy útil habida cuenta que no todos los proveedores
funcionan de la misma forma. Es por lo tanto muy prudente consultar si el
Recordset soporta una funcionalidad antes de pedírsela.
Estas funcionalidades se le pasan como
parámetro mediante una de las siguientes constantes:
AdAddNew Puede usar
el método AddNew para agregar nuevos registros.
AdApproxPosition Puede leer y establecer las propiedades
AbsolutePosition y AbsolutePage.
AdBookmark Puede usar la propiedad Bookmark para tener acceso a
registros específicos
AdDelete Puede usar el método Delete para eliminar registros.
AdHoldRecords Puede
recuperar más registros o cambiar la posición de recuperación siguiente sin
efectuar todos los cambios pendientes.
AdMovePrevious Puede usar
los métodos MoveFirst y MovePrevious, y los métodos Move o GetRows para desplazar
hacia atrás la posición del registro actual
sin que se requiera marcadores.
AdResync Puede
usar el método Resync para actualizar el cursor con los datos visibles en la
base de datos subyacente.
AdUpdate Puede
usar el método Update para modificar datos existentes.
AdUpdateBatch Puede
usar actualización por lotes (métodos UpdateBatch y CancelBatch)
para transmitir grupos de cambios al proveedor.
AdIndex Puede
utilizar la propiedad Index para dar nombre a un índice.
AdSeek Puede
utilizar el método Seek para encontrar una fila en un Recordset.
En este ejemplo vemos la sintaxis de
Supports:
If RsSeg.Supports(adApproxPosition) = True Then
MsgBox
"SI"
Else
MsgBox
"NO"
End
If
Nota Aunque el método Supports puede devolver True para una funcionalidad determinada,
eso no garantiza que el proveedor pueda hacer que la característica esté
disponible bajo cualquier circunstancia. El método Supports devuelve simplemente si el proveedor puede admitir la
funcionalidad especificada, dando por supuesto que se reúnen determinadas
condiciones. Por ejemplo, el método Supports
puede indicar que un objeto Recordset
admite actualizaciones aunque el cursor se base en una unión de múltiples
tablas, de las que algunas columnas no son actualizables.
El valor
devuelto por el método Supports dependerá del tipo de recordset elegido. En la
siguiente tabla puede ver el tipo de recordset y las constantes para las que va
a devolver True:
AdOpenForwardOnly Ninguna
AdOpenKeyset adBookmark,
adHoldRecords, adMovePrevious, adResync
AdOpenDynamic AdMovePrevious
AdOpenStatic adBookmark,
adHoldRecords, adMovePrevious, adResync
Método Open
Es el método que ABRE el recordset. Este
método es el que busca los registros que han de rellenar el recordset.
Sintaxis. Esta es la sintaxis general:
MiRecordset.Open Source, ActiveConnection, CursorType,
LockType,
Options
Un recordset puede abrirse partiendo de
una conexión ya abierta. Pero también puede crearse directamente, sin abrir
previamente la conexión. Al final, deberá aportar todos los datos necesarios
para determinar en que base de datos se abre ese recordset. Sobre que tabla,
consulta o sentencia SQL., que tipo de
cursor va a ser, etc. Lo que ocurre es que ADO es muy flexible y nos permite
hacerlo de varias formas, aunque todas ellas conducen a lo mismo.
Source (Opcional)
Es el nombre de una tabla, consulta o sentencia SQL de la
cual se obtienen los registros del Recordset.
ActiveConnection
(Opcional).
Es el nombre de un objeto Connection abierto o una cadena de conexión válida.
Esta cadena es la misma que la que emplearíamos para abrir el objeto
Connection.
CursorType (Opcional). Un valor que determina el tipo de cursor que el proveedor debe
usar al abrir el Recordset. Puede
ser una de las siguientes constantes
AdOpenForwardOnly (Predeterminado) Abre un
cursor de tipo sólo avance.
AdOpenKeyset Abre un
cursor de tipo conjunto de claves.
AdOpenDynamic Abre un
cursor de tipo dinámico. (Igual que el Dynaset de DAO)
AdOpenStatic Abre un
cursor de tipo estático.
LockType (Opcional).
Un valor que determina el tipo de bloqueo que debe usar el proveedor al abrir
el Recordset. Con este parámetro se
le indica también si debe hacer las actualizaciones registro a registro o en
bloque. Puede ser una de las siguientes constantes
AdLockReadOnly (Predeterminado)
Sólo lectura. No puede modificar los datos.
AdLockPessimistic Bloqueo
pesimista, registro a registro. El proveedor hace lo necesario
para asegurar una modificación correcta de los registros,
normalmente bloqueando registros en el
origen de datos
inmediatamente antes de la modificación.
AdLockOptimistic Bloqueo
optimista, registro a registro. El proveedor usa bloqueooptimista, bloqueando registros sólo cuando se llama al método Update.
Options (Opcional).
Constante que determina como va a evaluar el proveedor de datos el argumento Source.
Puede ser una de las siguientes constantes de esta lista.
AdCmdText Indica que el proveedor debe evaluar Source
como una definición textual
de un comando.
AdCmdTable Indica
que ADO debe generar una consulta SQL para devolver todaslas filas de la tabla
nombrada en Source.
AdCmdTableDirect Indica que
el proveedor debe devolver todas las filas de la tabla nombrada en Source.
AdCmdStoredProc Indica que
el proveedor debe evaluar Source como un procedimiento almacenado
AdCmdUnknown Indica que
el tipo de comando del argumento Source es desconocido.
AdCmdFile Indica que el Recordset guardado se debe restaurar desde el archivo nombrado en Source.
AdAsyncExecute Indica que
Source
se debe ejecutar de forma asíncrona.
AdAsyncFetch Indica que,
tras alcanzar la cantidad inicial especificada en la propiedad Initial Fetch
Size, las filas restantes deben buscarse
de forma asíncrona. Si se requiere una fila que no se ha encontrado, se bloqueará el subproceso principal hasta que se disponga de la fila solicitada.
AdAsyncFetchNonBlocking Indica que
el subproceso principal nunca se bloquea durante la búsqueda. Si no se
encuentra la fila solicitada,
la fila actual se desplaza automáticamente al
final del archivo.
Habrá observado que hemos remarcado que el método Open ABRE
un recordset. No lo crea. El recordset debe estar creado previamente. ¿Qué
cuando se crea? Mediante la instrucción:
Set
MiRecordset = New ADODB.Recordset
Metodo
Requery
Actualiza los datos de un objeto Recordset volviendo
a ejecutar la consulta utilizada para abrirlo. Se obtiene el mismo resultado
que si se cerrara el recordset y se volviera a abrir.
Sintaxis MiRecordset.Requery Opciones
Optiones Opcional. Máscara de bits
que indica opciones que afectan a esta operación. Si el valor de este parámetro
está establecido a adAsyncExecute,
esta operación se ejecutará de forma asíncrona y se emitirá un evento
RecordsetChangeComplete cuando concluya.
Método Resync
Actualiza los datos del objeto Recordset
actual. Este método, a diferencia del
método Requery, no vuelve a ejecutar el comando de creación del recordset, sino
que lee los registros existentes en el recordset para actualizar su valor, pero
no presenta aquellos registros que hubieran sido creados con posterioridad a la
apertura del recordset. Es más rápido
que el método Requery, y en muchos casos solamente nos interesa actualizar los
registros sobre los que estamos trabajando.
Los
parámetros AffectRecords y
ResyncValues determinan que registros se van a volver a leer y
sobreescribir. Vea la ayuda para mas detalles.
METODO AddNew
Crea un
nuevo registro en un objeto Recordset actualizable.
Sintaxis NombreDelRecordset.AddNew FieldList,
Values
Los parámetros FieldList y Values son opcionales. En
caso de ponerlos, FieldList serán los nombres de los campos a los que se les va
a poner un valor, y Values son los valores de cada uno de estos campos. El
orden nombre - valor debe mantenerse estrictamente.
Siempre
recomendaré que, en vez de meter los datos mediante estos parámetros, se metan
posteriormente linera a línea, tal como se hizo siempre con los recordsets
NombreDelRecordset!NombredelCampo =
ValorDelCampo
ó
NombreDelRecordset(“NombredelCampo”)
= ValorDelCampo
Esta
segunda forma es necesaria cuando el nombre del campo tiene espacios. Nunca es
recomendable poner espacios en los nombres de campos, pero en caso de que
existan, debe optar por utilizar la sintaxis segunda, con los paréntesis y
comillas dobles.
No siempre
se puede utilizar el método AddNew. Puede comprobar si se puede utilizar,
usando el método Supports visto
anteriormente.
El método AddNew convierte a este registro recién
creado en registro actual. Pero este registro solamente existe en el recordset.
Para introducir los datos en la base de datos, (Y por lo tanto en el disco
duro) es necesario invocar el método Update
una vez introducidos todos los valores de los campos que deseamos introducir.
Con algún tipo de cursor es necesario también utilizar el método Requery para poder acceder al registro
recién creado.
Si se invoca el método AddNew mientras se está editando el registro actual, o durante otra
operación AddNew, ADO invoca
automáticamente el método Update
para guardar los cambios. Vea más
adelante los métodos Update y UpdateBatch.
Método Update
Guarda los cambios realizados en el
registro actual de un objeto Recordset. Se utiliza tanto para “rematar” una
operación de creación de un registro iniciada con AddNew, como para guardar los
nuevos datos del registro actual (Recuerde que en ADO no existe el método Edit,
tal como ocurría en DAO)
.
Sintaxis NombreDelRecordset.Update Fields, Values
En esta
sintaxis, Fields y Values son opcionales, y solamente tienen aplicación cuando
se trata de cambiar los valores del registro actual, no de terminar una
operación de creación de un nuevo registro mediante AddNew.
Vuelvo a
recomendar lo anterior. Para cambiar los valores de varios campos de un
registro, nos colocaremos sobre ese registro, y sin invocar ningún método,
ejecutaremos este código
MiRecordset!Campo1 = Valor1
MiRecordset!Campo2 = Valor2
……….
MiRecordset!CampoN =
ValorN
MiRecordset.Update
Pero en ADO pasa una cosa que no pasaba en DAO. Si
cambiamos de registro una vez modificado el valor de un registro, ADO invoca
automáticamente el método Update.
Por lo tanto, el código siguiente:
MiRecordset!Campo1 = Valor1
MiRecordset!Campo2 = Valor2
……….
MiRecordset!CampoN = ValorN
Tendrá el
mismo resultado que el anterior cuando cambiemos de registro actual. Esto puede
ser bueno a malo, pero personalmente pienso que no es práctico porque implica
tener mucho más cuidado que en DAO. Hace lo mismo que cuando tenemos unos
controles enlazados a datos mediante un control Data.
Si una vez
que ejecutamos una línea tal como esta
MiRecordset!Campo1 = Valor1
Queremos que ese nuevo valor no entre en la base de
datos, debemos cancelarlo mediante el método CancelUpdate.
Método UpdateBatch
Escribe en disco todas las actualizaciones
pendientes de proceso por lotes. En ADO
un recordset puede actualizarse registro a registro o por lotes. Todo dependerá
de cómo se ha abierto (Si el valor LockType
se ha puesto a AdLockBatchOptimistic)
Sintaxis MiRecordset.UpdateBatch AffectRecords
AffectRecords
Constante que determina a cuántos registros afectará
el método UpdateBatch.
Puede tomar uno de los siguientes valores.
AdAffectCurrent Escribe solamente los cambios
pendientes en el registro actual.
AdAffectGroup Escribe
los cambios pendientes que cumplen el valor de la propiedad Filter.
AdAffectAll (Predeterminado) Escribe
los cambios pendientes en todos los registros del objeto Recordset.
Método Cancel
Cancela la
ejecución del método Open.
Sintaxis NombreDelRecordset.Cancel
El método Cancel solamente puede usarse si el método
Open fue invocado con la opción
adAsyncConnect, adAsyncExecute o
adAsyncFetch.
Método Delete
Elimina el
registro actual o un grupo de registros. Por defecto elimina solamente el
registro actual. Vea la ayuda para ampliar los detalles respecto al parámetro
opcional AffectRecords
Sintaxis MiRecordset.Delete AffectRecords
Método CancelUpdate
Habíamos
visto más atrás que el ADO no existe el método Edit. Para modificar un registro
basta con poner una instrucción tal como esta:
MiRecordset!MiCampo = MiNuevoValor
Y a
continuación rematar la operación mediante el método Update
MiRecordset.Update
Si por cualquier circunstancia se ha
ejecutado la primera instrucción, y luego queremos volvernos atrás, antes de
ejecutar el método Update debemos deshacer el cambio con el método
CancelUpdate, con lo que el registro afectado recuperará nuevamente su valor
original.
Sintaxis MiRecordset.CancelUpdate
Recuerde que ADO funciona de forma distinta a DAO con estos
métodos de modificación de los registros. Recuerde que si está en proceso de
modificación de un registro (Ha ejecutado la primera línea del ejemplo
anterior) y cambia de registro, por el hecho de cambiar de registro, ADO invoca
automáticamente el método Update.
Método CancelBatch
Cancela
una actualización por lotes pendiente. Es similar a la anterior, pero para
actualización por lotes.
Sintaxis MiRecordset.CancelBatch AffectRecords
Método Clone
Crea un objeto Recordset duplicado a partir de un
objeto Recordset existente.
Opcionalmente, puede especificarse que el nuevo recordset sea solamente de
lectura
Sintaxis Set rstDuplicate = rstOriginal.Clone (LockType)
(El objeto
rstDuplicate debe estar declarado previamente como objeto ADODB.Recordset)
LockType
puede tomar uno de los siguientes valores:
AdLockUnspecified (Predeterminado)
El recordset resultante tendrá el mismo tipo de bloqueo que el original.
AdLockReadOnly El recordset creado es solamente de lectura.
El recordset resultante del método Clone, aunque
igual al original en el momento de su creación, es completamente independiente
de este a partir de ese momento, por lo que las actualizaciones efectuadas en
el original no afectan al clonado.
Método Move
Mueve la posición del registro
actual de un objeto Recordset
.
Sintaxis MiRrecordset.Move NumRecords, Start
NumRecords Un valor Long con signo que especifica el número de
registros que debe moverse a partir de la posición del registro actual o del
registro especificado en el parámetro Start, si es que se especifica.
Start Opcional. Un String o Variant cuyo
resultado sea un marcador del tipo Bookmark.
Puede utilizar también una de las siguientes constantes:
AdBookmarkCurrent (Predeterminado) Cuenta a partir del registro actual
AdBookmarkFirst Cuenta a partir del primer registro
AdBookmarkLast Cuenta a partir del último registro
Métodos MoveFirst, MoveLast,
MoveNext y MovePrevious
Pasa al
primer, último, siguiente o anterior registro de un objeto Recordset
especificado y lo convierte en el registro actual. Funciona igual que en DAO
Tenga en
cuenta a la hora de usar los métodos Move que pueden existir Recordsets que no
permiten el movimiento hacia atrás.
Método Find
Busca el primer registro del recordset que
satisfaga los criterios especificados en el criterio de búsqueda. Si se cumple
el criterio de búsqueda, la posición del recordset se establece en el primer
registro encontrado; si no, la posición se establece al final del recordset.
Sintaxis MiRecordset.Find (criterio, SkipRows, searchDirection, start)
criterio Es el
criterio de búsqueda. Por ejemplo “Pais
= España” siendo Pais el nombre del
campo en el cual buscamos el valor España
SkipRows (Opciopnal) Es
un Long, cuyo valor predeterminado es cero, que especifica el número de registros
a partir del registro actual donde debe empezar la búsqueda.
searchDirection
(Opcional) Un valor que especifica si la
búsqueda se realiza en dirección al final del recordset (adSearchForward) o en dirección hacia el principio del recordset (adSearchBackward). La búsqueda termina
al final o al principio del recordset, dependiendo del valor de searchDirection.
start (Opcional) Un
marcador tipo BookMark que se utiliza como posición inicial de la búsqueda.
El operador de
comparación de criterio puede ser ">", "<",
"=", ">=" , "<=", "<>"
(distinto de) o "like"
(coincidencia parcial de cadenas). El
valor de comparación puede ser una cadena, un número en coma flotante o una
fecha. Los valores de cadena están delimitados con comillas sencillas (por
ejemplo, "Pais = 'España'"). Los valores de fecha están delimitados
con signos "#" y con
formato mm/dd/yy (por ejemplo, "fecha_inicial
> #7/22/97#"). Si el operador
de comparación es "like",
el valor de la cadena puede contener
los caracteres comodín "*"
o "_". (Funcionan de forma
idéntica, sustituyendo a cualquier sucesión de caracteres.) No acepta el
carácter “?” (Por ejemplo, "Pais like ‘Es_’" o “Pais Like ‘Es*’
encuentra España y Estonia)
ADO no tiene los métodos FindFirst, FindNext, FindPrevious y FindLast. Deberá emplear el método Find de forma
inteligente para implementar estos otros.
Método Save
Este
método permite guardar el contenido de un Recordset
en un fichero. Puede ser muy útil cuando queremos exportar ese recordset hacia
otra aplicación.
FileName
es la ruta
completa del fichero en el que se guardará el Recordset.
PersistFormat
(Opcional).
Un valor que especifica el formato en que se guardará el Recordset. Puede ser una de las
constantes siguientes.
AdPersistADTG (Valor
predeterminado) Se guarda en un formato propietario (Advanced
Data Tablegram). No es inteligible a simple vista, pero genera ficheros
bastante cortos.
AAdPersistXML Se
guarda en formato XML. Es un formato puramente en ASCII donde
pueden verse los nombres de los campos y su contenido.
Este formato genera ficheros más grandes que el ADT
Si el recordset tienen aplicado un filtro
(Mediante la propiedad Filter) solamente guarda los registros que deja ver ese
filtro.
Si ya existe el fichero le dará un error.
Cerciórese que no existe (Mediante la función Dir) y bórrelo antes de volver a
utilizar el método Save.
Método Seek
Este método busca un registro
desplazándose por el recordset a lo largo de un índice o un conjunto de
índices. La búsqueda mediante Seek es
mucho más rápida que con Find, ya que la realiza siguiendo el ordenamiento de
los registros según un índice.
Para poder usar el método Index es
necesario que el proveedor acepte índices en el objeto recordset. Esto ha llevado al autor a no poder
presentar ningún ejemplo de este método, ya que todas las bases de datos
ensayadas no permitían índices. Puede ver si acepta índices mediante el método
Supports:
If
MiRecordset1.Supports(adIndex) = True Then
Vea la
ayuda de VB para mayor información
Método NextRecordset
Para entender este método es necesario
explicar previamente como se puede crear un recordset compuesto.
Un recordset compuesto es un recordset que
se crea concatenando sentencias SELECT, y cada una de ellas creará, dentro del
mismo Recordset, un recordset particular. Al crear el recordset, el recordset
particular que va a estar activo es el correspondiente a la primera sentencia
SELECT. Mediante el método NextRecordset
podemos ir avanzando a través de los siguientes recordsets
particulares. El carácter de separación
entre las sentencias SELECT es el punto y coma ( ; )
MiRecordset1.Open "Select * From Regimenes; Select * From
Regimen_Seguimiento Where Rs_Origen = 'LSB'", MiConexionADO, adOpenDynamic,
adLockOptimistic
(La
instrucción anterior debe leerse como una sola línea)
MiRecordset es un recordset compuesto.
Toma datos de dos tablas distintas, pero podría haberlo hecho solamente de una
tabla con una condición distinta en la SELECT.
Cuando se ejecuta esa línea, el recordset
actual es el correspondiente a la primera selección. (Select * From
Regimenes). Ejecutando el método NextRecordset ese recordset
primero se borra y pasa a ser recordset actual el creado con la selección
segunda (Select * From Regimen_Seguimiento Where Rs_Origen = 'LSB'")
Set MiRecordset1 = MiRecordset1.NextRecordset
Puede usar
también este recordset para crear un nuevo recordset a partir del primero
Set MiRecordset2 = MiRecordset1.NextRecordset
MiRecordset2
debe estar declarado como objeto recordset, y creado con la instrucción New:
Set MiRecordset2 = New ADOBD.Recodset
La colección Fields de un recordset ADO
Contiene todos los objetos Field
de un objeto Recordset.
Un objeto Recordset
tiene una colección Fields que
contiene todos los objetos Field.
Cada objeto Field se corresponde a
una columna del Recordset.
Vamos a ver aquí un truco que nos permite ADO.
Podemos crear un recordset ¡Sin necesidad de una base de datos!
Cuando estudiamos el objeto recordset vimos que el
recordset se crea con una instrucción como esta:
Set MiRecordset1 = New ADODB.Recordset
Ahora ya podemos abrir el recordset leyendo los datos
desde una base de datos. Utilizamos para ello el método Open del recordset:
MiRecordset1.Open "Select
* From Regimenes", MiConexionADO, adOpenDynamic, adLockOptimistic
Mediante el método Open lo que hace el recordset es
conocer su estructura (Que campos tiene, propiedades de estos campos, etc) y el
valor de cada uno de los campos de sus registros. ¿Qué pasaría si en vez de abrir el recordset le vamos añadiendo
objetos Field a su colección Fields? Lo
hacemos mediante el método Append:
MiRecordset1.Fields.Append
"MiCampo1", adBigInt
MiRecordset1.Fields.Append
"MiCampo2", adChar, 25
MiRecordset1.Fields.Append
"MiCampo3", adBSTR
Lo que ocurre es que el recordset ya tiene tres
campos, el primero de nombre MiCampo1, numérico Long, el segundo, un string de
25 caracteres de nombre MiCampo2, y el tercero, de nombre MiCampo3, una cadena
de caracteres de longitud indefinida, terminada en un carácter nulo. Ya tenemos una estructura de un recordset
sin necesidad de haber leído la base de datos. No es necesario por lo tanto que
exista una tabla o consulta almacenada con esa estructura. Ahora podemos abrir
el recordset:
MiRecordset1.Open
Lo abrimos sin pasarle ningún parámetro. Ahora ya
está abierto y podemos trabajar con el como con un recordset cualquiera.
Recuerde que al principio está vacío.
MiRecordset1.AddNew
MiRecordset1!MiCampo1 = 34
MiRecordset1!MiCampo2 = "Guía del
Estudiante"
MiRecordset1!MiCampo3 = "Hola mi amor"
& vbCrLf & "Yo soy tu lobo"
MiRecordset1.Update
Ya tenemos un registro dentro del recordset. Podemos
introducirle tantos registros como queramos, y luego movernos por el recordset mediante
los métodos Movexxxx. Ahora podremos leer el contenido del registro actual:
Label1 = MiRecordset1!MiCampo1
Label2 = MiRecordset1!MiCampo2
Label3 = MiRecordset1!MiCampo3
El resultado del código de el ejemplo se traducirá en
algo como esto:
Y ahora vienen lo mejor. ¿Para que queremos un
recordset que no tienen datos leídos desde una base de datos? Las aplicaciones de esto solamente está
limitadas por la imaginación. Pienso, por ejemplo, en introducir en un
recordset todos los datos leídos de un fichero de configuración, y así tener
todos esos datos disponibles durante toda la aplicación, en vez de en
variables, como MiRecordset!MiDato1
Es una idea, pero piense que esto no regala nada.
El espacio de memoria consumido será similar a si usa variables. Pero
posiblemente estará más cómodo y más inteligible su código.
Veamos los métodos de la colección Fields
Método Append
Agrega un
campo a una colección Fields de un Recoprdset.
Sintaxis MiRecordset.Fields.Append Name, Type, DefinedSize, Attrib
Name Un
String con el nombre del nuevo objeto
Field, que tiene que ser único dentro de la coleccón Fields.
Type Tipo
de datos que va a contener ese campo. Puede tomar uno de estos valores:
adArray |
Se une
en una instrucción OR lógica con
otro tipo para indicar que los datos son una matriz segura de ese tipo
(DBTYPE_ARRAY). |
adBigInt |
Un
entero con signo de 8 bytes (DBTYPE_I8). |
adBinary |
Un valor
binario (DBTYPE_BYTES). |
adBoolean |
Un valor Boolean (DBTYPE_BOOL). |
adByRef |
Se une
en una instrucción OR lógica con
otro tipo para indicar que los datos son un puntero a los datos del otro tipo
(DBTYPE_BYREF). |
adBSTR |
Una
cadena de caracteres terminada en nulo (Unicode) (DBTYPE_BSTR). |
adChar |
Un valor
de tipo String (DBTYPE_STR). |
adCurrency |
Un valor
de tipo Currency (DBTYPE_CY). Un
valor Currency es un número de
coma fija con cuatro dígitos a la derecha del signo decimal. Se almacena en
un entero con signo de 8 bytes en escala de 10.000. |
adDate |
Un valor
de tipo Date (DBTYPE_DATE). Un
valor Date se almacena como un
valor de tipo Double; la parte
entera es el número de días transcurridos desde el 30 de diciembre de 1899 y
la parte fraccionaria es la fracción de un día. |
adDBDate |
Un valor
de fecha (aaaammdd)
(DBTYPE_DBDATE). |
adDBTime |
Un valor
de hora (hhmmss) (DBTYPE_DBTIME). |
adDBTimeStamp |
Una
marca de fecha y hora (aaaammddhhmmss
más una fracción de miles de millones) (DBTYPE_DBTIMESTAMP). |
adDecimal |
Un valor
numérico exacto con una precisión y una escala fijas (DBTYPE_DECIMAL). |
adDouble |
Un valor
de coma flotante de doble precisión (DBTYPE_R8). |
adEmpty |
No se ha
especificado ningún valor (DBTYPE_EMPTY). |
adError |
Un
código de error de 32 bits (DBTYPE_ERROR). |
adGUID |
Un
identificador único global (GUID) (DBTYPE_GUID). |
adIDispatch |
Un
puntero a una interfaz Idispatch
de un objeto OLE (DBTYPE_IDISPATCH). |
adInteger |
Un
entero firmado de 4 bytes (DBTYPE_I4). |
adIUnknown |
Un
puntero a una interfaz Iunknown de
un objeto OLE (DBTYPE_IUNKNOWN). |
adLongVarBinary |
Un valor
binario largo (sólo para el objeto Parameter). |
adLongVarChar |
Un valor
largo de tipo String (sólo para el
objeto Parameter). |
adLongVarWChar |
Un valor
largo de tipo String terminado en
nulo (sólo para el objeto Parameter). |
adNumeric |
Un valor
numérico exacto con una precisión y una escala exactas (DBTYPE_NUMERIC). |
adSingle |
Un valor
de coma flotante de simple precisión (DBTYPE_R4). |
adSmallInt |
Un
entero con signo de 2 bytes (DBTYPE_I2). |
adTinyInt |
Un
entero con signo de 1 byte (DBTYPE_I1). |
adUnsignedBigInt |
Un
entero sin signo de 8 bytes (DBTYPE_UI8). |
adUnsignedInt |
Un
entero sin signo de 4 bytes (DBTYPE_UI4). |
adUnsignedSmallInt |
Un
entero sin signo de 2 bytes (DBTYPE_UI2). |
adUnsignedTinyInt |
Un
entero sin signo de 1 byte (DBTYPE_UI1). |
adUserDefined |
Una
variable definida por el usuario (DBTYPE_UDT). |
adVarBinary |
Un valor
binario (sólo para el objeto Parameter). |
adVarChar |
Un valor
de tipo String (sólo para el
objeto Parameter). |
adVariant |
Un tipo Variant de automatización
(DBTYPE_VARIANT). |
adVector |
Se une
en una instrucción OR lógica con
otro tipo para indicar que los datos son una estructura DBVECTOR, tal como
está definida por OLE DB, que contiene un contador de elementos y un puntero
a los datos del otro tipo (DBTYPE_VECTOR). |
adVarWChar |
Una
cadena de caracteres Unicode terminada en nulo (sólo para el objeto Parameter). |
adWChar |
Una
cadena de caracteres Unicode terminada en nulo (DBTYPE_WSTR). |
DefinedSize Un Long que define el tamaño del
campo si fuese necesario. (Por ejemplo para un string)
Attrib (Opcional). Especifica los
atributos del campo a añadir. Puede
tomar estos valores:
adFldMayDefer |
Indica
que el campo se aplaza, es decir, los valores del campo no se recuperan del
origen de datos con todo el registro, sino solamente cuando se tiene acceso
explícito a los mismos. |
adFldUpdatable |
Indica
que se puede escribir en el campo. |
adFldUnknownUpdatable |
Indica
que el proveedor no puede determinar si se puede escribir en el campo. |
adFldFixed |
Indica
que el campo contiene datos de longitud fija. |
adFldIsNullable |
Indica
que el campo acepta valores Null. |
adFldMayBeNull |
Indica
que se pueden leer valores Null
del campo. |
adFldLong |
Indica
que se trata de un campo binario largo. También indica que se pueden utilizar
los métodos AppendChunk y GetChunk. |
adFldRowID |
Indica
que el campo contiene un identificador de fila persistente en el que no se
puede escribir y que no tiene ningún valor significativo excepto la
identificación de la fila (como por ejemplo un número de registro, un
identificador único, etc.). |
adFldRowVersion |
Indica
que el campo contiene algún tipo de marca de hora o de fecha que se utiliza
para efectuar actualizaciones. |
adFldCacheDeferred |
Indica
que el proveedor almacena los valores del campo en la memoria caché y que las
lecturas siguientes se efectúan en dicha memoria . |
Método Delete
Teóricamente
elimina un objeto de la colección Fields.
Sintaxis Fields.Delete Field
Field Un Variant que designa el objeto Field que se va a eliminar. Este
parámetro tiene que ser el nombre del objeto Field; no puede ser una posición ordinal o el propio objeto Field.
Comentarios
La llamada
al método Fields.Delete en un Recordset abierto provoca un error de
ejecución.
(Como ha ocurrido en otras ocasiones, al autor le ha
sido imposible ejecutar este método con los resultados esperados)
Método Item
Sintaxis MiRecordset.Fields.Item (Index)
Devuelve el elemento de la colección Fields especificado en el índice.
Devuelve el objeto, por lo tanto, y sobre ese objeto, podemos obtener las
propiedades que deseemos. En el ejemplo siguiente, introducimos los nombres de
todos los campos en un ComboBox llamado ComboCampos
Dim MM As String, I As Integer
For I = 0 To MiRecordset1.Fields.Count - 1
MM = MiRecordset1.Fields.Item(I).Name
ComboCampos.AddItem MM
Next I
Método Refresh
Aunque la colección Fields tiene este
método, la verdad es que no tienen efectos visibles sobre esa colección.
Propiedades de la colección Fields
Propiedad Count
Devuelve
el número de campos de la colección Fields.
Es un Long.
Un objeto Command
es la definición de un comando específico que se piensa ejecutar contra un
origen de datos. Mediante un objeto
Command podemos crear un recordset, pero recuerde que un recordset lo podemos
también crear directamente.
Utilice un objeto Command para consultar una base de datos y obtener registros en un
objeto Recordset, para añadir o eliminar registros, ejecutar una operación de
manejo masivo de datos o para manipular la estructura de una base de datos.
Propiedad ActiveConnection
Indica a
qué objeto Connection pertenece actualmente el objeto Command. Es un string con
el nombre de la conexión.
Propiedad CommandText
Contiene el texto del comando que se
quiere emitir al proveedor. Es un string. Suele ser una instrucción SQL, un
nombre de tabla o un procedimiento almacenado, o cualquier otra instrucción que
reconozca el proveedor. El valor predeterminado es una cadena vacía.
Propiedad CommandTimeout
Especifica el intervalo de espera para que
se ejecute un comando antes de que finalice el intento y se genere un error. Es
un Long que indica en segundos ese tiempo. El valor predeterminado es 30.
Propiedad CommandType (IMPORTANTE)
Indica el tipo de un objeto Command. Esta propiedad
se usa para optimizar la evaluación de la propiedad CommandText, ya que de esta forma el proveedor no tiene que perder
tiempo examinando si es una instrucción SQL, un procedimiento almacenado o un
nombre de tabla. Si el valor de esta
propiedad es adCmdUnknown (valor
predeterminado), estamos forzando al proveedor a que realice esa investigación
lo que provocará probablemente un descenso en su rendimiento. Si sabe qué tipo
de comando está usando, el establecimiento de la propiedad CommandType instruye a ADO a que vaya directamente al código
relevante. Si la propiedad CommandType
no coincide con el tipo de comando de la propiedad CommandText, ocurre un error cuando llama al método Execute.
Valores posibles
AdCmdText Indica que es una definición textual de un
comando o una llamada a un procedimiento almacenado.
AdCmdTable Indica que es un nombre de tabla cuyas columnas se
devuelven todas mediante
una consulta SQL generada internamente.
AdCmdTableDirect Indica que es un nombre de tabla en la que se devuelven todas las columnas.
AdCmdStoredProc Indica que es un nombre de procedimiento almacenado
AdCmdUnknown Predeterminado. El tipo de comando de la propiedad CommandText es desconocido.
AdCmdFile Evalúa CommandText
como el nombre de archivo de un valor Recordset
persistente.
AdExecuteNoRecords Indica que es un comando o un procedimiento almacenado que no devuelve
filas (por ejemplo, un comando que sólo inserta datos). Si se recupera alguna
fila, se descarta y no se devuelve. Siempre se combina con adCmdText o adCmdStoredProc.
Propiedad Prepared
Es un Booleano que indica si se debe
guardar una versión compilada de un comando antes de su ejecución. Esta
propiedad fuerza al proveedor a guardar una versión preparada (compilada) de la
consulta especificada en la propiedad CommandText antes de la primera ejecución
de un objeto Command. Esto puede disminuir el rendimiento de la primera
ejecución de un comando, pero cuando el proveedor haya compilado el comando,
utilizará la versión compilada del mismo para las ejecuciones siguientes, lo
cual aumentará el rendimiento.
Si el proveedor no admite la preparación del comando,
puede devolver un error cuando esta propiedad se establezca a True. Si no devuelve un error,
simplemente ignora la solicitud de preparar el comando y establece la propiedad
Prepared a False.
Propiedad State
Describe
el estado del objeto: abierto o cerrado. Devuelve un Long o una constante: adStateClosed o adStateOpen
Métodos del Objeto Command
Método Execute
(IMPORTANTE, más bien diríamos, el objetivo del
Command)
Ejecuta la consulta, la instrucción SQL o
el procedimiento almacenado especificado en la propiedad CommandText. Devuelve un recordset o modifica la base de
datos.
Sintaxis
Para un Command que devuelva filas:
Set recordset = command.Execute(RecordsAffected, Parameters,
Options)
Para un Command que no devuelva filas:
command.Execute RecordsAffected, Parameters,
Options
command es el
nombre del Objeto Command
RecordsAffected
Opcional. Una variable Long en la que el proveedor devuelve el número de registros afectados
por la operación.
Parameters
Opcional. Una matriz Variant con los valores de los parámetros pasados con una
instrucción SQL. (Los parámetros de salida no devuelven valores correctos
cuando se pasan en este argumento).
Options Opcional.
Un valor Long o una constante.
Acepta estos valores
adCmdText
Indica que el proveedor
tiene que evaluar CommandText como definición textual de un
comando, como una instrucción SQL.
adCmdTable
Indica que ADO tiene que
generar una consulta SQL para devolver
todas las filas de la tabla mencionada en CommandText.
adCmdTableDirect
Indica que el proveedor tiene que
devolver todas las filas de la tabla mencionada
en CommandText.
AdCmdStoredProc Indica que
el proveedor tiene que evaluar CommandText
como procedimiento
almacenado.
adCmdUnknown
Indica que el tipo de comando en CommandText
es desconocido.
adAsyncExecute
Indica que el comando se tiene
que ejecutar de forma asíncrona.
adAsyncFetch
Indica que el resto de las filas
siguientes a la cantidad inicial especificada en la propiedad CacheSize
tiene que ser recuperada de forma asíncrona.
Método Cancel
Cancela la
ejecución de una llamada asíncrona pendiente al método Execute
Sintaxis NombredelObjetoCommand.Cancel
Utilice el método Cancel para terminar la ejecución de una llamada asíncrona a un
método Execute (es decir, el método
fue invocado con la opción
adAsyncExecute o adAsyncFetch).
Comandos parametrizados.
Los objetos Command pueden utilizar parámetros. De
esta forma, podemos construir una consulta utilizando la interrogación (?) como
comodín. Así cada vez que ejecutemos el comando, V.B. se encargará de sustituir
el comodín por los parámetros asociados a dicho command. Además podemos utilizar los parámetros para recoger los
valores devueltos por un Procedimiento almacenado en la base de datos. Para
entender mejor este tipo de consultas primero veremos qué es el objeto parameter.
Veamos un ejemplo de cómo usar el Objeto Command.
Pero previamente vamos a ver un código del que hemos partido para hacer ver al
alumno que ADO permite hacer las cosas de muchas maneras. Este código mete los
datos de un documento en una base de datos Oracle, leyendo previamente el
número más alto del documento para poner al nuevo documento un número igual al
último + 1.:
Declaraciones
Dim ConexBDPrensa As ADODB.Connection
Dim RsBDPrensa1 As
ADODB.Recordset
Dim StrIntroducir As String,
NumeroDocumento as long
Rem Se abre un objeto Connection para crear sobre él
el recordset
Set ConexBDPrensa = New
ADODB.Connection
ConexBDPrensa.ConnectionString
= "Provider=MSDAORA.1;” & _
“User
ID=INTRANET;Password=INTRANET;Data Source=intranet;” & _
“Persist Security
Info=False"
ConexBDPrensa.Open
Rem Se abre un recordset para leer el número, se lee
y se vuelve a cerrar
RsBDPrensa1.Open
"Int_Documentos Order By CL_DOC", ConexBDPrensa, adOpenDynamic,
adLockOptimistic
RsBDPrensa1.MoveLast
NumeroDocumento = RsBDPrensa1!CL_DOC
NumeroDocumento = NumeroDocumento + 1
RsBDPrensa1.Close
(* Este es el
punto donde cambia el código que verá más adelante)
Rem Se
introduce en una variable tipo String una instrucción para añadir un nuevo
registro
Rem Esa
instrucción se va a ejecutar desde el objeto Connection mediante su método
Execute
StrIntroducir = "Insert Into INT_DOCUMENTOS
" & _
"(CL_DOC,NOM_DOC,TITULO_DOC,AUTOR_DOC,CL_TEMA_DOC,CL_DPT_DOC,”
& _
“CL_TIPO_DOC,FICH_DOC,FECHA_EMISION_DOC,ULTIMA_HORA_DOC,”
& _
VISIBLE_DOC) Values (" & NumeroDocumento
& ",'" & TbTitulo & "','" & TbTitulo &
_
"','" & TbTitulo.Tag &
"',19,2,1,'" & HRefPrensa & "/" & TbNombFichTIF
& "','" & Date & "',0,1)"
Rem Observe que los valores tipo string introducidos
(TbXXX) van entre comilla simple
Rem Se
ejecuta esa instrucción desde el objeto Connection ConexBDPrensa
ConexBDPrensa.Execute StrIntroducir
Rem Se cierra el Objeto Connection
ConexBDPrensa.Close
Rem Aquí termina la operación de crear un nuevo
registro
MsgBox "Documento enviado"
Este es el código real de una aplicación que
introduce los datos el resumen de prensa diario en una base de datos. Se
introduce un nuevo registro en la tabla INT_DOCUMENTOS. El resumen de prensa es
un fichero .Tiff de nombre
TbNombFichTIF que se mete en una carpeta del servidor mediante FTP, y para su
loccalización y presentación en una página Web es necesario introducir su
nombre y Path y otros datos en una base de datos. Los campos que se introducen y los valores de cada uno son:
Campo Valor
CL_DOC, NumeroDocumento (Long calculado)
NOM_DOC TbTitulo (String contenido en TbTitulo.Text)
TITULO_DOC TbTitulo (String contenido en TbTitulo.Text
– se repite-)
AUTOR_DOC TbTitulo.Tag (String contenido en
TbTitulo.Tag)
CL_TEMA_DOC 19 (Integer, dato
fijo)
CL_DPT_DOC 2 (Integer, dato
fijo)
CL_TIPO_DOC 1 (Integer, dato
fijo)
FICH_DOC HRefPrensa & "/" &
TbNombFichTIF Un string que indica el
nombre del
fichero (TbNombFichTIF.Text) y su carpeta (Variable HrefPrensa)
FECHA_EMISION_DOC Date
(Fecha actual)
ULTIMA_HORA_DOC 0 (Byte, dato
fijo)
VISIBLE_DOC 1 (Byte,
dato fijo)
Esta forma de introducir los datos, método que los lingüistas especializados en
la jerga informática llaman “a capón”,
es la que nunca falla. Exige un poco de código, con muchas probabilidades de
equivocarse, pero muchas veces se prefiere esta forma de meter datos a utilizar
el método AddNew. Tiene la gran ventaja
de que la acepta cualquier base de datos, independientemente de donde esté el
cursor. Habrá observado que utilizamos
el método Execute del objeto
Connection. Y así funciona perfectamente. Vamos a hacer lo mismo, pero
introduciendo la cadena de caracteres un objeto Command, (Que pertenece al
mismo objeto Connection sobre el que ahora hemos ejecutado el Execute) y vamos
a ejecutar el Execute de ese Command. ¿Se
da cuenta que estamos haciendo lo mismo?
El nuevo código creado a partir del anterior es el siguiente:
(* Este es el
mismo punto de antes. Aquí comienza el cambio del código)
Dim MiComando As
ADODB.Command
Set MiComando = New
ADODB.Command
MiComando.ActiveConnection =
ConexBDPrensa
MiComando.CommandText =
"Insert Into INT_DOCUMENTOS " _
&
"(CL_DOC,NOM_DOC,TITULO_DOC,AUTOR_DOC,CL_TEMA_DOC,CL_DPT_DOC,CL_TIPO_DOC,FICH_DOC,FECHA_EMISION_DOC,ULTIMA_HORA_DOC,VISIBLE_DOC)
" _
& "Values (" _
& NumeroDocumento & ",'" &
TbTitulo & "','" & TbTitulo & "','" &
TbTitulo.Tag & "',19,2,1,'" & HRefPrensa & "/"
& TbNombFichTIF & "','" & Date & "',0,1)"
MiComando.Execute
ConexBDPrensa.Close
ADO le permite hacer las cosas de maneras muy
distintas, pero siempre debe aportar la misma información. En este caso ha
visto que el objeto Command no hace falta para nada. ¿Entonces, para que
existe? La respuesta es sencilla:
facilita la comprensión del código.
Pero que el objeto Command no le perjudique precisamente eso, la
comprensión del código. No se preocupe de no ser estrictamente académico. Este
humilde autor nunca usa Command excepto para explicarlo. ADO nos permite eso.
Vamos a ver ahora cómo haríamos esto mismo con el
método AddNew.
Deberemos crear un recordset. Lo primero, lo
declaramos:
Dim RsBDPrensa as ADODB.Recodset
Luego lo creamos:
Set RsBDPrensa = New
ADODB.Recordset
Lo abrimos. Pero primero tomamos la
precaución de poner la propiedad CursorLocation del Objeto Connection a
adUseClient (Lado cliente) y de esta
forma los cursores creados para los recordsets abiertos sobre ese objeto
connection estarán del lado cliente. Si el cursor está de lado servidor es
posible que no nos deje usar el método AddNew. (Vea Nota 1)
ConexBDPrensa.CursorLocation = adUseClient
Abrimos el Recordset:
RsBDPrensa.Open "Int_Documentos",
ConexBDPrensa, adOpenDynamic, adLockOptimistic
Ejecutamos el método AddNew
RsBDPrensa.AddNew
Metemos los datos
RsBDPrensa!CL_DOC = NumeroDocumento
RsBDPrensa!NOM_DOC = TbTitulo
RsBDPrensa!TITULO_DOC = TbTitulo
RsBDPrensa!AUTOR_DOC = TbTitulo.Tag
RsBDPrensa!CL_TEMA_DOC = 19
RsBDPrensa!FECHA_EMISION_DOC = Date
RsBDPrensa!CL_DPT_DOC = 2
RsBDPrensa!CL_TIPO_DOC = 1
RsBDPrensa!FICH_DOC = HRefPrensa & "/" & TbNombFichTIF
RsBDPrensa!VISIBLE_DOC = 1
RsBDPrensa!ULTIMA_HORA_DOC = 0
Rematamos con el método Update
RsBDPrensa.Update
Cerramos el recordset.
RsBDPrensa.Close
Cerramos la conexión
ConexBDPrensa.Close
Nota 1. – Muchos
programadores se rinden cuando ven que no les funciona los métodos AddNew / Update
para introducir nuevos datos. Cierto es que cada base de datos se comporta de
forma distinta respecto a este método. Pero antes de rendirse y usar el código
“a capón” intente ver como tienen la propiedad CursorLocation, el tipo de
recordset abierto y el tipo de bloque elegido (Recuerde que por defecto es de
solo lectura). Eso sí, el método “a
capón” funciona siempre (Excepto que sea solo lectura), independientemente del
bloqueo y del tipo de cursor
El
“Control Data” de ADO - (Adodc
ADO Data Control)
Este capítulo parece que quedaba un poco corto. No
por el número de páginas, sino porque tanto en DAO como en RDO nos explayamos
con el control Data, y en ADO parece que solamente lo hemos visto de pasada
para explicar cómo se compone la cadena de conexión. Veámoslo un poco más en
profundidad.
El control Data para ADO es el “Microsoft ADO data control 6.0 (OLEDB)” que se encuentra en
Proyecto | Componentes. La apariencia
es similar a la del Data de DAO
Hagamos un repaso de sus propiedades. Veremos solamente
aquellas que son específicas de ADO:
Propiedad
BOFAction.
Establece la forma de proceder cuando llega a la fila
anterior a la primera. Toma uno de estos valores:
0 – adDoMoveFirst Vuelve
a la primera fila
1 – adDoStayBOF Permanece
en la fila BOF
Es idéntica a la misma propiedad del objeto Command.
Acepta los valores:
AdCmdText Indica que es una definición textual de un
comando o una llamada a un procedimiento almacenado.
AdCmdTable Indica que es un nombre de tabla cuyas columnas se
devuelven todas mediante
una consulta SQL generada internamente.
AdCmdStoredProc Indica que es un nombre de procedimiento almacenado
AdCmdUnknown Predeterminado. El tipo de comando de la propiedad CommandText es desconocido.
Propiedad
ConnectionString
Esta propiedad ya le hemos visto más atrás. Es la
cadena de conexión con la base de datos.
Propiedad
CursorLocation
Es la misma que la vista para el objeto Recordset.
Es la misma que para el objeto Recordset. Acepta los
valores:
1 – adOpenKeyset
2 - adOpenDynamic
3 – adOpenStatic
Propiedad EOFAction
Establece la forma de proceder cuando
llega a la fila EOF. Acepta los valores:
0 – adDoMoveLast Vuelve
a la última fila
1 – adStayEOF Permanece
en la fila EOF
2 – adDoAddNew Añade
una nueva fila
Tipo de Bloque. Igual a la misma propiedad del Objeto
Recordset
Propiedad
MaxRecords
Es similar a la del Objeto Recordset. Establece el
número de filas que obtiene en su recordset asociado.
Propiedad
Mode.
Igual a la misma propiedad del objeto Recordset
Establece la contraseña para crear la
cadena de conexión durante la creación del objeto Recordset asociado. Esta
contraseña es la contraseña del usuario en la base de datos.
Esta
propiedad es solamente de escritura. Si se pretende leer da error.
Establece el nombre del usuario. Debe ser
uno de los usuarios registrados en la base de datos. Esta propiedad es de
lectura y escritura. El valor de la propiedad Password debe ser el asociado a
este usuario.
Es una cadena de caracteres con el nombre de una
tabla o una sentencia SQL que devuelve filas.
Actualiza la información de los controles enlazados a
datos. No existe el método
UpdateRecords.
Vuelve a construir el recordset. Es idéntico al del
control Data de DAO.
Vistas ya las propiedades y métodos del control
Adodc, vamos a ver un poco como funciona y cuales son sus diferencias con el
control data de DAO
Funcionamiento
del Adodc
El Adodc puede enlazar una base de datos a los
típicos controles enlazados (Label, TextBox) usando la tecnología ADO. Los
demás controles enlazados no tienen un comportamiento igual con el Adodc, Control
Data o RDODataControl. En la siguiente lista puede ver que controles trabajan
con uno u otro control Data.
Control ADO RDO DAO Referencia
DBGrid NO SI SI Microsoft Data Bound Grid Control 5.0
SP3
DataGrid SI NO NO Microsoft DataGrid Control 6.0 (OLEDB)
DataList SI SI SI Microsoft Data List Controls 6.0
(OLEDB)
DataCombo SI SI SI Microsoft Data List Controls 6.0
(OLEDB)
DBList SI SI SI Microsoft
Data Bound List Controls 6.0
DBCombo SI SI SI Microsoft Data Bound List Controls 6.0
MSFlexGrid NO SI SI Microsoft FlexGrid Control 6.0
MSHFlexGrid SI NO NO Microsoft Hierarchical FlexGrid Control
6.0 (OLEDB)
Por lo demás el funcionamiento del Adodc es similar
al Control data y al RDODataControl.
Con este capítulo creo que ya tienen conocimientos
suficientes para empezar a trabajar con ADO, y por la tanto, ya tiene permiso
para aprender a programar con esta tecnología.
Le recomiendo paciencia, y sobre todo no tener miedo a esta tecnología.
Y como se dijo al principio, úsela siempre que tenga que usar una base de datos
instalada en un servidor y conectada al usuario a través de una red de área
local. En el próximo capítulo verá como se enlazan un cliente con el servidor
SQL Server.
De cualquier forma no olvide la tecnología DAO para
sus pequeñas aplicaciones, con la base de datos en el mismo ordenador que la
aplicación. Personalmente creo que es mucho más rápida y más sencilla.
Suerte.