Vincular tablas en Access con Visual Basic
Vamos a seguir con nuestra serie de artículos sobre Administración de aplicaciones Access con otra de las utilidades que más trabajo nos puede ahorrar a los administradores de bases de datos Access, la vinculación automática de tablas.
Suele ser bastante habitual que desde sistemas se realicen cambios en las rutas a los servidores o que simplemente tengamos que cambiar nuestro BackEnd de sitio. En estos casos, revincular nuestras aplicaciones manualmente puede ser además de laborioso, un posible punto de error ya que primero hay que quitar los vínculos viejos, añadir nuevos, tener cuidado de no borrar tablas locales, etc.
Para no tener que seguir todos estos pasos he decidido escribir este artículo sobre vinculación de tablas con Visual Basic además de añadir la funcionalidad al Administrador de aplicaciones Access. En principio puede parecer sencillo, pero como siempre que empiezo a añadir nuevas funcionalidades, surgen cuestiones que me parecen suficientemente interesantes como para escribir un artículo, así que como siempre, explicaré el desarrollo de la funcionalidad y para los que no os interese, al final del artículo adjuntaré las funciones para que las reutilicéis.
Empezaré siguiendo los pasos que he dado para el desarrollo de la funcionalidad y en primer lugar creé una función para simplemente cambiar la propiedad connect del tabledef de nuestro FrontEnd. En un principio pensaba que con eso iba a ser suficiente, buscar las tablas vinculadas en el FE, cambiar la ruta y listo. Como veremos unas líneas más abajo, no ha sido tan sencillo.
Empecemos con la función para modificar la propiedad connect de las tablas. Como siempre le pasamos la ruta del BackEnd, la contraseña y en este caso la ruta del FE (queremos que sea una herramienta externa:
Function VinculaTablas(ByVal BaseDatos As String, ByVal BackEnd As String, ByVal pass As String)
Declaramos las variables necesarias:
Dim trabajo As DAO.Workspace Dim Base, Back As DAO.Database Dim TablaDef, TablaBack As TableDef Dim sConexion As String
Y recorremos el tabledef modificando la propiedad connect (nos aseguramos de que sea una tabla vinculada comprobando que en la propiedad actual exista la cadena «DATABASE=»):
Set Base = trabajo.OpenDatabase(BaseDatos, False, False, "MS Access;PWD=" & pass & "") 'Abrimos base de datos remota Set Back = trabajo.OpenDatabase(BackEnd, False, False, "MS Access;PWD=" & pass & "") 'Abrimos base de datos remota en modo normal 'como véis le paso el mismo pass, si tenemos el FE con password diferente necesitaríamos otro parámetro For Each TablaDef In Base.TableDefs sConexion = Nz(TablaDef.Connect, "") If InStr(1, sConexion, "DATABASE=") > 0 Then 'Controlamos que sea una tabla vinculada If InStr(1, sConexion, "PWD=") > 0 Then 'Si tiene pass en la conexión vieja If Len(pass & "") > 0 Then 'Si le pasamos pass TablaDef.Connect = "MS Access;PWD=" & pass & ";DATABASE=" & BackEnd Else 'Creamos la cadena sin pass TablaDef.Connect = ";DATABASE=" & BackEnd 'Base.TableDefs(TablaDef.name).Connect = ";DATABASE=" & BackEnd End If Else 'Esta no tiene pass TablaDef.Connect = ";DATABASE=" & BackEnd End If TablaDef.RefreshLink End If Next
En el código de esta función podemos ver varias cosas interesantes. Mi idea inicial era, como se puede ver en la función, dejar la tabla vinculada sin guardar la contraseña (ver artículo sobre Dividir base de datos Access) en el caso de que no estuviera ya guardada. Además, dar la opción de borrarla si no le pasábamos el parámetro pass.
Como siempre, estas cosas no son tan sencillas, y aunque intenté hacerlo de varias maneras no funcionaba:
TablaDef.Connect = ";DATABASE=" & BackEnd
Base.TableDefs(TablaDef.name).Connect = ";DATABASE=" & BackEnd
Parece ser que Access guarda la contraseña de la cadena de conexión sí o sí. Tenía que pensar un método alternativo para dar la opción de no guardar la contraseña haciendo mucho más segura la aplicación. Para ello se me ocurrió una manera (a lo mejor encontráis otra más sencilla) que puede ser un poco rebuscada, pero mi neurona no da para más:
- Abrir la base de datos en modo exclusivo
- Quitar la contraseña
- Vincular las tablas
- Volver a poner la contraseña
Aquí es donde empezamos a ver sentido a mi artículo sobre encriptar y modificar la contraseña de Access en tiempo de ejecución. Modificamos la función anterior para ello. Pasamos un nuevo parámetro booleano «Guarda» que nos indica si queremos guarda la contraseña de la cadena de conexión o no. La función quedaría así:
Function VinculaTablas(ByVal BaseDatos As String, ByVal BackEnd As String, ByVal pass As String, ByVal Guarda As Boolean) Dim trabajo As DAO.Workspace Dim Base, Back As DAO.Database Dim TablaDef, TablaBack As TableDef Dim sConexion As String On Error GoTo mal Set trabajo = DBEngine.Workspaces(0) Set Base = trabajo.OpenDatabase(BaseDatos, False, False, "MS Access;PWD=" & pass & "") 'Abrimos base de datos remota If Guarda = False Then 'Si queremos que no guarde la contraseña en el tabledef Set Back = trabajo.OpenDatabase(BackEnd, True, False, "MS Access;PWD=" & pass & "") 'Abrimos base de datos remota en modo exclusivo Back.NewPassword pass, "" 'Quitamos el password para que no se almacene en local Else Set Back = trabajo.OpenDatabase(BackEnd, False, False, "MS Access;PWD=" & pass & "") 'Abrimos base de datos remota en modo normal End If For Each TablaDef In Base.TableDefs sConexion = Nz(TablaDef.Connect, "") If InStr(1, sConexion, "DATABASE=") > 0 Then 'Controlamos que sea una tabla vinculada If InStr(1, sConexion, "PWD=") > 0 Then 'Si tiene pass en la conexión vieja If Len(pass & "") > 0 Then 'Si le pasamos pass TablaDef.Connect = "MS Access;PWD=" & pass & ";DATABASE=" & BackEnd Else 'Creamos la cadena sin pass TablaDef.Connect = ";DATABASE=" & BackEnd 'Base.TableDefs(TablaDef.name).Connect = ";DATABASE=" & BackEnd End If Else 'Esta no tiene pass TablaDef.Connect = ";DATABASE=" & BackEnd End If TablaDef.RefreshLink End If Next If Guarda = False Then Back.NewPassword "", pass 'Volvemos a poner el password End If 'Cerramos Back.Close Set Back = Nothing Exit Function mal: MsgBox ("Error al revincular tablas. " & Err.Description), vbCritical, "Error al revincular tablas" End Function
Esta función si que funciona bien, pero me seguía sin gustar mucho… A veces modificamos el BE añadiendo o borrando (o cambiando de nombre) alguna tabla, con lo que la función nos daría un error y quedarían tablas sin vincular. Para ello la mejor manera que se me ocurrió fue la de borrar todas las tablas vinculadas y volverlas a crear. Y aquí es donde entendemos mi artículo sobre los bucles For Each. Me salto el paso del bucle mal creado y os paso la función final ya creada. Como veréis le paso otro parámetro nuevo «Todas» para controlar si borramos las tablas (todas=1) o simplemente las revinculamos (todas=0):
Function VinculaTablas(ByVal BaseDatos As String, ByVal BackEnd As String, ByVal pass As String, ByVal Guarda As Boolean, ByVal Todas As Integer) Dim trabajo As DAO.Workspace Dim Base, Back As DAO.Database Dim TablaDef, TablaBack As TableDef Dim sConexion As String Dim flagDesconexion, flagConexion As Boolean Dim n, i As Integer On Error GoTo mal Set trabajo = DBEngine.Workspaces(0) Set Base = trabajo.OpenDatabase(BaseDatos, False, False, "MS Access;PWD=" & pass & "") 'Abrimos base de datos remota If Guarda = False Then 'Si queremos que no guarde la contraseña en el tabledef Set Back = trabajo.OpenDatabase(BackEnd, True, False, "MS Access;PWD=" & pass & "") 'Abrimos base de datos remota en modo exclusivo Back.NewPassword pass, "" 'Quitamos el password para que no se almacene en local Else Set Back = trabajo.OpenDatabase(BackEnd, False, False, "MS Access;PWD=" & pass & "") 'Abrimos base de datos remota en modo normal End If If Todas = 1 Then 'Borramos todas las tablas vinculadas y creamos todas las del BE For i = Base.TableDefs.count - 1 To 0 Step -1 'Así que borramos con un bucle externo Set TablaDef = Base.TableDefs(i) sConexion = Nz(TablaDef.Connect, "") If InStr(1, sConexion, "DATABASE=") > 0 Then 'Controlamos que sea una tabla vinculada Base.TableDefs.Delete TablaDef.name Base.TableDefs.Refresh End If Next For Each TablaBack In Back.TableDefs If Left(TablaBack.name, 4) <> "MSys" Then 'Comprobamos que no sea una tabla de sistema Set TablaDef = Base.CreateTableDef(TablaBack.name) TablaDef.Connect = ";DATABASE=" & BackEnd TablaDef.SourceTableName = TablaBack.name 'la que se desea vincular Base.TableDefs.Append TablaDef ' y por ultimo agregamos la nueva Base.TableDefs.Refresh End If Next Else 'Recorremos todo el tabledef del FE para modificar los vínvulos For Each TablaDef In Base.TableDefs sConexion = Nz(TablaDef.Connect, "") If InStr(1, sConexion, "DATABASE=") > 0 Then 'Controlamos que sea una tabla vinculada If InStr(1, sConexion, "PWD=") > 0 Then 'Si tiene pass en la conexión vieja If Len(pass & "") > 0 Then 'Si le pasamos pass TablaDef.Connect = "MS Access;PWD=" & pass & ";DATABASE=" & BackEnd Else 'Creamos la cadena sin pass TablaDef.Connect = ";DATABASE=" & BackEnd 'Base.TableDefs(TablaDef.name).Connect = ";DATABASE=" & BackEnd End If Else 'Esta no tiene pass TablaDef.Connect = ";DATABASE=" & BackEnd End If TablaDef.RefreshLink End If Next End If If Guarda = False Then Back.NewPassword "", pass 'Volvemos a poner el password End If 'Cerramos Back.Close Set Back = Nothing Exit Function mal: MsgBox ("Error al revincular tablas. " & Err.Description), vbCritical, "Error al revincular tablas" End Function
Espero que os sirva.
Arkaitz Arteaga
Latest posts by Arkaitz Arteaga (see all)
- Access: Encriptar contraseñas con SHA-256 utilizando biblioteca de clases .NET con C# - 4 mayo, 2014
- Rendimiento de Access contra backend Access en servidor de archivos remoto. Cuarta parte. - 27 abril, 2014
- Rendimiento de Access contra backend Access en servidor de archivos remoto. Aclaración. - 21 abril, 2014
- Utilizar biblioteca de clases .NET en Access. Tercera aproximación a la Interoperabilidad COM - 14 abril, 2014
- Vincular tablas en Access con Visual Basic - 11 abril, 2014
10 Respuestas a Vincular tablas en Access con Visual Basic
Deja una respuesta
Lo siento, debes estar conectado para publicar un comentario.
Como estas me llamo emmanuel, quiero comenzar a trabajar con Access, como veo que sos un experto en el tema, quiero hacerte una consulta acerca de manuales de acces necesarios, en particular los relacionados con contabilidad, y mas aun con consultas pues me causan muchos problemas al crearlas. gracias.-
Hola Spike, puedes encontrar mucha información por la red sobre Acess. Empieza con alguno sencillo para crear tablas y consultas y si tienes alguna duda, te contestaremos encantados.
Un saludo.
Que tal Akaitz, tengo una consulta, tengo una aplicacion con vb.6 y access y me trabaja bien, ahora me veo en la necesidad de usar Sql Azure vincular la base de datos y trabajar en linea, mi pregunta es puedo vincular access para que mi aplicacion de vb.6 siga funcionando y que por medio de una controlador ODBC vincule Access con SQL Azure?. Gracias por tu tiempo y tu respuesta
En la función de Vinculación, ¿Qué datos son los que se han de pasar? ¿2 Bases de datos? ¿Base de datos y ruta?
Me provoca duda las siguientes sentencias:
Set Base = trabajo.OpenDatabase(BaseDatos, False, False, «MS Access;PWD=» & pass & «») ‘Abrimos base de datos remota
Set Back = trabajo.OpenDatabase(BackEnd, True, False, «MS Access;PWD=» & pass & «») ‘Abrimos base de datos remota en modo exclusivo
¿BaseDatos y BackEnd son las mismas? ¿Se abren 2 veces?
Muchas gracias por compartir tu tiempo y conocimientos.
Base de datos es el archivo local en el que quieres vincular las tablas de la base de datos remota o Backend. Así que tenemos que pasarle la ruta del archivo en el que queremos las tablas vinculadas y la ruta del archivo donde están las tablas.
Un saludo.
Tengo que vincular una Base de datos (archivo local) con 2 Backend, una mdb y otra accdb.
¿Es posible que no funcione? me indica en ambas «Contraseña inválida».
Por otra parte entiendo que si estás ejecutando la función desde el archivo local, no es necesario abrir esta.
Gracias y un saludo.
Arkaitz, muchas gracias por tu post.
Tengo una pregunta. Cuando se vincula una tabla access con un motor sql, quien mantiene el vínculo, SQL o Access. Me explico, si uso tu funcionalidad es seguramente porque no tengo el access instalado como tal, pero mi aplicación si está escribiendo en una bd access. Si viculo esta tabla con sql, sql monitorea el evento insert de la tabla access de tal forma que pueda disparar un trigger on create?
Nuevamente Gracias.
Excelente trabajo, Arkaitz Arteaga.
Muchas gracias
Arkaitz, muy interesante y explicativo el post pero ahora tengo una duda si se puede realizar lo mismo pero con un origen de datos ODBC, ¿crees que esto sea posible?
Hola Arkaitz, creo que hice la pregunta en otro tema donde no correspondía, vuel a escribir la misma pregunta. Soy un fanático principiante de access, siguiendo tu curso he logrado hacer una pequeña aplicación front-end back-end, pero me surge un problema y no se como resolverlo, solo puedo conectar un usuario a la vez, cuando intento conectar otro usuario me da un error indicando: “Error al vincular tablas. No se puede cambia la contraseña de una base de datos compartida”.
Te agradecería alguna recomendación, gracias de antemano.