Visual Basic Guía del estudiante Cap. 12

Document Sample
Visual Basic Guía del estudiante Cap. 12 Powered By Docstoc
					Visual Basic Guía del estudiante Cap. 12
Objetos DAO
ACCESO A BASES DE DATOS SIN UTILIZAR EL CONTROL DATA

En el capítulo anterior hemos visto los controles capaces de acceder a un Base de Datos,
enlazados mediante un control Data. Se comenzó a exponer que no es necesario usar un
control Data para acceder a leer datos, añadir registros o cambiar su contenido. Y es más.
Comenzaremos ahora a ver que el control Data pese a que puede evitarnos gran cantidad de
líneas de código, nos hace perder el control respecto al programa. Es normal. El control Data
se ha desarrollado para realizar un trabajo muy estándar. Si nuestra aplicación se separa un
poco de lo normal, lo mas probable es que necesitemos realizar las operaciones mediante
código. Esto no quiere decir que el Data haya que dejarlo en desuso. Será necesario en
aquellas aplicaciones en las que se va a usar un control DBGrid, pues como se recordará,
mediante el uso de un control Data metemos en memoria RAM todo el contenido de la base de
datos relativo al Recordset que hemos creado. El control Data será necesario en aquellas
aplicaciones donde utilicemos un DBGrid, un DBList o un DBCombo. Veremos mas
adelante que también será necesario cuando queramos guardar imágenes en una Base de
Datos.

El control Data también permite consultas más rápidas a la BD. El hecho de guardar el
contenido completo del Recordset en la memoria hace que cualquier consulta sea más rápida.
Eso sí, estamos empleando mucha más memoria RAM.

Pero en este capítulo vamos a ver como se pueden manejar bases de datos utilizando otros
objetos de acceso a datos. Concretamente los objetos DAO.- (Data Access Objet).

Los objetos DAO utilizan el Motor de Bases de Datos Jet de Microsoft y trabajan
directamente sobre el fichero que contiene la base de datos. Existen otros objetos de acceso a
datos, como ha podido ver en el capítulo anterior, que no trabajan directamente sobre el
fichero, sino sobre una conexión ODBC que enlaza con la base de datos. Son los objetos RDO
y ADO, cuyo estudio se realizará en capítulos posteriores. Estos últimos tipos son mas
modernos, pero no tienen algunas prestaciones que tienen los DAO, debido precisamente a
que no trabajan directamente sobre el fichero. Centrémonos sobre los objetos DAO

Estos objetos, pese a que no tienen representación en la interface gráfica, son objetos Visual
Basic como los demás, y nos podremos referir a ellos por su nombre como hacíamos con todos
los controles. Eso sí, debemos declararlos como se declaran las variables, y siguen siendo
válidos los criterios de declaración de variables en cuanto al ámbito de aplicación. Si
declaramos un DAO en un procedimiento, no nos podremos referir a él fuera de ese
procedimiento. Si queremos que sea válido en toda la aplicación deberemos declararlo en la
sección de declaraciones de un módulo, o en la sección de declaraciones de un formulario si
fuese suficiente ese ámbito para nuestra aplicación.

La primera sorpresa suele ocurrir a la hora de declarar un objeto. Por ejemplo, para declarar un
objeto tipo DataBase debemos hacerlo con la siguiente declaración:

                        Dim MiBaseDatos As DataBase

Y al ejecutar el programa puede ocurrirle el siguiente error: Error de compilación. No se ha
definido el tipo definido por el usuario.

Lo que le está ocurriendo es que su programa no conoce el tipo de variable DataBase. Para
que la conozca, debe agregarle una referencia. Vaya a Proyecto | Referencias … de la barra
de menú y seleccione Microsoft DAO 3.51 Objet Library Haga click en Aceptar y ya tiene
agregada esa referencia a su programa. Agregar una referencia significa que le ha dicho a su
programa que puede hacer uso de una colección de DLLs donde podrá encontrar la definición



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                        Página 1
del objeto o la variable que no encuentra. Ahora ya no le dará el error anterior, pues en esa
DLL que acaba de agregarle a su programa está la explicación al secreto de lo que es un
objeto DataBase.

Verá que hay mas referencias parecidas a Microsoft DAO 3.51. (Las versiones 2.0, 2.1,
2.5/3.5, y si ha instalado Access2000 tendrá la 3.6) Existen tantas versiones distintas como
versiones de Access. En realidad esta DLL no es mas que un componente de Access que
podemos usar, al igual que lo hace Access, para gestionar una base de datos. Debe elegir la
versión mas alta, pero con cuidado. La versión 3.5 corresponde a la versión de Access 97.
Cuando cree con su programa una base de datos con esta versión, no podrá abrirla con
Access 2.0 No se olvide de la teoría de la compatibilidad de Microsoft, que dice que cualquier
versión que Microsoft considere obsoleta no debe reconocer los datos guardados por versiones
más modernas del mismo programa. Piense si es posible que alguien que vaya a abrir una
base de datos guardada con su aplicación dispone de una versión anterior de Access. Por
ejemplo, cuando se está escribiendo este libro, está recién aparecido Access 2000. ¿Cree que
es oportuno en estos momentos, en los que todavía se está introduciendo en muchos usuarios
Access 97 usar una DLL que nos cree bases de datos que solamente puedan ser abiertas por
Access 2000?.

La versión Microsoft DAO 3.6 corresponde a Access 2000. Si ha instalado este programa le
aparecerá esa referencia en la lista de referencias. No se sorprenda si antes de instalar Access
2000 no tenía esa referencia y después de la instalación sí. Si crea una BD con la versión 3.6
no podrá abrirla con Access 97 ¡Esta es la compatibilidad hacia delante de Microsoft!

Objetos DAO de acceso a datos

Son muchos y tienen estructura jerárquica. Es importante resaltar lo de su estructura
jerárquica, ya que como verá, un objeto DAO crea los objetos DAO inmediatamente inferiores
en jerarquía.

Hay que señalar que las colecciones de estos objetos DAO son a su vez objetos de acceso a
datos. Esto hay que explicarlo un poco mejor. Por ejemplo, un objeto Database es un objeto
DAO que representa una base de datos abierta. Al objeto que agrupa a todas las bases de
datos abiertas en ese momento le llamamos Objeto Databases. Si tenemos dos bases de
datos abiertas en un determinado momento, el objeto Databases contendrá dos elementos.

Todos los objetos DAO excepto el dbEngine tienen colecciones. Es lógico. El dbEngine, como
verá mas adelante, es precisamente el Motor de Bases de Datos Jet y solamente existe uno.
Comenzaremos precisamente por él la explicación de los objetos DAO.

El dbEngine es el motor Jet. Y como vimos en el capítulo anterior, la versión 3.5 puede
trabajar directamente sobre el fichero de la base de datos o a través de una conexión ODBC.
En el primer caso decimos que está trabajando en el espacio de trabajo Microsoft Jet Si le
hacemos trabajar a través de ODBC decimos que estamos trabajando en el espacio de
trabajo ODBCDirect

Los objetos que emplea en cada uno de los espacios de trabajo pueden verse en las figuras
20.1 y 20.2. Puede observarse que tiene muchos mas objetos en el espacio de trabajo
Microsoft Jet que en el de ODBCDirect. Es lógico. Con el primero nos permite CREAR bases
de datos, y por lo tanto necesita tener objetos tales como el Tabledef, Index o Relation. Lo verá
un poco mas adelante.

El objeto dbEngine tiene los siguientes métodos, propiedades y colecciones
Métodos CreateWorkspace, CompactDatabase, RepairDatabase, Idle, RegisterDatabase
Propiedades DefaultPassword, DefaultUser, IniPath, LoginTimeout, Version
Colecciones Errors, Properties, Workspaces

Veremos estos métodos y propiedades según vayamos avanzando en el capítulo


LSB   Visual Basic - Guía del Estudiante   Capítulo 12                        Página 2
Fig. 20.1 Objetos DAO para el espacio de trabajo Microsoft Jet




En esta figura pueden verse los objetos y sus colecciones. Las colecciones llevan el nombre en
plural. Parece un poco complicado, y posiblemente lo será. Lo cierto es que para el trabajo que
se hace normalmente con bases de datos este diagrama queda bastante reducido. No se
extrañe tampoco de ver que objetos como el Fields y el Field existen en varios niveles. Lo verá
mucho mejor mas adelante.




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                       Página 3
Fig. 20.2 Objetos DAO para el espacio de trabajo ODBCDirect




Este modelo parece un poco mas asequible. La razón es que no hace todo lo que hace el
espacio de trabajo Microsoft Jet.



Objeto Workspace
Un objeto Workspace define una sesión de trabajo para un usuario específico. Una sesión de
trabajo es precisamente eso, una sesión de trabajo en el más puro estilo informático. Pueden
existir varias sesiones de trabajo, pero en la mayoría de los casos eso no es lo normal. Será
necesario crear varias sesiones cuando necesitemos imponer restricciones de acceso a una
base de datos, cuando tengamos que usar Transacciones (*) en un sistema multiusuario, y en
algún caso más. Las sesiones de trabajo tienen dueño (Usuario) y una palabra clave para
acceder a ellas.

Pero lo normal es tener solamente una sesión abierta. Y visual Basic nos facilita este caso
abriendo una sesión de trabajo automáticamente. Cuando se inicia Visual Basic, se crea un
Workspace con palabra clave y nombre de usuario Admin. Este Workspace es precisamente
el que ocupa el número cero de la colección de Workspaces. Es decir, es el Workspaces(0).

No se preocupe de que ahora mismo no lo entienda. Ya lo entenderá. Pero hay que exponerlo
ahora. El objeto Workspace contiene:

       Para el espacio de trabajo Microsoft Jet:
       Grupos de trabajo, que es un grupo de usuarios de un entorno multiusuario que
       comparten datos y el mismo sistema de base de datos.
       Grupos de usuarios, que es una colección de cuentas de usuario. Estos objetos, que
       no son objetos de acceso a datos, sino de explotación de los recursos del sistema,
       están enfocados a la seguridad respecto al acceso a las bases de datos que se
       trabajan conjuntamente. No tendría sentido hablar aquí de ellos si no fuese porque
       encontrará referencias a estos objetos continuamente en la ayuda de Visual Basic.
       Bases de Datos (Databases). Este el objeto que ahora nos interesa del objeto
       Workspace. Un objeto Database es una base de datos abierta.




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                     Página 4
       Para el espacio de trabajo ODBCDirect:
       Conexión, que representa una conexión con una base de datos a través de ODBC
       Bases de Datos (Databases).

Ya podemos comenzar a comprender una diferencia entre ambos espacios de trabajo. En el
Microsoft Jet tenemos Usuarios y Grupos de Usuarios. En el espacio ODBCDirect no los
tenemos, ya que el permiso o denegación de acceso de uno u otro usuario a una base de
datos se establece cuando se crea (en Windows) la conexión ODBC. En el espacio
ODBCDirect tenemos un objeto llamado Connection, objeto que no tenemos en el Microsoft
Jet ya que con este sistema accedemos directamente al fichero de la base de datos. No
necesitamos ninguna conexión establecida previamente.

Al objeto Workspace se le puede dar un nombre definido por el usuario. Ese nombre habrá que
declararlo como nombre de una variable objeto Workspace :

                        Dim Misesion as Workspace

La declaración de la variable Objeto tiene las mismas características que cualquier variable en
cuanto al ámbito en el que se puede usar. Para que pueda usarse en toda la aplicación
deberemos declararla en un Módulo con la sentencia Public

                        Public Misesion as Workspace

Esta advertencia es válida para la declaración de todos los objetos DAO.

Una vez declarado el nombre del objeto Workspace, hay que crearlo. En realidad, y tal como
citábamos mas atrás, cada vez que se inicia una sesión de Visual Basic, se crea
automáticamente un Workspace. El número 0 A este Workspace no podemos ponerle ningún
tipo de palabra de acceso, ya que se la ha puesto VB : Admin. Utilicemos este Workspace, el
número 0 de la colección Workspaces, para comenzar a trabajar. Tiempo tendremos mas
adelante de ver como se crea un Workspace. Para hacer que Misesion sea ese Workspace
que crea automáticamente VB basta con ejecutar la siguiente línea de código

                        Set Misesion = Workspaces(0)

Pero si no queremos aprovechar este Workspace creado automáticamente por Visual Basic, y
queremos usar otro, usemos el método CreateWorkspace. Se verá al final del capítulo.

Creación de Objetos DAO
Para crear un objeto DAO (Cualquiera que sea) debemos usar una forma que se va a repetir a
lo largo de toda su vida profesional, mientras trabaje con Visual Basic y Bases de Datos:

        Set ObjetoDAOInferior = ObjetoDAOSuperior.Método ( Aquí .... alguna cosa )

Logicamente el término Aquí .... alguna cosa va a depender de cada método y de lo que Vd.
quiera hacer, pero la estructura Set DAOInferior = DAOSuperior.Método ( - - - - - - - - - - )
se mantendrá en todas las operaciones de creación y manipulación de objetos DAO. Esta
sintaxis es tan simple que un profesor de Visual Basic decía que es como un “juego de niños”
No lo olvide y se le quitará el miedo al manejo de bases de datos mediante código.
Posiblemente hasta ahora le haya parecido muy difícil y haya optado por usar el control Data
para todas sus aplicaciones. Si recuerda este Juego de niños verá que es más sencillo crear
objetos DAO que poner un control Data en un formulario.

Comenzaremos a explicar la operación de bases de datos mediante DAO explicando como se
crean bases de datos Access mediante Visual Basic. ¿Para que se van a crear bases de datos
mediante un programa si puedo hacerlo directamente con Access? . Esta pregunta me la han
hecho los alumnos durante todos mis años de docencia. La única respuesta para ello es que
deseo que Vd. sea programador, no usuario de ofimática.



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                       Página 5
Objeto Database
Un objeto Database representa una base de datos abierta. Una colección Databases
contiene todos los objetos Database abiertos en un objeto Workspace del motor de bases de
datos Microsoft Jet.

Un objeto Database puede crearse, bien porque hemos creado una base de datos mediante el
procedimiento CreateDataBase, o porque hemos abierto una base de datos existente
mediante el procedimiento OpenDatabase. En cualquiera de los dos casos, el objeto
Database existe hasta que lo cerremos (mediante el método Close) o hasta que cerremos la
aplicación.

Al objeto Database se le debe dar un nombre definido por el usuario. Eso sí, hay que
declararlo como una variable objeto Database

                       Dim MiDataBase As Database

El nombre que le demos al objeto DataBase no tiene nada que ver con el nombre del fichero
que alberga esa base de datos. El objeto DataBase es la base de datos que creamos en la
memoria RAM del ordenador.

Colección Databases Es el conjunto de Objetos Database existentes. La colección
Databases pertenece al Workspace.




Crear una Base de Datos ACCESS. Método CreateDatabase
Para crear una base de datos deberemos utilizar el método CreateDatabase. Previamente
debemos declarar el nombre que queremos dar al objeto DataBase que se va a crear como un
objeto Database :

                       Dim MiBaseDatos as Database

Si tenemos declarado un Workspace llamado Misesion mediante la declaración :

                       Dim Misesion as Workspace

Y hacemos que Misesion sea el Workspace creado automáticamente por VB

                       Set Misesion = Workspaces (0)

podremos usar el método del Workspace CreateDatabase para crear ese objeto Database.
Recuerde que el objeto Database NO es el fichero que va a contener la base de datos sino que
es una estructura de base de datos que está de momento en la memoria RAM del ordenador.
El fichero se creará posteriormente cuando cerremos el objeto Database. El nombre del objeto
Database tampoco tiene porque coincidir con el nombre del fichero que se va a crear. En el
ejemplo que veremos mas adelante, el nombre del objeto Database es MiBaseDatos y el
nombre del fichero es MiBase.Mdb.

La sintaxis del método CreateDataBase es el “juego de niños” citado antes:

       Set ObjetoDAOInferior = ObjetoDAOSuperior.Método ( Parámetros )

En nuestro caso el Objeto DAO superior es el Workspace Misesion, y los parámetros que hay
que pasar en este caso son:




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                       Página 6
Nombre (y Path) del fichero de la base de datos
Idioma, para permitir la ordenación alfabética de los datos. Para los idiomas español, inglés y
francés debe usar dbLangGeneral.
Opciones, que le permite elegir la versión de la base de datos a crear (Equivalente a la versión
de Access) y si deseamos crear una base de datos cifrada. Si no pone nada en este parámetro
le crea una base de datos sin cifrar, y de la última versión que le permite la referencia elegida
para el motor de bases de datos (Microsoft DAO 3,51, por ejemplo)

Vayamos al ejemplo:

Set MiBaseDatos = Misesion.CreateDatabase (“C:\MiCarpeta\MiBase.MDB”, dbLangGeneral)

Si ahora cierra el programa le creará la Base en el disco. Ejecute Access y abra la BD
C:\MiCarpeta\MiBase.MDB. ¡Ya Existe! Pero observará que está completamente vacía. Es
normal. Una Base de Datos ACCESS tiene tablas. Y de momento no hemos escrito ningún
código para crear esas tablas. Vamos a seguir creando esta base de datos, al tiempo que
explicamos el resto de los procedimientos que hay que usar para ello.


El Método CreateDataBase Crea un nuevo objeto Database, guarda la base de datos en disco
y devuelve un objeto Database abierto.

Vaya a la ayuda de VB. Verá que la sintaxis de este método es:

Set MiBaseDatos = Misesion.CreateDatabase (nombre_base, escenario, opciones)


MiBaseDatos es el nombre del objeto Database por el cual nos referiremos a esa base de
datos, NO el nombre del archivo con el que quedará guardada en el disco.

Misesion es el nombre del objeto Workspace existente que contendrá la base de datos. Si se
omite este argumento, se utilizará el objeto Workspace predeterminado - Workspaces(0) – e
incluso, si no se pone nada, usará ese Workspace predeterminado.

nombre_base es el nombre del archivo de base de datos que se va a crear. Es decir, el
nombre del archivo en el disco. Puede ser una ruta completa y un nombre de archivo, como por
ejemplo "C:\MiCarpeta\MiBase.MDB". Si no se indica una extensión, se agregará .MDB. Si la
red lo admite, también puede especificar una ruta de red, como por ejemplo
"\\MISERVID\MICOMP\MIDIR\MIBD". Con este método sólo pueden crearse archivos de base
de datos .MDB. (ACCESS)

escenario es una expresión de cadena utilizada para especificar dos cosas: el orden alfabético
que se va a usar en esta base de datos, (Obligatorio) que denominaremos inf_local y el
Password o palabra clave que quiere usar para restringir su uso. Este Password es opcional.
Debe especificar el argumento inf_local o se producirá un error. Consulte la tabla de
constantes para inf_local incluida más adelante en este tema.

En el argumento Opciones puede combinar varias opciones, según se especifica a mas
adelante. Puede combinar varias opciones sumando las constantes correspondientes.




Valores de los parámetros

En el argumento inf_local se suministra información de la lengua empleada para especificar la
propiedad CollatingOrder del texto para las comparaciones entre cadenas. Es un argumento
obligatorio. Para los idiomas Inglés, alemán, francés, portugués, italiano y español moderno
se usa la siguiente constante :



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                        Página 7
                dbLangGeneral

No use dbLangSpanish. pues no hace nada especial respecto a dbLangGeneral

Este parámetro es obligatorio. Piense que una vez creada la Base de Datos, alguna vez le
pedirá que le obtenga un Recordset con los datos ordenados alfabéticamente ( acuérdese de
la sentencia SQL ORDER BY Nombredelcampo )

Si desea introducir una palabra clave para restringir el acceso a la base de datos, debe
indicarlo a continuación. Deberá concatenarlo con la inf_local mediante el signo & y separarlo
mediante punto y coma. Hay que poner pwd antes de la contraseña

                dbLangGeneral & ";pwd=NuevaContraseña"

Para el último parámetro, Opciones se pueden usar las siguientes constantes :

Constante       Descripción

dbEncrypt      Crea una base de datos codificada.
dbVersion10    Crea una base de datos que utiliza la versión 1.0 del motor de base de datos
               Microsoft Jet.
dbVersion11    Crea una base de datos que utiliza la versión 1.1 del motor de base de datos
               Microsoft Jet.
dbVersion25    Crea una base de datos que utiliza la versión 2.5 del motor de base de datos
               Microsoft Jet.
dbVersion30    Crea una base de datos que utiliza la versión 3.0 del motor de base de datos
               Microsoft Jet. Esta Versión es compatible con la 3.5

Si se omite la constante de codificación, se creará una base de datos no codificada.
El método CreateDataBase abre esta nueva base de datos y devuelve un objeto Database,
cuya estructura y contenido deberá completar utilizando objetos de acceso a datos adicionales.
Es decir, crea una Base de Datos sin nada que deberá rellenarla posteriormente con tablas.

(Advertencia sobre las bases de datos codificadas. No piense que al codificar la base de
datos va a mantener sus datos confidenciales en secreto. Access se los guardará codificados,
pero se los va a presentar de forma clara. Utilice para ello el Password, ya que no podrá abrir
la base si no se conoce ese Password. Pero tampoco se fíe mucho. Existen infinidad de
craqueadores de contraseñas de Access. El Password vale para proteger la BD de usuarios no
“piratas”. No emplee este procedimiento en aplicaciones en las que necesite verdadera
confidencialidad.

Objetos DAO para introducir en una base de datos

Estos objetos que se pueden añadir son : Objetos TableDef, TableDefs, Field, Fields,
QueryDef, QueryDefs. Para hacer las cosas poco a poco nos fijaremos solamente en las
tablas y los campos. (Objetos Tabledef y Field)

El Objeto TableDef es una tabla de una base de datos ACCESS. El Objeto TableDefs es la
colección que contiene todas las tablas de la base de datos

Un objeto Field representa un campo dentro de una tabla Access. La colección Fields contiene
todos los campos de una tabla. Verá mas adelante que también hay objetos Field en otros
objetos DAO (Index, QueryDef, Recordset, Relation), pero de momento vamos a fijarnos
solamente en las tablas.

Crear una Tabla. Método CreateTableDef.
Crea un objeto Tabledef, que no es ni más ni menos que la estructura de una tabla Access,
pero que de momento está en la memoria RAM del ordenador. Cuando esa estructura se pase



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                       Página 8
al fichero de la base de datos en el disco, será una Tabla que podemos ver cuando abramos la
BD con Access.

El objeto Tabledef debe crearlo un objeto DataBase. Puede ser perfectamente el objeto
Database creado anteriormente. Pero seguramente lo ha cerrado (cerrando el programa,
simplemente) para poder ver con Access la base de datos que acaba de crear. Puede volver a
crear el objeto DataBase abriendo la base de datos. Aunque se le explicará mas tarde, le
adelanto el método para abrir una base de datos existente en el disco:

       Set MiBaseDatos = Misesion.OpenDatabase (“C:\MiCarpeta\MiBase.MDB”)

Declaremos ahora el nombre que quiere ponerle al objeto Tabledef que va a crear: (MiTabla1)

                       Dim Mitabla1 As Tabledef

Si queremos introducir varias tablas en la BD deberemos declarar tantos objetos Tabledef
como tablas necesitemos:

       Dim MiTabla2 as Tabledef, MiTabla3 as Tabledef, ……

y crearemos las tablas necesarias mediante el método CreateTableDef

Si acude a la información de VB para ver los parámetros que hay que pasar en el método
CreateTableDef verá que son muchos: ([nombre[, atributos[, origen[, conexión]]]]) Se explicará
para que sirven todos ellos, pero de momento nos quedamos únicamente con el primero:
Nombre, que es el nombre que podrá ver en Access como nombre de la tabla que va a crear.

       Set Mitabla1 = MiBaseDatos.CreateTableDef (Nombre)

Ejemplo:       Set Mitabla1 = MiBaseDatos.CreateTableDef (“Alumnos”)

Si queremos crear más Tabladefs:

               Set Mitabla2 = MiBaseDatos.CreateTableDef (“Profesores”)
               Set Mitabla3 = MiBaseDatos.CreateTableDef (“Asignaturas”)

De momento solamente hemos creado uno o varios objetos Tabledef. Pero como siempre,
vacíos. Una tabla tiene campos. Un objeto Tabledef tiene Fields. Debemos crear objetos Field
(Campos) para poder meterlos en los objetos Tabledef que acabamos de crear.

Crear campos. Método CreateField
Crea un objeto Field, que es la estructura de lo que mas tarde será un Campo de una tabla de
la BD. El objeto Field solamente está en la memoria RAM del ordenador. Cuando pase a
formar parte de una tabla será un campo de esa tabla.

El objeto Field debe crearlo el objeto DAO superior a él: el Tabledef. Previamente
declararemos los nombres de los Objetos Field a introducir.

               Dim MiCampo11 as Field, MiCampo121 as Field, MiCampo21 as Field

(El Campo11 es el primer campo que meteremos en el Tabledef Tabla1. El Campo12 el
segundo, el Campo21 será el primer campo del Tabledef Tabla2, etc.

Los parámetros que vamos a pasar en este método son:

Nombre         Será el nombre de ese campo. P.e. NombreAlumno, Apellidos, etc
Tipo           Tipo de dato, String, numérico, Date, etc
Tamaño         Sólo para los campos String. Indicará el número de caracteres de ese campo.



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                      Página 9
Creamos el objeto Field con la siguiente sintaxis

        Set MiCampo11 = Mitabla1.CreateField ([nombre[, tipo [, tamaño]]])

(Vea el Anexo 1 Propiedades de los campos al final de este capítulo)

Ejemplos
       Set MiCampo11 = Mitabla1.CreateField (“ID_Alumno”, dbText, 8)
       Set MiCampo12 = Mitabla1.CreateField (“NombreAlumno”, dbText, 20)
       Set MiCampo13 = Mitabla1.CreateField (“Apellidos”, dbText, 25)
       Set MiCampo14 = Mitabla1.CreateField (“Edad”, dbInteger)
       Set MiCampo15 = Mitabla1.CreateField (“Fecha_Ingreso”, dbDate)

        Set MiCampo21 = Mitabla2.CreateField (“NombreProfesor”, dbText, 20)

Se crean todos los campos que se quieren introducir en las tablas. Observe que cada objeto
Field debe ser creado por el objeto Tabledef que lo va a contener. (MiTabla1 crea todos sus
campos, MiTabla2 los suyos, etc)

Ya están todos los campos creados, pero todavía no están metidos en las tablas. Tenemos que
añadirlos a la colección de campos de la tabla que los creó. Esa colección de campos es el
Objeto Fields de la tabla. Se añade mediante el método Append.

        MiTabla1.Fields.Append Micampo11
        MiTabla1.Fields.Append Micampo12
        MiTabla1.Fields.Append Micampo13
        MiTabla1.Fields.Append Micampo14
        MiTabla1.Fields.Append Micampo15

        MiTabla2.Fields.Append Micampo21

Ya tenemos campos formando parte de la colección Fields de las tablas. Ahora debemos
añadir las tablas a la colección de tablas de la base de datos. Esa colección de tablas es el
objeto Tabledefs de la base de datos, es decir, del objeto DataBase. Lo haremos también
mediante el método Append

        MiBaseDatos.TableDefs.Append Mitabla1
        MiBaseDatos.Tabledefs.Append Mitabla2

Si ahora cerramos la base de datos mediante el método Close:

        MiBaseDatos.Close

Ya tenemos la base de datos creada en el disco de la misma forma que lo hubiera hecho
Access. Pero puede que le falte algo respecto a una base creada directamente con Access: los
Indices y las Relaciones.

Un índice es una marca que le podemos poner a cada uno de los registros en un campo. Esa
marca puede servir por ejemplo, para ordenar los registros de la BD por ese campo. Puede
servir también para evitar que dos registros tengan el mismo valor para un determinado campo.
En el ejemplo que estamos preparando, el Campo11 (ID_Alumno) queremos que sea un
índice, y además que no se pueda repetir el mismo valor para dos registros distintos, de forma
que no puedan existir dos registros con el mismo valor en ese campo.

Una Relación es una correspondencia entre un campo de una tabla y otro campo de
características similares en otra tabla. Esto nos lleva al concepto de Base de Datos Relacional
que seguramente ya sabe de que se trata. En Access se puede establecer una relación de una
forma muy sencilla. En Visual Basic también. Pero antes de seguir reflexionemos y recordemos
lo que hemos hecho hasta ahora.




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                       Página 10
Observe que, cada vez que creamos un objetos (DataBase, Tabledef, Field) usamos el
mencionado “juego de niños”. El método correspondiente para crear un objeto DAO pertenece
al objeto DAO inmediatamente superior en jerarquía, es decir, CreateDatabase es un método
del objeto Workspace, CreateTableDef es un método del objeto Database, CreateField es un
método del objetos TableDef.

Las colecciones pertenecen también al objeto inmediatamente superior en jerarquía al tipo de
objetos que forman la colección. La colección Fields (Objeto Fields) pertenece a un objeto
TableDef, la colección TableDefs (objeto TableDefs) pertenece a un objeto Database, y la
colección Databases (Objeto Databases) pertenece a un objeto Workspace. La colección
Workspaces pertenece al DBEngine, y el DBEngine ya no podemos asignarlo a ningún objeto
DAO. Tendremos que decir que pertenece al sistema.

Recordemos ese “juego de niños” :

               Set DAOInferior = DAOSuperior.Método ( - - - - - -)

Hemos visto que después de crear un objeto, debemos añadirlo a la colección a la que debe
pertenecer con el método Append. El procedimiento es siempre el mismo :

               Objeto superior.Colección.Append Objeto a añadir

Sigamos ahora perfeccionando la base de datos. Vamos a ver como se crea un Indice.


Crear Indices para los campos. Método CreateIndex
Para crear un índice debe estar creado el campo al que se le va a aplicar el índice. Puede que
le parezca un poco extraño alguno de los métodos que vamos a usar para crear un índice,
como por ejemplo volver a usar el procedimiento CreateField para crear un campo que ya
existe. Son las incongruencias que tiene a veces Visual Basic. Le recomiendo que si no se
acuerda bien de cómo se hace, recurra a la ayuda de VB, que en este caso es exacta y
concisa. O si lo prefiere, al ejemplo que ilustra esta Guía del Estudiante como colofón a este
capítulo.

Primer debemos crear el Objeto Index. Se hace mediante el método del objeto Tabledef,
CreateIndex. El índice debe crearlo el Tabledef al que pertenece el campo que queremos que
sea índice. La sintaxis de CreateIndex es:

               Set NombreIndice = NombreTabledef.CreateIndex([Nombre])

Donde NombreIndice es el nombre de una variable declarada como tipo de dato objeto Index.
NombreTabledef es el nombre de variable del objeto TableDef que se desea usar para crear el
nuevo objeto Index.
Nombre es una variable de tipo String que da un nombre único al nuevo objeto Index. Este
nombre lo puede ver si abre la base de datos con Access y en la vista de Diseño de la tabla,
abre la función Ver | Indices de la barra de menú.

En nuestro ejemplo:

Declaramos el objeto Index

               Dim MiIndice as Index

Creamos el índice

               Set MiIndice = MiTabla1.CreateIndex (“Indice1”)




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                      Página 11
Ya tenemos creado el Objeto Index. Ahora, (y aquí empieza la incongruencia citada) este
objeto Index debe crear el campo que queremos que sea índice. Pero ese campo ya debe
existir en el objeto Tabledef con el que hemos creado el índice (en este caso, en MiTabla1)

                Set MiCampo11 = MiIndice.CreateField (“ID_Alumno”, dbText, 8)

El nombre del campo, tipo y tamaño deben coincidir con los datos que sirvieron para crear el
campo en el objeto Tabledef.

Pero un índice puede tener varios campos. Por ejemplo, piense en el código de un objeto en un
inventario. El código es el número que identifica de forma unívoca a un objeto. Un objeto
inventariable (por ejemplo una mesa) tiene un código de grupo (por ejemplo, el 123) Hay
muchas mesas dentro de un inventario, pero todas ellas tienen un número distinto (una tiene el
001, otra el 002, etc) La combinación de código de grupo más el número del objeto dentro de
ese grupo queremos que sea un índice. Ese índice estará formado entonces por dos campos.
En este caso deberemos crear los dos campos:

                Set MiCampo11 = MiIndice.CreateField (“C_Grupo”, dbText, 3)
                Set MiCampo12 = MiIndice.CreateField (“Numero”, dbText, 3)

Ya tenemos el campo o los campos creados por el índice. Ahora debemos añadirlo (o
añadirlos) a la colección Fields del objeto Index recién creado. Lo hacemos mediante el
método Append

                MiIndice.Fields.Append MiCampo11

Si fuesen dos los campos

                MiIndice.Fields.Append MiCampo11
                MiIndice.Fields.Append MiCampo12

No crea que ya hemos terminado. Un objeto Index tiene propiedades. Una de ellas ya la hemos
visto sin querer, la propiedad Name (nombre del índice, en nuestro ejemplo, Indice1). Otras
propiedades son:

Primary - El objeto Index representa la clave primaria de la tabla.
Unique - No permite repetición de valores en ese campo
Required - Indica que todos los campos del objeto Index deben rellenarse.
IgnoreNulls - Indica si permite valores Nulos en los campos del índice.

(Existen además las propiedades Clustered, Foreign, DistinctCount que no se explican para
no complicar mas el tema. Cuando los necesite no tendrá inconveniente en estudiarlos
partiendo de la ayuda de VB)

Para introducir el valor de una de estas propiedades se procede con la siguiente sintaxis:

                MiIndice.Uniuqe = True
                MiIndice.Primary = True

Ya está creado el índice y tiene ya metido uno o mas campos y todas sus propiedades. Ahora
debemos añadir ese índice a la colección Indexes del Objeto Tabledef.

                MiTabla1.Indexes.Append MiIndice


Lo confieso. Cada vez que hago esto en la vida real tengo que volver a leer este procedimiento
en la Guía del Estudiante. Es complicado, pero alguna vez se terminará aprendiendo.




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                        Página 12
Ya tenemos la base de datos completamente creada. Sin embargo alguien dirá que le falta
algo: Relacionar dos tablas


Relaciones entre tablas Método CreateRelation
Una Relación es una asociación establecida entre dos campos del mismo tipo ubicados en dos
tablas distintas. Se pueden establecer relaciones uno a uno ó uno a varios. Para relacionar un
campo con otros, ese campo debe ser clave primaria. A la tabla que contiene a este campo se
le llama Tabla Principal. A la tabla que contiene el campo (o los campos) relacionados se le
llama Tabla Relacionada.

Para crear una relación, usaremos un nuevo objeto DAO : El objeto Relation. Este objeto
forma parte de una colección, que es a su ves otro objeto DAO : el objeto Relations.

Para crear una relación usaremos el Método CreateRelation, que es un método del objeto
Database. (Lógico, una relación se establece entre dos tablas. Por lo tanto, la relación debe
pertenecer al objeto DAO superior jerárquicamente a las tablas: el Objeto Database. Como
para cualquier otro objeto DAO, es necesario declararlo :

               Dim MiRelacion as Relation

Para crear la relación deberemos usar el método CreateRelation

               Set MiRelacion = MiBaseDatos.CreateRelation ("RelacionUno")

Una relación se hace entre dos campos. Una relación debe tener campos. Por lo tanto,
deberemos hacer una cosa similar a la que hacíamos para el método CreateIndex, crear los
campos mediante el Objeto Relation que acabamos de crear. Pero esos campos ya deben
estar creados en las tablas que se van a relacionar.

Supongamos que queremos crear una relación en la base de datos creada en el ejemplo
anterior, y queremos relacionar el campo Campo11 que está en MiTabla1 y que lo habíamos
hecho clave primaria, con el campo Campo21 de MiTabla2. MiTabla1 y MiTabla2 son los
nombres reales de las tablas, NO los nombres de los objetos Tabledef.

El ejemplo que trae la ayuda de VB puede ser muy aclaratorio, pero le advertimos lo mismo
que para los índices, paciencia. Una vez creada la relación, podrá comprobarlo visualizándola
con el visor de relaciones del Access

Suponemos que la base de datos está abierta. Si no lo está, la abrimos.

       Set MiBaseDatos = Workspaces(0).OpenDatabase("MIBD.MDB")

Creamos el objeto Relation, que tendrá por nombre RelacionUno, pero este nombre NO debe
confundirse con el nombre del objeto DAO Relation, que es MiRelacion

       Set MiRelacion = MiBaseDatos.CreateRelation ("RelacionUno")

Una vez creada, le decimos a MiRelacion cual es la Tabla principal

       MiRelación.Table = "MiTabla1"                     'Nombre de la tabla principal.

Le decimos cual es el nombre de la tabla relacionada

       MiRelación.ForeignTable = "MiTabla2"              ‘Nombre de la tabla relacionada

Le ponemos los atributos a la relación. En este caso dbRelationUpdateCascade, para que, si
hacemos un cambio en el valor del campo de la tabla principal, ese cambio se refleje en el
campo o los campos relacionados con el.


LSB   Visual Basic - Guía del Estudiante   Capítulo 12                        Página 13
        MiRelación.Attributes = dbRelationUpdateCascade

Le decimos cual es el nombre del campo de la tabla principal que vamos a relacionar, mediante
el método CreateField. Deberemos declarar el nombre del objeto Field que vamos a crear para
la relación

        Dim MiCampo as Field

        Set MiCampo = MiRelación.CreateField("Campo11")

Le recordamos lo de antes. Campo11 debe estar ya creado en la tabla Tabla1. Parece un
poco ilógico usar el método CreateField para un campo que ya está creado.

Le decimos ahora cual es el nombre del campo en la tabla relacionada

        MiCampo.ForeignName = "Campo21"

Añadimos el campo creado a la colección Fields del objeto Relation

        MiRelación.Fields.Append MiCampo

Y ahora añadimos el objeto Relation recién creado a la colección Relations del objeto Database

        MiBaseDatos.Relations.Append MiRelación

Solamente nos falta ver que valores puede tener la propiedad Attributes del objeto Relation

dbRelationUnique                La relación es uno a uno.
dbRelationDontEnforce           La relación no es impuesta (no hay integridad referencial).
dbRelationInherited             La relación existe en una base de datos no activa que contiene
                                las dos tablas vinculadas.
dbRelationUpdateCascade         Las actualizaciones se realizarán en cascada.
dbRelationDeleteCascade         Las eliminaciones se realizarán en cascada.

Ahora ya casi podemos decir que tenemos la base de datos creada. Puede que sea así o que
le falte alguna cosa. Puede faltarle una o varias consultas. Las consultas también se pueden
crear mediante objetos DAO. Precisamente con un objeto QueryDef


Consultas. El Objeto QueryDef
Pero habrá observado que una base de datos ACCESS puede contener, además de tablas,
CONSULTAS. Las consultas no contienen datos. Contienen una referencia a los registros de
las tablas que los contienen. Una consulta podríamos decir que son conjuntos de registros
tomados de una o varias tablas (en este último caso, esas tablas deben estar relacionadas)
que cumplen unas determinadas condiciones. Pero aunque podemos ver esos registros como
tales, con sus datos exactamente igual que si se tratase de los registros de una tabla, las
consultas no contienen el dato, sino el número del registro dentro de la tabla que lo contiene. A
la hora de presentar los datos de una consulta, lo que estamos presentando son los datos
almacenados en la tabla o las tablas que componen esa consulta.

Crear una consulta. Método CreateQueryDef
Un objeto QueryDef representa una consulta de la base de datos. El objeto QueryDefs es la
colección de objetos QueryDef. La diferencia entre una consulta (Un QueryDef) y una tabla
(Un TableDef) es que la Tabla tiene dentro de sí los datos. La consulta tiene dentro una
referencia al lugar de las tablas donde se encuentran los datos.




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                        Página 14
Antes de utilizar el método CreateQueryDef debe declarar el nombre de los objetos a crear,
declarándolos como Variables Objeto tipo QueryDef . El ámbito es igual que para cualquier
variable:

         Public MiConsulta1 as QueryDef
         Public MiConsulta2 as QueryDef

Ahora podemos utilizar el método CreateQueryDef para crear el nuevo objeto QueryDef en la
base de datos.

Sintaxis Con la fórmula de siempre :

         Set MiConsulta1 = MiBaseDatos.CreateQueryDef ([Nombre][, Texto_sql])

Donde

MiConsulta1 es una variable del tipo QueryDef que previamente se ha declarado como tal.
Será el nombre por el que llamemos al Objeto QueryDef en el código de nuestra aplicación.
MiBaseDatos es el nombre del objeto Database abierto en el que vamos a introducir el nuevo
objeto QueryDef.
Nombre es una expresión de cadena que representa el nombre de la nueva consulta que
vamos a crear. Este nombre será el que veamos al abrir la base de datos con Access en la
pestaña Consultas. Puede omitirlo a la hora de crear la consulta, pero deberá añadirselo
posteriormente.
Texto_sql es una expresión de cadena (instrucción SQL válida) que define el objeto
QueryDef.
Lógicamente una consulta nos debe suministrar una serie de datos de una o mas tablas. Esos
datos no tienen porqué ser todos los datos de las tablas. Texto_sql es precisamente el filtro de
esos datos (expresado mediante una cláusula SQL).

Una vez creado el objeto QueryDef, no es necesario añadirlo a la colección QueryDefs de la
Base de Datos, excepto que hayamos creado el objeto QueryDef sin nombre. (Sin haber
puesto el parámetro Nombre, según se comentó mas atrás). Para añadirlo a la colección
QueryDefs :

         MiBaseDatos.QueryDefs.Append MiConsulta1

Como caso práctico de creación de una consulta, podemos tener

         Set MiConsulta1 = MiBaseDatos.CreateQueryDef (“Fernandez”, “Select Nombre,
         Apellido1, Apellido2 From Alumnos Where Apellido1 = ‘Fernandez’ )

Ahora ya tenemos la base de datos creada con todas las posibilidades. Ha llegado el momento
de crear una base real para comprobar todo lo expuesto.


Ejemplo práctico de creación de una base de datos. El famoso
ejercicio del Videoclub
Vayamos a un ejemplo típico en cualquier curso de Visual Basic: el famoso Videoclub. Un
videoclub tiene una base de datos en la que tenemos una tabla, de nombre Clientes donde
figuran los nombres y dirección de los clientes, así como el número de su cuenta bancaria.
Tiene un campo (ID_Cliente) que es el que define al cliente. Será un campo tipo texto, que
albergará un número que se incrementará en 1 cada vez que se hace un nuevo cliente. Cada
cliente tiene un ID_Cliente y ese ID_Cliente es único para él. (Este campo podría ser un
autonumérico, pero personalmente no me gusta usar autonuméricos. Un autonumérico es un
Long –numérico- y quiero ser coherente con lo expuesto en el capítulo 1 donde se decía que
solamente se usarían campos numéricos en aquellos datos con los que se hagan operaciones




LSB     Visual Basic - Guía del Estudiante   Capítulo 12                      Página 15
matemáticas) El campo ID_Cliente será clave primaria, ya que no pueden existir dos clientes
con el mismo ID_Cliente.

Otra tabla necesaria será la tabla Peliculas, donde introduciremos todos los datos relativos a
las películas (existentes o no en el videoclub), tal como título, director, artistas, resumen,
calificación, precio, etc. Tendrá un campo, ID_Pelicula que identificará a esa película. Pero
puede haber versiones en varios idiomas, por lo tanto, existirá otro campo Idioma de tipo texto,
para introducir ese dato. Por lo tanto, una película deberemos definirla por el conjunto formado
por su ID_Pelicula y por su Idioma. El conjunto de esos dos campos será la clave primaria. (Si
cree que hay campos que no tienen sentido en esta tabla (Idioma), piense que esto es un
ejemplo para poder explicar de la forma más didáctica todas las posibles variaciones de una
instrucción)

Existe otra tabla denominada Cintas, donde figurarán todas las cintas existentes en el
videoclub. Para poder relacionarla con la tabla Peliculas, le ponemos un campo llamado
ID_Pelicula que en esta tabla no será clave primaria. También le pondremos el campo Idioma,
sobre el que no haremos ningún tipo de relación. Tendrá un campo ID_Cinta que será la
combinación de varios datos, uno que nos indique la película que tiene grabada esa cinta (Será
la combinación de los campos ID_Pelicula e Idioma) y de un número secuencial que indicará
el número de la copia. Si le pone imaginación y este conjunto de datos puede meterse en un
código de barras, le facilitará la operación de alquiler y devolución. En este ejercicio haremos
que sea así, dándole a este campo un tamaño de 13 dígitos para poder meterlo en un código
EAN-13. Podemos añadirle mas campos a nivel administrativo, como fecha de alta, fecha de
baja, precio de esta copia, etc.


Existirá una tercera tabla, Alquileres, que relacionará al cliente con la cinta que ha alquilado.
Tendrá un campo llamado ID_Cliente y otro ID_Cinta. Aparte tendrá otros dos campos, fecha
de alquiler y fecha de devolución.

La base de datos deberá tener dos relaciones, una, entre el campo ID_Cliente de la tabla
Clientes y el campo ID_Clientes de la tabla alquileres (Será uno a infinito) y otra relación, entre
el campo ID_Cinta de la tabla Cintas y el campo ID_Cinta de la tabla Alquileres (Relación 1 a 1
ya que solamente existe una cinta con esa ID_Cinta). Para darle más alegría al ejercicio le
pondremos una relación entre los campos ID_Pelicula e Idioma de las tablas Peliculas y Cintas.
(Se ha puesto el nombre de Pelicula al campo relacionado con ID_Pelicula para que se vea
que dos campos relacionados no tienen porqué tener el mismo nombre. Eso sí, deben tener las
mismas características)
Como colofón a todo esto, crearemos una consulta en la que utilizaremos todas las relaciones.

Para llevar a cabo este ejercicio se ha partido de una interface gráfica en la que pueden verse
tres botones (Borrar la base de datos, crearla y salir) y un TextBox donde se ha puesto el
nombre del fichero de la base de datos en su propiedad Text. Veamos el código de cada uno
de los botones (por orden inverso de complejidad del código)




Fig. 20.3 Interface gráfica de la parte de crear bases de datos para la aplicación del Videoclub

CODIGO

Private Sub BSalir_Click()
Unload Me
End Sub



LSB   Visual Basic - Guía del Estudiante    Capítulo 12                         Página 16
Private Sub BBorrar_Click()
On Error GoTo RutErr
Dim HayDir As String
HayDir = Dir(TBNombreBase)
   If HayDir <> "" Then
   Kill TBNombreBase
   End If
RutErr:
If Err = 75 Then
MsgBox "Tiene la Base de Datos abierta por otro programa"
End If
End Sub

Creación de la base de datos

Private Sub BCrear_Click()
On Error GoTo RutErr

Dim HayDir As String ‘Se comprueba que existe la BD y se invita a borrarla
HayDir = Dir(TBNombreBase)
If HayDir <> "" Then
MsgBox "Ya existe el fichero con la base de datos. Debe borrarlo previamente"
Exit Sub
End If

‘ Se declaran todas las variables tipo objeto
Dim MiBaseDatos As Database
Dim MiTabla1 As TableDef, MiTabla2 As TableDef, MiTabla3 As TableDef
Dim MiTabla4 As TableDef
Dim MiCampo11 As Field, MiCampo12 As Field, MiCampo13 As Field
Dim MiCampo14 As Field, MiCampo15 As Field, MiCampo21 As Field
Dim MiCampo22 As Field, MiCampo23 As Field, MiCampo24 As Field
Dim MiCampo25 As Field, MiCampo31 As Field, MiCampo32 As Field
Dim MiCampo33 As Field, MiCampo34 As Field, MiCampo35 As Field
Dim MiCampo36 As Field, MiCampo41 As Field, MiCampo42 As Field
Dim MiCampo43 As Field, MiCampo44 As Field

‘Se crea el Objeto DataBase (Se toma el nombre del fichero del TextBox TBNombreBase
Set MiBaseDatos = Workspaces(0).CreateDatabase(TBNombreBase, dbLangGeneral)

‘Se crean los Objetos Tabledef
Set MiTabla1 = MiBaseDatos.CreateTableDef("Clientes")
Set MiTabla2 = MiBaseDatos.CreateTableDef("Peliculas")
Set MiTabla3 = MiBaseDatos.CreateTableDef("Cintas")
Set MiTabla4 = MiBaseDatos.CreateTableDef("Alquileres")

‘Cada Tabledef crea sus propios Objetos Field
Set MiCampo11 = MiTabla1.CreateField("ID_Cliente", dbText, 8)
Set MiCampo12 = MiTabla1.CreateField("Nombre", dbText, 20)
Set MiCampo13 = MiTabla1.CreateField("Apellidos", dbText, 50)
Set MiCampo14 = MiTabla1.CreateField("Direccion", dbText, 50)
Set MiCampo15 = MiTabla1.CreateField("Telefono", dbText, 15)

Set MiCampo21 = MiTabla2.CreateField("ID_Pelicula", dbText, 8)
Set MiCampo22 = MiTabla2.CreateField("Titulo", dbText, 20)
Set MiCampo23 = MiTabla2.CreateField("Idioma", dbText, 1)
Set MiCampo24 = MiTabla2.CreateField("Director", dbText, 25)
Set MiCampo25 = MiTabla2.CreateField("Resumen", dbText, 255)

Set MiCampo31 = MiTabla3.CreateField("ID_Cinta", dbText, 13)



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                    Página 17
Set MiCampo32 = MiTabla3.CreateField("Pelicula", dbText, 20)
Set MiCampo33 = MiTabla3.CreateField("Idioma", dbText, 1)
Set MiCampo34 = MiTabla3.CreateField("Precio", dbSingle)
Set MiCampo35 = MiTabla3.CreateField("Fecha_Alta", dbDate)
Set MiCampo36 = MiTabla3.CreateField("Fecha_Baja", dbDate)

Set MiCampo41 = MiTabla4.CreateField("ID_Cliente", dbText, 8)
Set MiCampo42 = MiTabla4.CreateField("ID_Cinta", dbText, 13)
Set MiCampo43 = MiTabla4.CreateField("Fecha_Alq", dbDate)
Set MiCampo44 = MiTabla4.CreateField("Fecha_Dev", dbDate)

‘Una vez creados los campos se les ponen las peopiedades que se estime oportuno
‘En este caso, se ha puesto la propiedad AllowZeroLength (Permitir valores nulos en ese
‘campo) a lo que interesa en cada uno de los campos. Nota Tenga presente que por defecto le
‘va a dejar el campo que NO permite valores nulos, circunstancia que le va a crear problemas.

MiCampo12.AllowZeroLength = True
MiCampo13.AllowZeroLength = False
MiCampo14.AllowZeroLength = True
MiCampo15.AllowZeroLength = True

‘Se añaden los campos a la colección Fields de las tablas
MiTabla1.Fields.Append MiCampo11
MiTabla1.Fields.Append MiCampo12
MiTabla1.Fields.Append MiCampo13
MiTabla1.Fields.Append MiCampo14
MiTabla1.Fields.Append MiCampo15

MiTabla2.Fields.Append MiCampo21
MiTabla2.Fields.Append MiCampo22
MiTabla2.Fields.Append MiCampo23
MiTabla2.Fields.Append MiCampo24
MiTabla2.Fields.Append MiCampo25

MiTabla3.Fields.Append MiCampo31
MiTabla3.Fields.Append MiCampo32
MiTabla3.Fields.Append MiCampo33
MiTabla3.Fields.Append MiCampo34
MiTabla3.Fields.Append MiCampo35
MiTabla3.Fields.Append MiCampo36

MiTabla4.Fields.Append MiCampo41
MiTabla4.Fields.Append MiCampo42
MiTabla4.Fields.Append MiCampo43
MiTabla4.Fields.Append MiCampo44

‘Se añaden las tablas a la colección Tabledefs del objeto Database
MiBaseDatos.TableDefs.Append MiTabla1
MiBaseDatos.TableDefs.Append MiTabla2
MiBaseDatos.TableDefs.Append MiTabla3
MiBaseDatos.TableDefs.Append MiTabla4

‘Se declaran las variables tipo objeto Index y tipo objeto Field para crear los índices
Dim MiIndice1 As Index, MiIndice2 As Index, MiIndice3 As Index
Dim CampoIndiceA As Field
Dim CampoIndiceB As Field

‘Se crea el primer objeto Index
Set MiIndice1 = MiTabla1.CreateIndex("IndiceCliente")
‘Este objeto Index crea el campo que va a ser índice, con los mismos datos que el



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                     Página 18
‘campo MiCampo11
Set CampoIndiceA = MiIndice1.CreateField("ID_Cliente", dbText, 8)
‘Se añade el campo a la colección Fields del Index
MiIndice1.Fields.Append CampoIndiceA
‘Se le dice que es un índice primario (Clave primaria)
MiIndice1.Primary = True
‘Se añade el objeto Index recién creado a la colección Index del objeto tabledef
MiTabla1.Indexes.Append MiIndice1

‘Se procede de igual forma con el segundo objeto Index
Set MiIndice2 = MiTabla2.CreateIndex("IndicePeliculas")
‘Aquí se meten dos campos en el mismo índice
Set CampoIndiceA = MiIndice2.CreateField("ID_Pelicula", dbText, 10)
Set CampoIndiceB = MiIndice2.CreateField("Idioma", dbText, 1)
MiIndice2.Fields.Append CampoIndiceA
MiIndice2.Fields.Append CampoIndiceB
MiIndice2.Primary = True
MiTabla2.Indexes.Append MiIndice2

Set MiIndice3 = MiTabla3.CreateIndex("IndiceCintas")
Set CampoIndiceA = MiIndice3.CreateField("ID_Cinta", dbText, 13)
MiIndice3.Fields.Append CampoIndiceA
MiIndice3.Primary = True
MiTabla3.Indexes.Append MiIndice3



‘Se declaran los objetos Relation y un par de objetos Field para crear las relaciones. Por
‘claridad se han declarado objetos Field distintos para la creación de los índices y de las
‘relaciones, pero podrían haber sido los mismos
Dim MiRelacion1 As Relation, MiRelacion2 As Relation, MiRelacion3 As Relation
Dim CampoRelacionA As Field
Dim CampoRelacionB As Field

‘Se crea la primera relación entre el campo ID_Clientes de la tabla Clientes (Tabla
‘primaria) y el campo ID_Cliente de la tabla Alquileres (Tabla relacionada)
Set MiRelacion1 = MiBaseDatos.CreateRelation("RelClientes", "Clientes", "Alquileres")
Set CampoRelacionA = MiRelacion1.CreateField("ID_Cliente", dbText, 8)
CampoRelacionA.ForeignName = "ID_Cliente"
MiRelacion1.Fields.Append CampoRelacionA
MiBaseDatos.Relations.Append MiRelacion1

‘Se crea la segunda relación
Set MiRelacion2 = MiBaseDatos.CreateRelation("RelCintas", "Cintas", "Alquileres")
MiRelacion2.Attributes = dbRelationUnique
Set CampoRelacionA = MiRelacion1.CreateField("ID_Cinta", dbText, 13)
CampoRelacionA.ForeignName = "ID_Cinta"
MiRelacion2.Fields.Append CampoRelacionA
MiBaseDatos.Relations.Append MiRelacion2

‘La tercera relación “relaciona” dos campos, Película e Idioma
Set MiRelacion3 = MiBaseDatos.CreateRelation("RelCintasPelis", "Peliculas", "Cintas")
Set CampoRelacionA = MiRelacion1.CreateField("ID_Pelicula", dbText, 8)
Set CampoRelacionB = MiRelacion1.CreateField("Idioma", dbText, 8)
CampoRelacionA.ForeignName = "Pelicula"
CampoRelacionB.ForeignName = "Idioma"
MiRelacion3.Fields.Append CampoRelacionA
MiRelacion3.Fields.Append CampoRelacionB
MiBaseDatos.Relations.Append MiRelacion3




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                      Página 19
‘Se comienza a crear una consulta (La sentencia SQL está cortada dado que no cabe en
‘una línea. El signo     indica que esa línea continúa en la siguiente
Dim MiConsulta1 As QueryDef
Set MiConsulta1 = MiBaseDatos.CreateQueryDef("Pelis", "SELECT Clientes.Nombre,
Clientes.Apellidos, Clientes.Telefono, Peliculas.Titulo, Alquileres.ID_Cinta " & _
" FROM Peliculas INNER JOIN (Clientes INNER JOIN (Cintas INNER JOIN Alquileres ON
Cintas.ID_Cinta = Alquileres.ID_Cinta) " & _
" ON Clientes.ID_Cliente = Alquileres.ID_Cliente) ON (Peliculas.Idioma = Cintas.Idioma) AND

 (Peliculas.ID_Pelicula = Cintas.Pelicula)" & _
" WHERE (((Alquileres.ID_Cinta)='0000000000001'));")

‘Se cierra la el objeto database. En este momento es cuando se crea el fichero.
MiBaseDatos.Close

‘se comunica al usuario la buena nueva de que la base ha sido creada.
MsgBox "La base de datos se ha creado con éxito"

‘Aquí comienza la rutina de error
Exit Sub
RutErr:
MsgBox "Ha ocurrido el error " & Err & ". " & Err.Description

End Sub

Nota acerca de la sentencia SQL para crear la consulta.
Se puede ser muy experto en SQL y tener miedo a crear una consulta SQL debido a la
complejidad que puede tener. No crea que el autor ha escrito la sentencia SQL que ha visto.
Ha utilizado el truco de crear primero la consulta con Access, de la forma gráfica que seguro
que Vd. conoce, ha comprobado que era eso lo que quería, pasó a Vista SQL y la copió. Es
muy bueno hacer prácticas con SQL, para que no se olvide. Pero en algunos casos es
preferible acudir a los trucos que nos proporcionan nuestras herramientas.


El resultado de todo esto podemos verlo si abrimos la base de datos con Access




Fig. 20.4 Tablas de la BD de Videoclub creada con el código descrito




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                     Página 20
Fig. 20.5 Y la consulta




Fig. 20.6 Clave Primaria formada con los dos campos de la tabla Películas




Fig. 20.7 Propiedades de esa clave primaria




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                      Página 21
Fig. 20.8 Las relaciones creadas


Crear bases de datos con contraseña
Imagínese que quiere que su base de datos no se pueda abrir mediante Access. Lo que debe
hacer es crearla con una contraseña (Password) de forma que cuando la quiera abrir, le pida el
Password. Si no lo sabe, no se puede abrir. Si crea una base de datos con estas
características, y no comunica el Password a nadie, solamente la podrá abrir mediante el
programa. (Eso sí, el programa para abrirla, deberá introducir en su instrucción de apertura el
Password con el que se creó.)

Si volvemos a la línea donde creabamos la base de datos del videoclub:

Set MiBaseDatos = Workspaces(0).CreateDatabase(TBNombreBase, dbLangGeneral)

Basta con añadirle ";pwd=PaswordElegido" concatenándolo tras el parámetro que especifica la
lengua. En el ejemplo siguiente hemos usado como Password las iniciales LSB

Set MiBaseDatos =
= Workspaces(0).CreateDatabase(TBNombreBase, dbLangGeneral & ";pwd=LSB")

Cuando lleguemos a la parte de abrir bases de datos, explicaremos cómo se abre una base de
datos con contraseña. Y no crea que ha conseguido la confidencialidad total de sus datos.
Existen programas que puede bajarse de Internet que le leen la contraseña con la que ha
protegido su base. No es una protección total, pero sí suficiente para que un usuario “normal”
no se la pueda abrir.

Crear bases de datos encriptada
Puede encriptar el fichero de su base de datos. Solamente le será útil para que no puedan ver
el contenido del fichero .MDB, ya que si se abre con Access, le presentará los datos de forma
correcta. Para encriptar una base de datos basta con añadir la palabra dbEncrypt en la
instrucción donde ha creado la BD

Set MiBaseDatos = Workspaces(0).CreateDatabase(TBNombreBase,dbLangGeneral & ";pwd=LSB", dbEncrypt)


Ha merecido la pena el trabajo. Hemos creado la base de datos haciendo click en un botón de
la aplicación. No ha sido necesario venderle al cliente Access, ni enviar una base de datos
vacía con los discos de distribución. Además hemos controlado todos los parámetros de los
campos de nuestra BD. Merece la pena crearse las bases de datos por programa.




LSB    Visual Basic - Guía del Estudiante      Capítulo 12                           Página 22
Anexo1
Propiedades de los campos
Ha visto mas atrás que puede ser necesario cambiar las propiedades de los campos una vez
creados (Por ejemplo, MiCampo13.AllowZeroLength = False) Alargaríamos demasiado este ya
largo capítulo si se explican todos los las propiedades que puede tener un campo. Añada un
poco de esfuerzo a su estudio y vea las propiedades de los objetos Field en la ayuda. Le
reseño aquí las que he considerado mas importantes


AllowZeroLength Si/NO Si es Si permite que ese campo tenga valores nulos
DataUpdatable Si/No Si es Si permite modificar el dato de ese campo. No tiene aplicación a
la hora de crear un campo. Sí puede cambiar el valor de esta propiedad por ejemplo, cuando
crea un recordset.

DefaultValue Es el valor que le pone a ese campo si no introduce ninguno. Puede indicar un
valor a la hora de crear el campo:

                       Campo14.DefaultValue = “Madrid”

Required Si/No Indica si el dato es requerido. En caso de que tome el valor SI (True) es
necesario introducir un dato en ese campo

Value Es justamente el dato que almacena en ese campo. Es la propiedad por defecto del
objeto Field.


Propiedades Type, Attributes y Size referidas a los campos

En el método CreateField debe introducir el tipo del campo que desea crear. (Como puede ver
mas atrás, con esta sintaxis p.e.: CreateField("Fecha_Alq", dbDate) Ese tipo coincide con la
propiedad Type aplicada a los campos. La propiedad Size solamente tendrá que aplicarla
cuando vaya a crear un campo tipo Texto.

Puede ver la ayuda de VB para mas detalles. Le enumero los mas usuales



Propiedad Type

Constante              Descripción              Constante     Descripción

dbBoolean              Campo SI/NO             dbByte        Campo tipo Byte
dbCurrency             Tipo moneda             dbDate        Tipo Date/Time
dbDouble               Numérico Doble                 dbInteger     Numérico Integer
dbLong                 Entero Long             dbMemo        Campo Memo
dbLongBinary           Binario largo (Objeto OLE)
dbSingle               Numérico Single         dbText        CampoTexto

Propiedad Attributes

Constante              Descripción

dbFixedField           El tamaño del campo es fijo (predeterminado en campos numéricos).
dbVariableField        El tamaño del campo es variable (Sólo campos de texto).
dbAutoIncrField        El valor del campo en los registros nuevos es incrementado
                       automáticamente a un valor Long integer único que no puede ser
                       modificado. Sólo aceptado en tablas bases de datos Jet.



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                      Página 23
dbUpdatableField       El valor del campo no puede ser modificado.
dbDescending           El campo está ordenado de forma descendente (Z-A o 100-0) (sólo se
                       aplica a objetos Field de una colección Fields de un objeto Index). Si se
                       omite esta constante, el campo se ordena ascendentemente (A-Z o 0-
                       100) (predeterminado).


dbAutoIncrField es la constante a utilizar cuando queremos crear un campo que se vaya
incrementando cada vez que se introduce un nuevo registro (Campo Contador). Por ejemplo,
si hemos creado un campo denominado ID que será el contador de una serie de registros, y
queremos que se incremente en 1 cada vez que añadamos un registro, debemos usar la
propiedad Attributes ANTES de añadir ese campo al objeto TableDef correspondiente, de la
siguiente forma :

Set micampo1N = mitabla01.CreateField("ID", 4) ‘ Creamos el campo ID
micampo1N.Required = True                             ‘ La propiedad Required la veremos
micampo1N.Attributes = dbAutoIncrField                ‘ Le damos atributo de contador
mitabla01.Fields.Append micampo11                     ‘ Añadimos el campo a la tabla

Propiedad Size

Devuelve o establece un valor que indica el tamaño máximo, en bytes, de un objeto Field que
contiene texto o el tamaño fijo de un objeto Field que contiene texto o valores numéricos

Esta propiedad se le debe suministrar en la sintaxis de CreateField solamente cuando creamos
un campo tipo texto - CreateField("ID_Cinta", dbText, 13). El tamaño de un campo texto
puede ser desde 1 a 255 caracteres. Para el resto de los tipos de datos, el tamaño va implícito
en el tipo de dato. Puede consultar el tamaño ocupado por cualquier campo, leyendo la
propiedad Size de un campo:

                 Variable = Micampo11.Size




Abrir una Base de Datos ya existente mediante DAO.
Método OpenDatabase
Hasta ahora hemos visto como crear una base de datos. No es lo más usual. Lo normal es
tener la base de datos creada y abrirla cuando queremos extraer datos o introducir datos.
Vamos a ver como se abre una base de datos mediante DAO, usando el espacio de trabajo
Microsoft JET. Veremos luego como se puede crear un Recordset, que es en realidad sobre el
que se leen y escriben datos, como se pueden añadir registros, borrarlos etc.

Para abrir una base de datos existente deberemos usar el método OpenDatabase. Pero
previamente deberemos declarar el nombre que se le va a dar a ese objeto Database
mediante la instrucción Dim si queremos que el ámbito de ese Database sea un formulario, o
Global o Public, (en la sección de declaraciones de un Módulo o Formulario) si queremos que
el ámbito sea toda la aplicación.

Por ejemplo, si queremos abrir una base de datos y poder referirnos a ella en toda la
aplicación, debemos declararla de esta forma en la sección de declaraciones de un módulo :

                        Public MiBaseDatos as Database

Método OpenDatabase
Abre la base de datos existente. La base de datos abierta se agrega automáticamente a la
colección Databases.



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                       Página 24
Sintaxis Recuerde la expresión general: Set DAOInferior = DAOSuperior.Método ( - - - - - -)

Set MiBaseDatos = Misesion.OpenDatabase(nombre_bd[, exclusivo[, sólo-lectura[, origen]]])

La sintaxis del método OpenDatabase consta de las siguientes partes:

MiBaseDatos Variable de tipo de dato objeto Database que representa el objeto DAO
            Database que se va a abrir.
Misesion    Variable de tipo de dato objeto Workspace que representa el objeto
            Workspace existente que va a contener a la base de datos.
nombre_bd   Expresión de cadena con el nombre de un archivo (y su Path) de una base de
            datos existente. Si el nombre de archivo tiene extensión, es necesario
            especificarla. Si la red lo admite, también puede especificar una ruta de red,
            como por ejemplo "\\MISERVID\MICOMP\MIDIR\MIBD.MDB". nombre_bd
            también puede ser un origen de datos OBDC. Lo veremos en otro capítulo.

                Al especificar nombre_bd hay que tener en cuenta algunas consideraciones:

                Si se refiere a una base de datos ya abierta por otro usuario con acceso
                exclusivo, se producirá un error.

                Si no se refiere a una base de datos existente o a un origen de datos ODBC
                válido, se producirá un error.

                Si es una cadena de longitud cero ("") y origen es "ODBC;", aparecerá un
                cuadro de diálogo con todos los nombres de orígenes de datos ODBC
                registrados, en el que el usuario podrá elegir una base de datos.

exclusivo       Valor de tipo Boolean que es True si la base de datos se va a abrir con acceso
                exclusivo (no compartido) o False si se va a abrir con acceso compartido. Si se
                omite este argumento, la base se abrirá con acceso compartido.
sólo_lectura    Valor de tipo Boolean que es True si la base de datos se va a abrir con acceso
                de sólo lectura o False si se va a abrir con acceso de lectura/escritura. Si se
                omite este argumento, la base se abrirá para lectura/escritura.

origen          Expresión de cadena utilizada para abrir la base de datos. Esta cadena
                constituye los argumentos de conexión ODBC. Para especificar una cadena de
                origen deberá especificar también los argumentos exclusivo y sólo_lectura.
                Consulte la sintaxis en la propiedad Connect.

p.e.     Set MiBaseDatos = Misesion.OpenDatabase (“C:\Guia_Est\Videoclub.MDB”)

abre la base de datos cuyo fichero está en C :\Guia_Est y se llama Videoclub.MDB. Al no
expresarle mas parámetros la abre de modo no exclusivo, y de lectura y escritura. Al no
especificar nada en el parámetro origen entiende que la base es ACCESS

Nota para todo este capítulo. No es necesario cambiar el nombre del Workspace. Si Misesion
= Workspaces (0), la sentencia anterior podemos ponerla también :

Set MiBaseDatos = Workspaces(0).OpenDatabase (“C:\Guia_Est\Videoclub.MDB”)

El hecho de poner siempre un nombre al Workspace es solamente a efectos didácticos

Ya tenemos la base de datos abierta. Pero no crea que nuestro programa ha hecho trabajo. Se
ha limitado a ver si existía el fichero indicado y a “apuntar” el nombre y path de ese fichero que
contiene la base de datos. El trabajo comienza cuando cree el recordset.




LSB    Visual Basic - Guía del Estudiante   Capítulo 12                        Página 25
EL OBJETO RECORDSET
(O la mitad de lo que Vd. necesita saber de Bases de Datos)
Un objeto Recordset contiene los registros de una tabla o de una consulta. Puede ser que no
los contenga todos, si al crear ese recordset le hemos impuesto que los registros cumplan una
determinada condición. En resumen, un recordset es un objeto de acceso a datos que contiene
una colección de registros tomados, bien de una tabla, bien de un conjunto de tablas (a través
de una consulta)

También hay una colección Recordsets. La colección Recordsets contiene todos los objetos
Recordset abiertos de un objeto Database.

Al utilizar objetos de acceso a datos, casi toda la interacción con los datos se produce a través
de objetos Recordset. Todos los objetos Recordset están formados por registros (filas) y
campos (columnas). Existen tres tipos de objetos Recordset:

Recordset de tipo tabla: Representación en código de una tabla base de datos que puede
utilizarse para agregar, modificar o eliminar registros de una sola tabla de base de datos. Un
Recordset tipo Tabla contiene todos los campos de una tabla y no puede contener campos que
no pertenezcan a esa tabla.

Recordset de tipo hoja de respuestas dinámica: Resultado de una consulta que puede tener
registros actualizables. Un Recordset de tipo hoja de respuestas dinámica es un conjunto
dinámico de registros que puede utilizarse para agregar, modificar o eliminar registros de una o
más tablas de una base de datos subyacente. Este tipo de objeto Recordset puede contener
campos de una o más tablas de una base de datos.

Recordset de tipo instantánea: Copia estática de un conjunto de registros que puede
utilizarse para buscar datos o generar informes. Los objetos Recordset de tipo instantánea
pueden contener campos de una o más tablas de una base de datos, pero no pueden
actualizarse. Un recordset de tipo instantánea (Snapshot) es una fotografía que se hace a la
tabla o tablas que lo componen. Los datos que tiene el recordset son los que existían cuando
se realizó la fotografía. Cualquier actualización posterior no se puede ver.

Resumiendo, un Recordset es un conjunto de registros. Recuerde cuando explicábamos en
control Data se decía que este control creaba un Recordset a partir de sus propiedades
DatabaseName y RecordSource. De esta forma, el conjunto de registros que tiene ese control
Data es la totalidad de los registros de la tabla (o consulta) que poníamos en la propiedad
RecordSource. Pero siempre podemos asignar a la propiedad Recordset de ese control Data
un Recordset ya creado mediante código. Y en ese caso, solamente contendrá los campos que
a nosotros nos interese, incluso campos de distintas tablas, cosa que viene muy bien algunas
veces.

Un Recordset lo crearemos con el método OpenRecordset que estamos estudiando. El objeto
Recordset se abre desde un objeto DataBase (que es lo normal). Pero si acude a la
información de VB verá que también se puede abrir desde un TableDef, un QueryDef y desde
otro Recordset. No se complique la vida. Abra directamente los Recordsets desde la base de
datos. A lo mejor, tenemos oportunidad de ver que también se puede abrir desde otro
recordset, pero que en este caso solamente podemos abrirlo para cambiar alguna de sus
propiedades.

Como cualquier objeto DAO, debemos declararlo como variable tipo objeto.

        Public Mirecordset As Recordset

Una vez declarado, para abrirlo basta con ejecutar la sentencia :

Set Mirecordset = base_datos.OpenRecordset (origen[, tipo[, opciones]])




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                        Página 26
Al crear un nuevo objeto Recordset se agrega automáticamente a la colección Recordsets.

base_datos es el nombre del objeto Database que va a crear el recordset. (La base de datos
que acaba de abrir)

Origen en la primera expresión es una variable de tipo String que especifica el origen de los
registros del nuevo objeto Recordset. El origen puede ser un nombre de tabla, un nombre de
consulta o una instrucción SQL que devuelva registros. En el caso de los objetos Recordset de
tipo tabla, el origen sólo puede ser un nombre de tabla.

Tipo es el tipo de Recordset que se quiere crear. Si no se especifica un tipo, OpenRecordset
creará un objeto Recordset de tipo tabla cuando sea posible. (Cuando especifica como Origen
el nombre de una Tabla) Si se especifica una consulta o una tabla adjunta, OpenRecordset
creará un objeto Recordset de tipo hoja de respuestas dinámica. El tipo del nuevo objeto
Recordset se define mediante una de las siguientes constantes :

         dbOpenTable para abrir un objeto Recordset de tipo tabla.
         dbOpenDynaset para abrir un objeto Recordset de tipo hoja de respuestas dinámica.
         dbOpenSnapshot para abrir un objeto Recordset de tipo instantánea.

El parámetro opciones permite especificar las características del nuevo objeto Recordset tales
como las restricciones de edición y consulta para otros usuarios. Vea la Ayuda de VB para
mayor detalle.

Los objetos Recordset se eliminan automáticamente de la colección Recordsets al cerrarlos
con el método Close. También se eliminan automáticamente cuando creamos otro recordset
con el mismo nombre.

Ejemplo de creación de un Objeto Recordset

Decíamos que se puede crear un Recordset con la sentencia :

Recuerde la Fórmula general Set DAOinf = DAOsup.Método ( - - - - - - - )

Set Mirecordset = base_datos.OpenRecordset (origen[, tipo[, opciones]])

Si tenemos abierta una base de datos llamada MiBaseDatos, podemos crear el objeto
MiRecordset eligiendo de la tabla MiTabla de esa base de datos los campos Campo1, Campo2
y Campo3, y que sea del tipo de hoja de respuestas dinámica, de la siguiente forma :

Set Mirecordset = MiBaseDatos.OpenRecordset (“SELECT Campo1, Campo2, Campo3 _
FROM MiTabla”, dbOpenDynaset)

Si deseamos que el Recordset contenga todos los campos de esa misma tabla :

Set Mirecordset=MiBaseDatos.OpenRecordset (“SELECT * FROM MiTabla”, dbOpenDynaset)

o simplemente sin utilizar la sentencia SQL :

Set Mirecordset = MiBaseDatos.OpenRecordset (“MiTabla”, dbOpenDynaset)

En los ejemplos anteriores no se ha establecido ningún parámetro en Opciones.

Veamos lo que decíamos antes. Crear un Recordset desde otro recordset. Se puede usar
solamente para variar sus propiedades. Si desde el Recordset anterior, queremos crear un
nuevo Recordset denominado MiRecordset1, que tenga la condición de que sea solo lectura,
usaremos la sentencia :

Set Mirecordset1 = Mirecordset.OpenRecordset (dbReadOnly)




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                      Página 27
Este nuevo Recordset contendrá los mismos campos que el Recordset origen, pero no
podremos cambiar datos en él.

Pueden crearse tantos Recordsets como se necesiten. Estos Recordsets pueden tener campos
comunes. Es más, podríamos crear dos Recordsets exactamente iguales.

Pero en la mayoría de los casos, necesitaremos crear un Recordset donde se elijan varios
campos de una o varias tablas, seleccionando de esos campos unos determinados valores.
Por ejemplo, en una base con las direcciones de los clientes, a lo mejor queremos seleccionar
todas aquellas direcciones en las cuales el código postal sea el 28700 (San Sebastián de los
Reyes). Imaginemos que hemos abierto la base de datos con el nombre CLIENTES (Recuerde
que este es el nombre del objeto DAO usado para abrir la B.D., no el nombre que pueda tener
esa B.D. en el disco), y esta base de datos tiene una tabla llamada DIRECCIONES (Este sí es
el nombre real de la tabla dentro de la B.D.) Vamos a abrir un Recordset con todos los clientes
de San Sebastián de los Reyes :

Set Mirecordset2 = CLIENTES.OpenRecordset (“SELECT * FROM DIRECCIONES WHERE
COD_POSTAL = 28700“, dbOpenDynaset)

El Recordset Mirecordset2 contiene todos los campos de todos los registros de la tabla
DIRECCIONES que cumplan la condición de que el código postal (campo COD_POSTAL en el
ejemplo) sea igual a 28700.

Observe en esta y anteriores expresiones, que la sentencia SQL está entre doble comilla.

Podemos introducir cualquier sentencia SQL para determinar qué registros introducimos en el
Recordset. Por ejemplo, si queremos seleccionar todos los clientes de Madrid (su código postal
comenzará necesariamente por 28 y le seguirán tres cifras) :

Set Mirecordset2 = CLIENTES.OpenRecordset (“SELECT * FROM DIRECCIONES WHERE
COD_POSTAL LIKE 28???“, dbOpenDynaset)

Tipo de recordset más práctico ¿Dynaset, Table?
A la hora de crear un recordset podemos pensar que tipo es el más adecuado. Todo
dependerá de lo que necesitemos de nuestro recordset y de cómo nos queramos mover por él.
Cuando decimos movernos por él queremos decir cambiar de un registro a otro, buscar
registros, etc.

Vamos a prescindir del recordset tipo Snapshot si lo que queremos es leer y escribir datos. Un
recordset Snapshot solamente sirve para realizar informes (leer) de los datos en un instante
determinado. Veamos la elección entre Dynaset y Table

Si queremos seleccionar parte de los registros de una tabla, o ver registros de varias tablas al
mismo tiempo (lo que podemos ver en Access en una consulta), debemos elegir directamente
el tipo Dynaset, ya que el tipo Table debe contener TODOS los registros de una UNICA
TABLA.

Si estamos en ese caso es el único en el que tendremos dudas respecto al tipo elegido.

Si creamos un recordset tipo Table se nos puede complicar un poco el código a la hora de
movernos a lo largo del recordset, ya que no podemos usar ciertos métodos como los Find
(FindFirst, FindLast, etc.) debiendo utilizar para realizar la misma función los métodos Move
(MoveFirst, MoveLast, MovePrevious, MoveNext), o el método Seek, un poco más complicado
y que exige un índice. (Lo que ganamos con la complicación del Seek es velocidad). Los
desplazamientos a lo largo de un recordset tipo tabla son mucho más rápidos que sobre un
recordset tipo Dynaset. Esa rapidez se nota fundamentalmente cuando va a manejar miles de
registros, en cuyo caso es indispensable usar recordsets tipo tabla y moverse sobre un índice.
Si no va a manejar miles de registros, no apreciará mucha diferencia entre uno y otro. Y si usa
Dynaset dispone de más recursos, sobre todo de búsqueda. Veremos casos de uno y otro tipo.



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                        Página 28
Métodos y Propiedades del recordset que va a necesitar inmediatamente
Propiedad RecordCount

Devuelve el número de registros accedidos en un objeto Recordset. El valor de esta propiedad
es de sólo lectura

Sintaxis          NombredeMiRecordset.RecordCount

Donde NombredeMiRecordset es un objeto Recordset. El valor devuelto por la propiedad
RecordCount es un dato numérico Long

(NombredeMiRecordset puede ser del tipo Dynaset, Snapshot Table. Pero en el caso de que
sea Dynaset se va a encontrar con una sorpresa. Si le pide ese dato a un recordset tipo
Dynaset recién creado, le devolverá el valor 1. ¡Parece que solamente tiene un registro! No es
así. Un recordset tipo Dynaset tiene la ventaja (y el inconveniente) de que solamente guarda en
memoria un registro. Por lo tanto no sabe cuantos registros tiene realmente hasta que no los
recorre todos. Para que el método RecordCount le devuelva el número de registros existentes,
tiene que acceder previamente al primero y al último. Para ello basta con ejecutar estas dos
líneas de código:

                  NombredeMiRecordset.MoveLast
                  NombredeMiRecordset.MoveFirst

A partir de ese momento, ya le indicará el número correcto de registros existentes.


Método AddNew

Crea un nuevo registro en un objeto Recordset de tipo Table o Dynaset.

Sintaxis          MiRecordset.AddNew

El método AddNew crea un nuevo registro donde puede introducir nuevos datos, y
posteriormente agregarlo al conjunto de registros del objeto Recordset. Este método establece
en los campos el valor Null (predeterminado para los objetos Recordset de tipo tabla) o los
valores predeterminados, si existen. El registro creado queda en la memoria, y ahí se puede
modificar simplemente asignando a cada campo el valor deseado. Para asignar un valor a un
campo simplemente tenemos que poner la expresión :

           MiRecordset ! MiCampo1 = “Dato tipo string”
           MiRecordset ! MiCampo2 = Dato tipo numérico

Una vez que se hayan introducido los datos en el nuevo registro, debe utilizar el método
Update para guardar los cambios y agregarlo al conjunto de registros. No se modificará la base
de datos hasta que se utilice el método Update.

La posición del nuevo registro depende del tipo de objeto Recordset:

En un objeto Recordset de tipo hoja de respuestas dinámica, (Dynaset) los registros se
insertan al final del conjunto, independientemente de las reglas de ordenación que pueda haber
en vigor al abrir el conjunto de registros. En un objeto Recordset de tipo tabla cuya propiedad
Index esté definida, los registros se agregan en el lugar correspondiente al orden. Si no se ha
establecido la propiedad Index, los nuevos registros se agregan al final del conjunto.

El registro que era actual antes de utilizar el método AddNew continúa siéndolo después. Esto
puede comprobarlo asignando a un Label el contenido de un campo, añadir un registro con un
valor para ese campo distinto al que está presente en el Label y comprobar que el contenido
del Label no se ve afectado por haber introducido un registro nuevo. Si desea hacer que el


LSB   Visual Basic - Guía del Estudiante   Capítulo 12                        Página 29
nuevo registro sea el actual, puede establecer en la propiedad Bookmark el marcador
identificado por el valor de la propiedad LastModified. En la práctica anterior observará tras
este proceso que se cambia el contenido del Label al nuevo valor.

Vea la propiedad LastModified un poco mas adelante.


Método Edit

Copia el registro actual de un objeto Recordset de tipo hoja de respuestas dinámica o tabla en
el búfer de copia para su edición.

Sintaxis           MiRecordset.Edit

Donde MiRecordset representa el nombre de un objeto Recordset abierto y actualizable que
contiene el registro a editar.

Una vez invocado el método Edit, los cambios efectuados en los campos del registro actual se
copian en el búfer de copia. Al terminar de realizar los cambios deseados, utilice el método
Update para guardarlos. Como en el caso del método AddNew este registro modificado está
en la memoria y es necesario introducirlo en la BD.

El registro actual después de utilizar Edit es precisamente el registro que acabamos de editar.
Para poder usar Edit debe existir un registro actual. Si no es así o si MiRecordset no se refiere
a un objeto Recordset de tipo tabla u hoja de respuestas dinámica, a un objeto Table o a un
objeto Dynaset abierto, se producirá un error.

El uso de Edit producirá un error en las condiciones siguientes:

           No hay registro actual.
           La base de datos o el conjunto de registros es de sólo lectura.
           Ningún campo del registro es actualizable.
           Otro usuario ha abierto la base de datos o el conjunto de registros para uso exclusivo.
           Otro usuario ha bloqueado la página que contiene el registro.

Una vez añadido el registro, o cambiados los datos de un registro, debemos utilizar el Método
Update para guardar los datos en la BD.



Método Update

Guarda el contenido del búfer de copia en un objeto Recordset de tipo hoja de respuestas
dinámica o tabla especificado.

Es decir, mete en la Base de Datos el contenido del registro que estaba en la memoria, bien
por haber utilizado el método Update, bien por haber utilizado el método Edit.

Sintaxis                   MiRecordset.Update

Donde MiRecordset representa el nombre de un objeto Recordset de tipo hoja de respuestas
dinámica o tabla, abierto y actualizable.

Los cambios en el registro actual se perderán en las siguientes situaciones:

Uso del método Edit o AddNew y desplazamiento a otro registro sin utilizar antes Update.
Uso de Edit o AddNew y utilización de nuevo de Edit o AddNew sin especificar antes Update.
Establecimiento de otro registro en la propiedad Bookmark.
Cierre del conjunto de registros indicado en MiRecordset sin utilizar antes Update.




LSB   Visual Basic - Guía del Estudiante      Capítulo 12                        Página 30
Cada vez que se crea o edita un registro se cambia el valor de la propiedad LastModified, que
tomará el marcador de ese registro creado o editado.

Método CancelUpdate

Cancela todas las actualizaciones pendientes del objeto Recordset.

Sintaxis        recordset.CancelUpdateTipo


Tipo puede tomar los siguientes valores

dbUpdateRegular         Cancela los cambios pendientes que no están en la memoria caché.
dbUpdateBatch           Cancela los cambios pendientes en la memoria cache actualizada.
Comentarios

El método CancelUpdate cancela todas las actualizaciones pendientes a causa de una
operación Edit o AddNew. La utilización del método CancelUpdate tiene el mismo efecto que
moverse a otro registro sin utilizar el método Update, salvo que el registro activo no cambia y
algunas propiedades, como BOF y EOF, no se actualizan.


Método Delete

Este método elimina el registro actual de un objeto Recordset de tipo hoja de respuestas
dinámica o tabla. Para eliminar un registro, debe haber un registro actual en el Recordset antes
de utilizar Delete, pues de lo contrario se producirá un error interceptable. Una vez eliminado,
este registro sigue siendo el registro actual. Puede observar, que si a continuación de Delete
utiliza AbsolutePosition para conocer en que registro está, la respuesta será -1, prueba de que
está sobre un registro inexistente.

Propiedad Bookmark

Devuelve o establece un marcador que identifica de forma única el registro actual de un objeto
Recordset o define el registro actual de un Recordset como marcador válido.

Esto merece una pequeña aclaración. Bookmark en inglés significa ese papel que introducimos
en un libro para saber en qué página hemos dejado la lectura. En Visual Basic, significa el
registro en el que estamos actualmente (registro actual) Podemos conocer en que registro
estamos mediante la siguiente expresión:
                       Variable = MiRecordset.Bookmark

Pero tenemos que tener en cuenta que Variable es una variable tipo String (Sí, string, aunque
parezca que para conocer la posición de un registro debería ser un numérico, pero es así). Por
lo tanto deberíamos haber declarado la variable previamente como una variable tipo String

                        Dim Variable As String

Pero esta propiedad sirve para colocarnos en el registro que deseemos. Eso sí, previamente
deberíamos haber obtenido el Bookmark de ese registro. Imagínese que se está moviendo a lo
largo del recordset y hemos visto un registro donde tenemos un dato importante (por ejemplo,
un máximo del valor de un campo) No sabemos si habrá otro registro que tenga un valor mayor
que este. Deberemos seguir buscando, pero antes anotamos el Bookmark de ese registro

                        Variable = MiRecordset.Bookmark

Seguimos buscando moviéndonos por todo el recordset, y comprobamos que no hay otro
registro con un valor mayor. Queremos volver a aquel registro. Para ello forzamos a que el
registro cuyo Bookmark sea igual a Variable se convierta en registro actual:




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                        Página 31
                        MiRecordset.BookMark = Variable

Y se colocará en el registro deseado.

Solamente se puede ver la propiedad Bookmark en aquellos recordsets que tengan la
propiedad Bookmarkable a True. En un Recordset basado completamente en tablas del
motor de base de datos Microsoft Jet, el valor de la propiedad Bookmarkable es True y
pueden usarse marcadores. Sin embargo, otros productos de bases de datos pueden no
aceptar los marcadores. Por ejemplo, no se pueden usar marcadores en un Recordset basado
en una tabla anexa Paradox que no tiene clave principal.

La propiedad Bookmark se almacena internamente como matriz de Byte. Por esta razón, si se
intenta usar la propiedad Bookmark en una operación de comparación, se producirá un error
interceptable. Antes de tener acceso a la propiedad Bookmark, copie los valores de los
marcadores a variables cadena y efectúe las comparaciones usando dichas variables cadena.
Por ejemplo, el siguiente código compara marcadores en dos objetos Recordset:

Dim Marca1 as String, Marca2 as String
Dim Rs1 as Recordset, Rs2 as Recordset
Set Rs1 = Db.OpenRecordset("Títulos")
Set Rs2 = Rs1.Clone()
Marca1 = Rs1.Bookmark
Marca2 = Rs2.Bookmark
If Marca1 = Marca2 Then Print "Esta comparación es válida "

No intente realizar la siguiente comparación, aunque a primera vista parezca igual :

If Rs1.Bookmark = Rs2.Bookmark Then ..... Porque dará error.

No hay límite en el número de marcadores que pueden establecerse. Para crear un marcador
para otro registro distinto del registro actual, muévase al registro deseado y asigne el valor de
la propiedad Bookmark a una variable String que identificará el registro.
Para asegurarse de que el Recordset acepta marcadores, inspeccione el valor de su propiedad
Bookmarkable antes de usar la propiedad Bookmark. Si Bookmarkable es False, el Recordset
no acepta marcadores, y el uso de la propiedad Bookmark produce un error interceptable.

Si la propiedad Bookmark se establece a un valor que corresponda a un registro eliminado, se
produce un error interceptable.


Propiedad LastModified

Devuelve un marcador que indica el registro más recientemente agregado o modificado.

Sintaxis        NombreRecordset.LastModified


El valor devuelto por esta propiedad es un tipo de datos Variant o String. (Similar al devuelto
por Bookmark) LastModified se puede usar para colocarse en el registro más recientemente
agregado o actualizado.

Esta propiedad puede usarse para volver al último registro que ha sido modificado. Basta para
ello igualar la propiedad Bookmark a la propiedad LastModified :

                NombreRecordset.Bookmark = NombreRecordset.LastModified


Métodos MoveFirst, MoveLast, MoveNext, MovePrevious
Estos métodos son aplicables a todos los tipos de recordset.


LSB   Visual Basic - Guía del Estudiante   Capítulo 12                        Página 32
Se sitúan en el primer, el último, el siguiente o el anterior registro del objeto Recordset
especificado y lo convierten en el registro actual.

Sintaxis        MiRecordset.{MoveFirst | MoveLast | MoveNext | MovePrevious}

Puede utilizar los métodos Move para desplazarse de un registro a otro sin aplicar una
condición.

Al abrir el conjunto de registros indicado en Recordset, el primer registro pasa a ser el registro
actual y en la propiedad BOF se establece False. Si el conjunto no contiene ningún registro, se
establecerá en BOF el valor True y no habrá registro actual.

Si el primer o el último registro ya es el actual al utilizar MoveFirst o MoveLast, el registro
actual no varía.
Si utiliza MovePrevious cuando el registro actual sea el primero, en la propiedad BOF se
establecerá True y no habrá registro actual. Si utiliza de nuevo MovePrevious, se producirá un
error y BOF continuará con el valor True.
Si utiliza MoveNext cuando el registro actual sea el último, en la propiedad EOF se establecerá
True y no habrá registro actual. Si utiliza de nuevo MoveNext, se producirá un error y EOF
continuará con el valor True.
Si Recordset hace referencia a un objeto Recordset de tipo tabla o a un objeto Table, el
movimiento se hará según el índice actual de la tabla. Para establecer el índice actual puede
usar la propiedad Index. Si no establece un índice actual, el orden de los registros devueltos no
estará definido.
Si utiliza MoveLast en un objeto Recordset basado en una consulta SQL o QueryDef, se
forzará la terminación de la consulta, poblando completamente el objeto Recordset.

No es posible utilizar los métodos MoveFirst ni MovePrevious en los Recordset tipo snapshot
de desplazamiento hacia delante.

Para desplazar la posición del registro actual en un objeto Recordset un número de registros
determinado hacia adelante o hacia atrás, utilice el método Move.




Método Move
Desplaza la posición del registro actual en un objeto Recordset.

Sintaxis                 MiRecordset.Move filas[, inicio]

Donde :
filas es un valor de tipo Long con signo que especifica el número de filas (de registros) que se
desplaza la posición. Si filas es mayor que 0, la posición se desplaza hacia adelante (hacia el
final del archivo). Si es menor que 0, la posición se desplaza hacia atrás (hacia el principio del
archivo).

Inicio (opcional) es un valor de tipo String que identifica un marcador. Si se especifica inicio, el
desplazamiento será relativo al marcador indicado. Si se omite, Move comenzará por el registro



LSB    Visual Basic - Guía del Estudiante    Capítulo 12                         Página 33
actual. El marcador que debe utilizarse para definir el registro Inicio debe ser un Bookmark o
similar (LastModified, por ejemplo)

Si se especifica una posición anterior al primer registro, la posición del registro actual se situará
al principio del archivo (BOF). Si se especifica una posición posterior al último registro, la
posición del registro actual se situará al final del archivo (EOF).

Si el objeto Recordset no contiene registros y el valor de su propiedad BOF es True, el uso de
este método para desplazarse hacia atrás producirá un error interceptable en tiempo de
ejecución. Lo mismo ocurrirá si el valor de la propiedad EOF es True y pretende desplazarse
hacia adelante. Si las propiedades BOF o EOF tienen el valor True y se intenta usar el método
Move sin un marcador válido, se generará un error interceptable.
Si el objeto Recordset está basado en una consulta, la operación forzará la ejecución de la
consulta en el número de filas especificado..


Métodos FindFirst, FindLast, FindNext, FindPrevious
Estos métodos no se pueden aplicar a un recordset tipo Tabla

Buscan el primer, el último, el siguiente o el anterior registro de un objeto Recordset de tipo
instantánea u hoja de respuestas dinámica, que satisfaga el criterio especificado y lo convierte
en el registro actual.

Sintaxis           MiRecordset.{FindFirst | FindLast | FindNext | FindPrevious} criterio


MiRecordset es el nombre de un objeto Recordset.
Criterio es una expresión de cadena (como la cláusula WHERE de una instrucción SQL, sin la
palabra WHERE) que se utiliza para buscar un registro.

Si no se encuentra ningún registro que satisfaga el criterio, el puntero de registro actual se
situará en el primer registro del objeto Recordset y se establecerá en la propiedad NoMatch el
valor True. Si Recordset contiene más de un registro que satisfaga el criterio, FindFirst hallará
el primero de ellos, FindNext el siguiente y así sucesivamente. La propiedad NoMatch tomará
en este caso el valor False.

Compruebe siempre el valor de la propiedad NoMatch para determinar si la operación de
búsqueda ha tenido éxito. Si la búsqueda ha tenido éxito, NoMatch se establece a False. Si ha
fracasado, NoMatch se establece a True y el registro actual pasa a ser el primero del objeto
Recordset. Por ejemplo:


           Dim Estabaaqui as String
           Estabaaqui = Recordset.Bookmark

           Recordset.FindFirst "Nombre = 'Luis' "    ' Busca un nombre. Recuerde siempre las
                                                    comillas dobles para la expresión de búsqueda
                                                    y las comillas simples si se trata de un dato
                                                    string.

           If Recordset.NoMatch = True Then         'Si no se ha encontrado

           Recordset.Bookmark = Estabaaqui           ' Si no se ha encontrado, vuelve al que era el
                                                    ‘registro actual.

           Else                                     ' Sí se ha encontrado.

.          Aquí las instrucciones adecuadas
.


LSB    Visual Basic - Guía del Estudiante     Capítulo 12                         Página 34
           End If

No es posible utilizar estos métodos en un objeto Recordset de tipo snapshot de
desplazamiento hacia delante.

Al buscar campos que contengan fechas, deberá utilizar el formato de fecha de los Estados
Unidos (mes-día-año), incluso cuando no utilice la versión para este país del motor de base de
datos Jet, pues de lo contrario es posible que no se encuentren los datos buscados. Puede
utilizar la función Format para convertir la fecha. Por ejemplo:

Mirecordset.FindFirst "fecha > #" & Format(mifecha, "mm/dd/yyyy" ) & "#"

Observe que las fechas, aparte de ponerlas en americano, hay que presentarlas entre
almohadillas (#). Observe lo dicho mas atrás para las comillas dobles en la expresión de
búsqueda.

Método Seek
Este método solo se puede usar con recordsets tipo Tabla

Si no podemos usar los métodos Find en un recordset tipo Tabla, ¿Qué podemos hacer para
buscar un dato en un recordset de este tipo? Usar el método Seek

El método Seek busca el primer registro de un objeto Recordset indexado de tipo Table que
cumple el criterio especificado para el índice activo y lo convierte en el registro activo. Sólo
funciona en espacios de trabajo Microsoft Jet.

Sintaxis            MiRecordset.Seek comparación, clave1, clave2...clave13

Donde MiRecordset es un recordset de tipo Table que tiene definido un índice en el campo por
el que se va a realizar la búsqueda. Como podemos tener varios índices en una tabla,
deberemos indicarle cual es el índice de búsqueda. Una vez que se lo indiquemos, ese índice
será el Indice activo.

comparación Es una de esta expresiones de cadena: <, <=, =, >=, >.

clave1, clave2...clave13 Son uno o más valores que corresponden a los campos en el índice
activo del objeto Recordset. Puede utilizar un argumento de hasta 13 claves.

Antes de usar Seek se debe establecer el índice activo. Todo índice tiene un nombre.
Habíamos visto cuando creábamos un índice que debía tener un nombre. Recuerde el ejemplo:

                    Set MiIndice2 = MiTabla2.CreateIndex("IndicePeliculas")

Puede ver el nombre de ese índice en la Fig. 20.7 En este caso habíamos creado el índice
mediante código y hemos podido controlar su nombre. Si lo hubiésemos creado directamente
en Access, el nombre que le pone por defecto es el mismo que el nombre del campo.

Ese nombre del índice es el que debemos usar para crear el índice activo. Por ejemplo, si
quisiéramos que el índice activo fuese el IndicePeliculas lo haríamos índice activo mediante la
siguiente instrucción:

                    MiRecordset.Index = "IndicePelículas"

A partir de ahora, el campo (o campos) de ese índice será sobre el que realizaremos la
búsqueda mediante Seek. Para encontrar el registro que tenga por valor 00000012 usaremos
la expresión

                    MiRecordset.Seek "=", "00000012"



LSB   Visual Basic - Guía del Estudiante      Capítulo 12                     Página 35
Ese registro será ahora el registro actual. Si hubiese mas de un registro con ese valor, el
registro actual será el primero que cumpla esa condición

En el ejemplo hemos utilizado el comparador = para buscar un registro cuyo valor en el campo
indicado por el índice activo sea igual al indicado en el siguiente parámetro (00000012). Si
quisiésemos encontrar un registro cuyo valor sea superior a 00000012 usaríamos la expresión

               MiRecordset.Seek ">", "00000012"

Pero observe ahora que el 0000012 no es un número, es una cadena de caracteres. No se
preocupe. Seek puede comparar el contenido de un campo numérico, de un campo texto, de
un campo Fecha/Hora, etc. Eso sí, debe compararlo con un valor del mismo tipo, es decir, si el
contenido del campo es numérico, en el parámetro Clave1 deberemos pasarle un campo
numérico, si el campo es texto, deberemos pasarle un dato tipo texto, etc.

El método Seek busca en los campos clave especificados y localiza el primer registro que
cumpla el criterio especificado por comparación y clave1. Cuando lo encuentra, convierte ese
registro en activo y la propiedad NoMatch se establece en False. Si el método Seek no
consigue localizar ninguna coincidencia, la propiedad NoMatch se establece en True y el
registro activo es indefinido.

Si comparación es igual (=),mayor o igual (>=) o mayor que (>), Seek empezará al principio del
índice y buscará hacia adelante.
Si comparación es menor que (<) o mayor o igual que (<=), Seek empezará al final del índice y
buscará hacia atrás, a menos que haya entradas de índice duplicadas al final. En tal caso,
Seek empezará en una entrada cualquiera entre las entradas duplicadas existentes al final del
índice.

Debe especificar valores para todos los campos definidos en el índice. Si utiliza Seek con un
índice de múltiples columnas y no especifica un valor de comparación para cada campo del
índice, no podrá usar el operador de igual (=) en la comparación. Esto se debe a que algunos
de los campos de criterio(clave2, clave3, etc) estarán predeterminados en Null, lo que
posiblemente no concordará. Por tanto, el operador de igual sólo funcionará correctamente si
tiene un registro que sea Null en su totalidad, excepto la clave que está buscando. Es
aconsejable usar el operador mayor que o igual en su lugar.

En el ejemplo siguiente se toman los nombres de las calles y otros datos de una tabla llamada
Calles_Nombre, cuyo campo NombreVia esta indexado. El índice tiene el mismo nombre que el
campo porque se creó directamente con Access. El procedimiento BBuscaCalle_Click busca la
primera calle cuyo nombre coincida con las letras tecleadas en el TextBox TBBuscaCalle

Set BaseDatos = OpenDatabase("C:\Callejero\Calles.mdb")
Set RsCalles = BaseDatos.OpenRecordset("Calles_Nombre", dbOpenTable)

Private Sub BBuscaCalle_Click()
RsCalles.Index = "NombreVia"
RsCalles.Seek ">=", TBBuscaCalle
        If RsCalles.NoMatch = False Then
                TBNombreCalle = RsCalles!nombrevia
        Else
                TBNombreCalle = "No se encontró la calle"
        End If
End Sub


Método Clone
En muchas ocasiones es necesario crear un Recordset que sea copia exacta de otro. Las
ocasiones en las que es necesario hacer esto pueden ser variadas, pero vamos a destacar
una : crear un Recordset idéntico al Recordset de un control Data, para trabajarlo con código



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                      Página 36
durante una parte de la ejecución del programa. Otras aplicaciones pueden ser copiar el
Recordset de otra máquina a través de la Red de Area Local, ... y donde podamos llegar con
nuestra imaginación.

La sintaxis de Clone es la siguiente :

Sintaxis        Set Duplicado = Original.Clone

Donde Duplicado es una variable tipo Recordset, y Original es el Recordset que se va a
duplicar.

Con el método Clone puede crear múltiples Recordsets. Cada uno de ellos puede tener su
propio registro actual. El uso de Clone no modifica los datos de los registros. Puede modificar
un registro desde cualquier Recordset, bien desde el que sirvió de original, bien desde
cualquiera de sus copias, pero debe hacerlo invocando los métodos Edit - Update. Puede
compartir marcadores entre dos o más Recordsets creados de esta forma.

Puede utilizar el método Clone cuando desee realizar en un conjunto de registros una
operación que requiera varios registros actuales. Este método es más rápido y eficiente que
crear un nuevo Recordset.

Inicialmente, un Recordset creado con Clone carece de registro actual. Para hacer que un
registro sea el actual antes de utilizar el Recordset copia, puede utilizar cualquiera de los
métodos Move, Find o Seek (solo para Recordsets tipo Tabla), o establecer su propiedad
Bookmark

El hecho de cerrar el Recordset original no afecta al duplicado y viceversa.

Nota No es posible utilizar este método con snapshots de desplazamiento hacia delante
(objetos Recordset de tipo instantánea con la opción dbForwardOnly activada).



Método Requery
El método Requery actualiza los datos de un objeto Recordset, volviendo a ejecutar la consulta
con la que se ha creado ese Recordset. Este método debe usarse cada vez que se sospeche
que los datos de la Base de datos han cambiado, y se quieran presentar los datos
actualizados. Es un método típico de una BD que se está usando desde varios puestos a
través de una Red de Area Local.

Sintaxis        NombreRecordset.Requery [NuevoQueryDef]

Donde NombreRecordset es el nombre del Recordset, y NuevoQueryDef (opcional) es una
consulta almacenada

No es posible utilizar el método Requery en objetos Recordset tipo Snapshot o en los Dynaset
que tengan la propiedad Restartable a False, ni tampoco en los objetos Recordset de tipo
Tabla.

Si los valores de las propiedades BOF y EOF del objeto Recordset son ambos True después
de utilizar el método Requery, la consulta no habrá devuelto ningún registro y el objeto
Recordset no contendrá datos.


Transacciones

Métodos BeginTrans, CommitTrans y Rollback



LSB   Visual Basic - Guía del Estudiante    Capítulo 12                        Página 37
Estos métodos son métodos del Objeto Workspace

Veamos estos tres métodos que, dadas sus funciones, deben estudiarse conjuntamente.

Supongamos un Banco. Debe hacer una transferencia entre dos cuentas corrientes que están
en la misma base de datos. La operación es sencilla : Busca la cuenta origen y crea un nuevo
registro. Apunta en el campo OPERACIÓN una T de Transferencia, en el campo IMPORTE
apunta el valor del dinero a transferir, y en el campo SALDO pone la diferencia entre lo que
había en ese campo en la última operación, menos el importe del dinero transferido.

A continuación hace un proceso similar con la cuenta destino, pero en este caso, sumándole el
importe de la transferencia. No hay problemas. Pero que pasa si, una vez sacado el dinero de
la cuenta origen, no se puede ingresar en la cuenta destino, por la razón que sea (cuenta
bloqueada, no existe esa cuenta, fallo de la red de área local) Obviamente la operación no se
ha completado, y hay que devolver el dinero a la cuenta origen. Podría hacerse un apunte,
metiendo la misma cantidad de dinero que se ha extraído anteriormente, y su saldo no se verá
afectado. Pero no sé lo que pensaría el cliente cuando vea un estadillo de su cuenta, en la que
le han sacado una cantidad de dinero, aunque en el siguiente apunte se lo hayan vuelto a
introducir.

Para evitar estas situaciones usamos lo que se denomina una Transacción, que es una
combinación de estos tres métodos. Con el método BeginTrans iniciamos la Transacción. Con
CommitTrans terminamos la transacción y se guardan los cambios realizados (En ambas
cuentas a la vez, en el caso del ejemplo). Con Rollback se termina la transacción sin llegar a
guardar los cambios, quedando el Objeto Workspace afectado por las operaciones internas a
esa transacción tal y como estaba antes de comenzar dicha operación.

Dado que una transacción pertenece a un Workspace, deberemos aplicar estos métodos al
Workspace que ese usuario tenga abierto. Es decir, en un sistema con varios usuarios que
están trabajando simultáneamente sobre una Base de Datos, un determinado usuario deberá
entrar con un Workspace propio (una sesión de trabajo solo para él). En estas condiciones
podemos crear una transacción. Y aquí comenzamos a ver la necesidad de crear Workspaces
distintos para distintos usuarios. Veremos un poco más adelante como se crean los
Workspaces.

Sintaxis        MiSesión.BeginTrans
                MiSesión.CommitTrans
                MiSesión.Rollback

Dentro de un objeto Workspace, las transacciones son siempre globales y no se limitan sólo a
la base de datos o al conjunto de registros. Si realiza operaciones en más de una base de
datos o conjunto de registros durante una transacción en un objeto Workspace, el método
Rollback deshará todas las operaciones en todos ellos. Quiere esto decir que una transacción
debe iniciarse al comenzar una determinada operación, realizar esa operación sin realizar
ninguna otra durante ese tiempo, terminar la operación y finalizar la transacción, bien con
CommitTrans o con Rollback.
Si desea tener transacciones simultáneas, lo mas indicado es crear varios objetos Workspace
para usar uno con cada transacción.

Puede anidar transacciones. Es posible tener hasta cinco niveles de transacciones abiertos a
un tiempo en un mismo objeto Workspace utilizando múltiples combinaciones anidadas de
BeginTrans y CommitTrans o Rollback. En este caso, el orden de finalización de una
transacción debe ser siempre de menor a mayor nivel jerárquico, es decir, se deberá cerrar
primero la transacción que esté mas interior dentro del anidamiento, y así sucesivamente. Si
cierra una transacción anidada mediante CommitTrans, y posteriormente cierra una
transacción que abarque a esta última con Rollback, los cambios de la primera transacción NO
quedarán guardados.

(Cuando se utilizan bases de datos SQL ODBC externas no es posible anidar las
transacciones).



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                       Página 38
Si cierra un objeto Workspace sin guardar o deshacer las transacciones pendientes, éstas se
desharán automáticamente.

Algunas bases de datos pueden no admitir las transacciones. En este caso la propiedad
Transactions del objeto Database o Recordset tendrá el valor False. Lea detenidamente la
Ayuda de estos métodos antes de trabajar con ellos.

El hecho de usar transacciones, aparte de lo que significa para asegurar la integridad de los
datos, ahorra accesos al disco (Importantísimo en algunas redes LAN y WAN), ya que los
cambios a introducir se van almacenando en un búfer en la memoria, y se vuelcan al disco
solamente en el momento de terminar la transacción de modo afirmativo con CommitTrans.




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                     Página 39
La protección de accesos a una base de datos Access. Usuarios,
Workspaces, Grupos de Trabajo, Grupos de Usuarios. La base de datos
de sistema.
Acabamos de ver que es necesario poder crear Workspaces para cada usuario. Hasta ahora, y
para no complicar el estudio de las bases de datos, habíamos usado solamente el
Workspaces(0) que VB crea automáticamente. Vamos a entrar ahora en la creación de
Usuarios (Users) y Workspaces. El método para crear Workspaces es el CreateWorkspace,
método del dbEngine. Comencemos con una mirada a este objeto desde el punto de vista de
DAO. No olvide que el dbEngine es el motor de bases de datos Jet.

El dbEngine. Visión desde DAO
El objeto dbEngine es el objeto de nivel más alto en el modelo de objeto DAO. Es el
encargado de contener y controlar todos los objetos DAO. Hay un solo objeto dbEngine,
inherente a la aplicación, y no se pueden crear más.

Tiene como cualquier objeto DAO sus propiedades y métodos. Vamos a ver alguna propiedad,
en orden ascendente de importancia práctica.

Propiedad Version

Devuelve la versión actual de DAO en uso. El tipo de datos es String (p.e., "3.5" )

Propiedad DefaultType

Establece o devuelve un valor que indica qué tipo de espacio de trabajo (Microsoft Jet u
ODBCDirect) utilizará el próximo objeto Workspace que se cree. Puede tomar los valores:

dbUseJet        Crea objetos Workspace conectados al motor de base de datos Microsoft Jet.
dbUseODBC       Crea objetos Workspace conectados a un origen de datos ODBC.

Propiedad DefaultUser. Establece el nombre de usuario utilizado para crear el Workspace
predeterminado cuando se inicializa.

Propiedad DefaultPassword. Establece la contraseña utilizada para crear el Workspace
predeterminado cuando se inicializa.

El DefaultUser es un tipo de datos String, que puede tener entre 1 y 20 caracteres de longitud
en espacios de trabajo Microsoft Jet y cualquier longitud en espacios de trabajo ODBCDirect.

El DefaultPassword es un tipo de datos String que puede tener hasta 14 caracteres de longitud
en bases de datos Microsoft Jet y cualquier longitud en conexiones ODBCDirect. Puede
contener cualquier carácter excepto 0 ASCII.

De modo predeterminado, la propiedad DefaultUser se establece a "administrador" y la
propiedad DefaultPassword se establece a una cadena de longitud cero ("").

Para que estas propiedades tenga efecto, debe establecerla antes de llamar a cualquier
método DAO.

Propiedad LoginTimeout. Establece o devuelve el número de segundos que se esperará
antes de que se genere un error cuando se intenta conectar a una base de datos de ODBC.
Tiene como valor predeterminado, 20 segundos.

Propiedad IniPath. Devuelve la ubicación de la información de Registro de Windows de
Microsoft Jet. El método SetOption le permite sobrescribir los valores del Registro de Windows
para el motor de base de datos Microsoft Jet. (Recuerde que cualquier operación indebida
sobre el registro de Windows puede hacerle perder toda la información de su PC)


LSB   Visual Basic - Guía del Estudiante   Capítulo 12                         Página 40
Propiedad SystemDB              (Muy importante)
Establece o devuelve la ruta de acceso del archivo de información del grupo de trabajo (sólo
espacios de trabajo Microsoft Jet). Este archivo es una base de datos Access, que
normalmente se llama System.Mdw (Observe que la extensión es distinta a la .Mdb a la que
nos tiene acostumbrados Access) Access usa este fichero y lo guarda generalmente en
C:\Windows\System. Pero puede copiar esta base con otro nombre, y colocarla en el directorio
que quiera. Lo único que tendrá que hacer es indicarle al dbEngine su nombre y ubicación
mediante esta propiedad SystemDB En esa base de datos se guarda la información de los
usuarios. Se guarda su nombre y su contraseña. Lógicamente no se puede leer con Access,
aunque la abre como si se tratase de una base de datos ordinaria, pero cuando pretende abrir
una tabla, no la visualiza.
(NOTA. - La ayuda dice que el nombre predeterminado es System.Mda. Ese era el nombre
para versiones antiguas del Motor Jet. En mi PC, con W98 y VB6, y con Access98 solamente
encuentro System.Mdw)


Creación de nuevos usuarios Método CreateUser
(Sólo espacios de trabajo Microsoft Jet). Crea un nuevo Usuario, e introduce sus datos en el
archivo de información del grupo de trabajo (Base de Datos System.Mdw o la especificada en
la propiedad SystemDB) El método CreateUser corresponde al Workspace o al Objeto Group.

Para crear un nuevo usuario deberemos suministrar la siguiente información:

Nombre del usuario, PID y contraseña. La sintaxis de CreateUser es:

       Set User = Objeto.CreateUser (Nombre, PID, contraseña)

Donde User es la variable tipo objeto User que desea crear. Debe declararse como User)
Objeto El nombre del Workspace (o del objeto objeto Group) que quiere utilizar para crear el
nuevo objeto User.
Nombre Nombre del nuevo usuario
PID. Identificador de Usuario. Debe contener de 4 a 20 caracteres alfanuméricos
Contraseñal. Contraseña para el nuevo usuario. La contraseña puede tener hasta 14
caracteres de longitud y puede incluir cualquier carácter excepto el carácter ASCII 0

Esto merece algún comentario. El nuevo usuario debe crearlo un Workspace (o un Group, pero
de eso no nos vamos a ocupar por ahora) Lo normal es crear el nuevo usuario con el
Workspaces(0) que como sabe, lo crea automáticamente Visual Basic.

Recuerde que antes de crear un nuevo usuario, debe indicar donde está la base de datos con
la información del systema, mediante la propiedad SystemDB

DBEngine.SystemDB = "C:\Windows\System\System.Mdw")

Con las siguientes instrucciones se crea un nuevo usuario

Dim NuevoUser As User
Set NuevoUser = Workspaces(0).CreateUser("Luis", "EsteesmiPID", "MiContraseña")
Workspaces(0).Users.Append NuevoUser

Podemos saber cuantos usuarios tiene el Workspaces(0) y su nombre. Con las siguientes
instrucciones vamos a introducir los nombres de los usuarios en la lista ListUsers

ListUsers.Clear
For I = 0 To Workspaces(0).Users.Count - 1
NomUsuario = Workspaces(0).Users(I).Name
ListUsers.AddItem NomUsuario
Next I


LSB   Visual Basic - Guía del Estudiante   Capítulo 12                        Página 41
Creación de nuevos Workspaces. Método CreateWorkspace
Podemos crear cuantos Workspaces necesitemos. Recuerde que un Workspace es una sesión
de trabajo. Y una sesión de trabajo se abre para que trabaje un usuario. Por eso, a la hora de
crear un Workspace debemos indicarle para que usuario, y la contraseña de ese usuario.
Como el objeto Workspace pertenece al dbEngine, es este objeto el que debe crearlo.

La sintaxis es la siguiente:

Set NuevoWorkSpace = DBEngine.CreateWorkspace (Nombre, Usuario, Contraseña, Tipo)

NuevoWorkSpace es el Workspace que queremos crear, que habremos declarado como
variable tipo objeto Workspace.
Nombre es el nombre del Workspace (P.e., MiSesion)
Usuario Nombre de un usuario registrado en la base de datos del sistema (Que lo habremos
creado con CreateUser) que será el propietario del nuevo objeto Workspace.
Contraseña La contraseña del Usuario propietario del Workspace.
Tipo (Opcional). Indica el tipo de espacio de trabajo. Puede tomar los valores dbUseJet para
crear un espacio de trabajo Microsoft Jet, o dbUseODBC para crear un espacio de trabajo
ODBCDirect. Si omite tipo, la propiedad DefaultType del objeto DBEngine determinará a qué
tipo de origen de datos está conectado el Workspace
No es necesario añadir el nuevo Workspace a la colección Workspaces

Veamos un ejemplo de cómo crear un Workspace para el usuario Luis creado anteriormente:

Dim NewWS as Workspace
Set NewWS = DBEngine.CreateWorkspace("SesiondeLuis", "Luis", "MiContraseña")
DBEngine.Workspaces.Append NewWS

Podemos ver todos los Workspaces existentes. En las siguientes instrucciones podemos ver el
código para listarlos en ListWS

ListWS.Clear
For I = 0 To DBEngine.Workspaces.Count - 1
NomWS = DBEngine.Workspaces(I).Name
ListWS.AddItem NomWS
Next I

Debe tenerse en cuenta que el objeto Workspace es un objeto que solamente existe mientras
está ejecutándose la aplicación. Cuando salimos de la aplicación, ese Workspace desaparece.
No ocurre lo mismo con el Usuario, que queda en la base de datos del sistema, es decir, es un
objeto persistente.

Las partes de código expuestas se han sacado de un ejemplo creado para ver el número y
nombre de los usuarios existentes, Workspaces y DataBases. Es un ejemplo para explicar
estos conceptos. No tiene otra finalidad.




LSB    Visual Basic - Guía del Estudiante   Capítulo 12                     Página 42
Fig. 20.9 Aspecto de la interface gráfica del ejercicio para crear Users y Workspaces

Código de este ejercicio

General/Declaraciones
Option Explicit
Dim VarDrag As String
Dim NuevoWS() As Workspace


Private Sub BAnadirUser_Click()
On Error GoTo RutErr
Dim NomUsuario As String, I As Integer
If BAnadirUser.Caption = "Añadir" Then
TBNuevoUserName.Visible = True
TBNuvoUsePID.Visible = True
TBNuevoUserPw.Visible = True
LNUserName.Visible = True
LNuevoUserPID.Visible = True
LNuevoUserPw.Visible = True
BAnularUser.Left = 3480
BAnularUser.Visible = True
BBorrarUser.Visible = False
BAnadirUser.Caption = "O.K."
Exit Sub
End If
If BAnadirUser.Caption = "O.K." Then
Dim NuevoUser As User
Set    NuevoUser     =    Workspaces(0).CreateUser(TBNuevoUserName,            TBNuvoUsePID,
TBNuevoUserPw)
Workspaces(0).Users.Append NuevoUser
TBNuevoUserName.Visible = False
TBNuvoUsePID.Visible = False
TBNuevoUserPw.Visible = False
LNUserName.Visible = False
LNuevoUserPID.Visible = False
LNuevoUserPw.Visible = False
BAnularUser.Visible = False
BBorrarUser.Visible = True


LSB   Visual Basic - Guía del Estudiante   Capítulo 12                       Página 43
BAnadirUser.Caption = "Añadir"
ListUsers.Clear
For I = 0 To Workspaces(0).Users.Count - 1
NomUsuario = Workspaces(0).Users(I).Name
ListUsers.AddItem NomUsuario
Next I
BAnularUser.Visible = False
BAnadirUser.Visible = True
End If
RutErr:
If Err = 3304 Then
MsgBox "Debe introducir el PID (Mínimo 5 caracteres, máximo 20 caracteres)"
Exit Sub
Else
If Err > 0 Then MsgBox "Ha ocurrido el error " & Err & "."
End If
End Sub


Private Sub BAnadirWs_Click()
On Error GoTo RutErr
If BAnadirWs.Caption = "Añadir" Then
TBNuevoWorkspace.Visible = True
TBNombreUser.Visible = True
TBNuevoWSPw.Visible = True
LNWSName.Visible = True
LNombreUsuario.Visible = True
LUserPw.Visible = True
BAnularWS.Left = 5520
BAnularWS.Visible = True
BEliminarWs.Visible = False
BAnadirWs.Caption = "O.K."
Exit Sub
End If
If BAnadirWs.Caption = "O.K." Then
Dim NumWS As Integer
NumWS = Workspaces.Count
ReDim Preserve NuevoWS(NumWS)
Dim I As Integer, NomWS As String
Set NuevoWS(NumWS) = DBEngine.CreateWorkspace(TBNuevoWorkspace, TBNombreUser,
TBNuevoWSPw)
DBEngine.Workspaces.Append NuevoWS(NumWS)
ListWS.Clear
For I = 0 To DBEngine.Workspaces.Count - 1
NomWS = DBEngine.Workspaces(I).Name
ListWS.AddItem NomWS
Next I
BAnadirWs.Caption = "Añadir"
TBNuevoWorkspace = ""
TBNombreUser = ""
TBNuevoWSPw = ""
TBNuevoWorkspace.Visible = False
TBNombreUser.Visible = False
TBNuevoWSPw.Visible = False
LNWSName.Visible = False
LNombreUsuario.Visible = False
LUserPw.Visible = False
BAnularWS.Visible = False
BEliminarWs.Visible = True
End If



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                    Página 44
RutErr:
If Err = 3029 Then
MsgBox "El Password usado no coincide con el de ese Usuario (User)"
Exit Sub
End If
End Sub

Private Sub BAnularUser_Click()
If BAnadirUser.Caption = "O.K." Then
TBNuevoUserName.Visible = False
TBNuvoUsePID.Visible = False
TBNuevoUserPw.Visible = False
LNUserName.Visible = False
LNuevoUserPID.Visible = False
LNuevoUserPw.Visible = False
BAnularUser.Visible = False
BBorrarUser.Visible = True
BAnadirUser.Caption = "Añadir"
End If
If BBorrarUser.Enabled = True Then
BBorrarUser.Enabled = False
BAnadirUser.Visible = True
BAnularUser.Visible = False
ListUsers.ListIndex = -1
End If
End Sub


Private Sub BAnularWS_Click()
If BAnadirWs.Caption = "O.K." Then
BAnadirWs.Caption = "Añadir"
TBNuevoWorkspace = ""
TBNombreUser = ""
TBNuevoWSPw = ""
TBNuevoWorkspace.Visible = False
TBNombreUser.Visible = False
TBNuevoWSPw.Visible = False
LNWSName.Visible = False
LNombreUsuario.Visible = False
LUserPw.Visible = False
BAnularWS.Visible = False
BEliminarWs.Visible = True
End If
If BEliminarWs.Enabled = True Then
BEliminarWs.Enabled = False
BAnadirWs.Visible = True
BAnularWS.Visible = False
End If
End Sub

Private Sub BBorrarUser_Click()
Dim NomUsuario As String, I As Integer
Workspaces(0).Users.Delete ListUsers.Text
ListUsers.Clear
For I = 0 To Workspaces(0).Users.Count - 1
NomUsuario = Workspaces(0).Users(I).Name
ListUsers.AddItem NomUsuario
Next I
BAnularUser.Visible = False
BAnadirUser.Visible = True



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                Página 45
End Sub


Private Sub BEliminarWs_Click()
Dim I As Integer, NomWS As String, NumWS As Integer
For I = 0 To DBEngine.Workspaces.Count - 1
NomWS = DBEngine.Workspaces(I).Name
If NomWS = ListWS.Text Then NumWS = I
Next I
Workspaces(NumWS).Close
ListWS.Clear
For I = 0 To DBEngine.Workspaces.Count - 1
NomWS = DBEngine.Workspaces(I).Name
ListWS.AddItem NomWS
Next I
BEliminarWs.Enabled = False
BAnularWS.Visible = False
BAnadirWs.Visible = True
End Sub

Private Sub BSalir_Click()
End
End Sub

Private Sub BVerIni_Click()
Shell "Notepad.exe " & App.Path & "\Cap20Usr.INI", vbNormalFocus
End Sub

Private Sub Form_Activate()
On Error GoTo RutErr
Dim LineaEntr As String
Dim LineaEntr8 As String
Dim I As Integer, NomUsuario As String
Dim PathFichero As String
Open App.Path & "\Cap20Usr.INI" For Input As #1
Do Until EOF(1)
Line Input #1, LineaEntr
LineaEntr8 = ""
LineaEntr8 = Left(LineaEntr, 8)
If UCase(LineaEntr8) = "PROYCAPT" Then Me.Caption = Right(LineaEntr, Len(LineaEntr) - 9)
If UCase(LineaEntr8) = "DBENGINI" Then PathFichero = Trim(Right(LineaEntr, Len(LineaEntr)
- 9))
Loop
Close #1
LBDSys = PathFichero
TBTextINI = PathFichero
DBEngine.SystemDB = PathFichero
For I = 0 To Workspaces(0).Users.Count - 1
NomUsuario = Workspaces(0).Users(I).Name
ListUsers.AddItem NomUsuario
Next I
For I = 0 To DBEngine.Workspaces.Count - 1
NomUsuario = Workspaces(I).Name
ListWS.AddItem NomUsuario
Next I

RutErr:
If Err = 3028 Then
MsgBox "No se puede abrir la base de datos del sistema. Compruebe que su Path y nombre
son correctos. Vealo en Ver Ini"



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                  Página 46
End If
End Sub

Private Sub ListUsers_Click()
BAnadirUser.Visible = False
BBorrarUser.Enabled = True
BAnularUser.Left = 4560
BAnularUser.Visible = True
End Sub

Private Sub ListWS_Click()
BEliminarWs.Enabled = True
BAnadirWs.Visible = False
BAnularWS.Left = 6600
BAnularWS.Visible = True
End Sub

Private Sub Text1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As
Single)
If Shift = 1 And Button = 1 Then
VarDrag = Text1.Text
Text1.Drag
End If
End Sub


El fichero Cap20Usr.INI que debe estar necesariamente en la misma carpeta que el programa,
en el caso del PC del autor tiene esta forma

REM Visual Basic - Guía del Estudiante. Cap. 20. Creación de Usuarios y WorkSpaces
DBEngINI=C:\WinNT\System32\System.mdw

(Deberá cambiar el Path del fichero System.Mdw de acuerdo a como lo tenga en su
ordenador.)




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                   Página 47
Mantenimiento y Copia de Bases de Datos.
Vamos a ver dos métodos del Objeto DBEngine para el mantenimiento y copia de Bases de
Datos ACCESS.

En una Base de Datos ACCESS, cuando borramos un dato en realidad no lo estamos
borrando, sino marcándolo como borrado. (No intente recuperar un dato marcado y no borrado
porque no se puede.) Por lo tanto, verá que tras sucesivas operaciones de escritura / borrado
en una BD, esta va aumentando su tamaño. Se necesita un método que limpie todos los datos
inservibles de la BD para disminuir su tamaño. Este método también deberá reorganizar los
índices y marcadores internos a esa BD. El objeto DAO que debe hacer estas cosas es el
Motor de Bases de Datos. Es decir, el Objeto DBEngine.                   Los métodos son
CompactDatabase, que hace una copia de la base de datos (no borra la BD original) sin
copiar los datos inútiles, y RepairDatabase, que intenta (no siempre lo consigue) reparar los
datos internos de una BD que presente datos corruptos (Se generan con bastante facilidad
cuando apagamos el ordenador con la base abierta)


Método CompactDatabase

Copia, compacta y da la opción de modificar la versión, el orden de intercalado y la codificación
de una base de datos cerrada.

Sintaxis

DBEngine.CompactDatabase BaseDatosAnt, BaseDatosNva [, inf_local [, opciones]]

BaseDatosAnt es el nombre del fichero de la base de datos a compactar. Debe expresar el
Path completo y el nombre del fichero (C :\MiCarpeta\MiBase.MDB) Si el nombre de archivo
tiene extensión, deberá especificarla. Si la red lo admite, también puede especificar una ruta de
red, como por ejemplo "\\MISERVID\MIDIR\MiBase.MDB".

BaseDatosNva es el nombre del fichero (con su Path completo) de la base de datos nueva,
creada al copiar la BaseDatosAnt, ya compactada. No es posible especificar en el argumento
BaseDatosNva el mismo archivo de base de datos que en BaseDatosAnt.

inf_local es una expresión de cadena utilizada para especificar el alfabeto usado a la hora de
ordenar datos de esa Base de Datos. El parámetro a introducir es el mismo que para el
argumento similar usado en la creación de la Base de Datos (dbLangGeneral para el caso de
España). Este argumento es opcional. Si se omite, la información local de BaseDatosNva será
la misma que la de BaseDatosAnt.

Opciones nos permite cambiar alguna característica de la Base de Datos. Puede elegirse
entre cifrarla o no cifrarla y cambiar la versión del motor de bases de datos que va a usar la
nueva Base de Datos.

dbEncrypt       Codifica la base de datos durante la compactación.
dbDecrypt       Descodifica la base de datos durante la compactación.
dbVersion10     Crea una base de datos que utiliza la versión 1.0 del motor Jet
dbVersion11     Crea una base de datos que utiliza la versión 1.1 del motor Jet
dbVersion25     Crea una base de datos que utiliza la versión 2.5 del motor Jet
dbVersion30     Crea una base de datos que utiliza la versión 3.0 del motor Jet

Se puede usar una constante (solamente) de encriptación y una (solamente) de Versión. Sólo
se puede compactar BaseDatosNva con una versión igual o posterior a la de BaseDatosAnt.

Lea detenidamente la ayuda en línea de este Método.




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                        Página 48
Método RepairDatabase
Intenta reparar una base de datos dañada que accede al motor de base de datos Microsoft Jet.

Sintaxis        DBEngine.RepairDatabase NombreBase

Donde NombreBase es el nombre (Y path) del fichero que contiene la Base de Datos a reparar.
Puede especificar una ruta de red. P.e. : "\\MISERVID\ MIDIR\NombreBase.MDB".

Para poder reparar la base debe estar Cerrada. Recuerde, si está en un entorno multiusuario,
que los demás usuarios tampoco pueden tenerla abierta mientras la repara.

El método RepairDatabase también intenta validar todas las tablas del sistema y todos los
índices. Los datos que no puedan repararse se pierden. Si la base de datos no puede
repararse, se producirá un error interceptable.

Sugerencia Después de reparar una base de datos, es aconsejable compactarla con el
método CompactDatabase para desfragmentar el archivo y recuperar espacio en disco.


METODOS DEL OBJETO DataBase

Método Execute
Este Método es para el Objeto DataBase y para el Objeto QueryDef.

Ejecuta una consulta de acciones o una instrucción SQL en el objeto Database especificado.

Sintaxis        Para un objeto DataBase         NombreBD.Execute origen[, opciones]

Donde NombreBD es el nombre del objeto DataBase
      Origen es una instrucción SQL
      Opciones es un entero o constante que determina las características de integridad de
      datos de la consulta, según se especifica mas adelante.


                Para un objeto QueryDef         NombreQuerydef.Execute [opciones]

Donde NombreQuerydef es el nombre del objeto QueryDef cuya propiedad SQL especifica la
      instrucción SQL a ejecutar.
      Opciones igual que para el Objeto Database.

En opciones puede utilizar las siguientes constantes:

dbDenyWrite            Deniega el permiso de escritura a los demás usuarios.
dbInconsistent         (Predeterminado) Actualizaciones inconsistentes.
dbConsistent           Actualizaciones consistentes.
dbSQLPassThrough       Paso a través de SQL. Hace que se pase la instrucción SQL a una
                       base de datos ODBC para su procesamiento.
dbFailOnError          Deshace las actualizaciones en caso de error.
dbSeeChanges           Genera un error en tiempo de ejecución si otro usuario modifica los
                       datos que se están editando.

El método Execute sólo es válido para las consultas de acciones. Si utiliza Execute con otro
tipo de consultas, se producirá un error. Debido a que las consultas de acciones no devuelven
registros, Execute no devuelve un conjunto de registros.

Ejemplo. En el siguiente ejemplo, usamos EXECUTE para cambiar el campo Nombre en una
tabla llamada CLIENTES de una Base de Datos abierta, cuyo Objeto DataBase se llama



LSB   Visual Basic - Guía del Estudiante   Capítulo 12                      Página 49
BaseDatos. Para poder “jugar” con el nombre a cambiar y el nombre cambiado, se introduce el
nombre que queremos cambiar en TBNombre2 y el nuevo nombre en TBNombre1

Dim RegistrosCambiados As Long
Dim MiSQL As String

MiSQL = "UPDATE CLIENTES SET NOMBRE = '" & TBNombre2 & "' WHERE NOMBRE= '" &
TBNombre1 & "'"

BaseDatos.Execute MiSQL, dbFailOnError
RegistrosCambiados = BaseDatos.RecordsAffected
MsgBox RegistrosCambiados

Dada una instrucción SQL sintácticamente correcta y teniendo los permisos adecuados, el
método Execute no fallará, aún cuando no pueda modificarse ni eliminarse una línea. Por lo
tanto, debe especificar siempre la opción dbFailOnError cuando utilice el método Execute
para ejecutar una consulta de actualización o eliminación. Esta opción generará un error
interceptable y deshará todos los cambios realizados con éxito cuando alguno de los registros
afectados se encuentre bloqueado y no pueda actualizarse o eliminarse.

Propiedad RecordsAffected
Para determinar el número de registros afectado por el último método Execute, puede utilizar
la propiedad RecordsAffected del objeto Database o Querydef. Por ejemplo, RecordsAffected
contienen el número de registros eliminados, actualizados o insertados al ejecutar una consulta
de acciones. Al utilizar el método Execute para ejecutar un objeto Querydef, en la propiedad
RecordsAffected del Querydef se establece el número de registros afectados.

Para obtener el mejor rendimiento, especialmente en un entorno multiusuario, puede anidar el
método Execute dentro de una transacción: Utilice el método BeginTrans en el objeto
Workspace actual, use luego el método Execute y complete la transacción con el método
CommitTrans en el objeto Workspace. De esta forma se guardarán los cambios en el disco y
se liberarán los bloqueos que se hayan podido producir durante la ejecución de la consulta.


IMÁGENES EN UNA BASE DE DATOS ACCESS


Una imagen (la fotografía de una persona por ejemplo) puede guardarse en una base de datos
tipo ACCESS y presentarse en un control Picture. ¡¡ Imagine una aplicación que sea una
agenda de teléfonos y pueda insertar la foto de la persona !!

Para introducir una imagen en una BD, el campo de esa BD donde se va a introducir la imagen
debe ser LongBinary ( si esa versión de ACCESS lo tiene) u Objeto OLE.

Introducir y presentar un bit-map en una base de datos es necesario hacerlo mediante un
Control Data. Un bit-map puede presentarse en un control Picture o en un control Image.
Ambos son controles enlazados a datos. Si introducimos un Control Data y un Control
Picture o Control Image en el Formulario, asociamos el Control Data a la Base de Datos, y el
campo que contiene el gráfico a el Control Picture (o Control Image) mediante sus propiedades
DataSource = Nombre del Control data, DataField = Nombre del Campo, tenemos el problema
resuelto. Para meter un gráfico en la BD basta con introducir ese gráfico en el Picture (o Image)
mediante LoadPicture, por ejemplo, y guardar los datos en la BD, bien cambiando el registro
actual del Control data, bien mediante el método UpdateRecord de dicho Control Data.

La asociación de la Base de datos al Control Data puede hacerse, bien mediante sus
propiedades DatabaseName y RecordSource, bien creando un Recordset con código e
igualando la propiedad Recordset del Control Data a ese Recordset.




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                        Página 50
Es posible que se pueda introducir y presentar un bit-map en un control Picture o Image de otra
forma, sin usar el control Data. Eso sí, complicando el código. No merece la pena liarse con
esto. Lo mismo que decíamos que necesitamos un Control Data cuando vamos a usar un
DBGrid, debemos usar un Control Data cuando vayamos a presentar una imagen.




LSB   Visual Basic - Guía del Estudiante   Capítulo 12                       Página 51

				
DOCUMENT INFO
Shared By:
Categories:
Stats:
views:13
posted:2/8/2010
language:Spanish
pages:51