Cómo compactar una base de datos Access con JRO |
Por Enrique Martínez Montejo |
Última revisión: 13/01/2013 |
Este artículo es la revisión a .NET del artículo Cómo compactar una base de datos Access que en su día escribí para los usuarios de Visual Basic clásico, y como indica el título, explica cómo utilizar la biblioteca Microsoft Jet and Replication Object 2.6 Library para crear un nuevo archivo de Access como resultado de la compactación de una base de datos Microsoft Access.
Al tratarse de una biblioteca COM, lo más fácil sería que referenciara en su proyecto de .NET la citada biblioteca, aunque como explicaré posteriormente, no es necesario, porque podemos utilizar la capa COM Interop de .NET para establecer una referencia mediante reflexión.
Mediante el método CompactDatabase del objeto JetEngine de la biblioteca JRO, podemos copiar y compactar una base de datos Access que esté previamente cerrada, teniendo la opción de poder cambiar su versión, la secuencia de ordenación, el cifrado entre otras opciones más.
En cuanto a la modificación de la versión de la base de datos, indicar que sólo está permitido si el número de versión de la base de datos resultante es igual o superior a la base de datos que deseamos compactar, nunca inferior, por lo que no podremos compactar una base de datos Access 2003 al formato Access 2000, por ejemplo, ya que obtendremos el oportuno error interceptable en tiempo de ejecución.
Un punto importante sería indicar que con la biblioteca JRO ya no es posible compactar una base de datos Access 2007, o cuyo destino sea una base de datos con formato Access 2007-2013, aunque se especifique el nuevo proveedor OleDb del Motor de Conectividad de Access (Microsoft.ACE.OLEDB.12.0). Para ello tiene que utilizar la biblioteca Microsoft Office 12.0 Access Database Engine Object Library, o su ensamblado de interoperabilidad primario Microsoft.Office.Interop.Access.Dao.dll, si dispone de Access 2007 o ha descargado los Componentes de conectividad de datos de Microsoft Office 2007 System. En caso de que disponga de Access 2010, la versión de la biblioteca COM o del PIA indicados anteriormente, sería la 14.0, cuyos componentes redistribuibles podrá descargar desde la siguiente dirección: Componente redistribuible del motor de base de datos de Microsoft Access 2010.
El siguiente ejemplo compactaría una base de datos Access 97 al formato de Access 2003. El ejemplo tiene en cuenta si la base de datos tiene establecida una contraseña, teniendo la posibilidad de anular ésta o modificarla en la base de datos resultante.
Dim jro
As JRO.JetEngine =
Nothing
Try
' Cadena de conexión de origen.
'
Dim connStringOrigen
As String = _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data source=C:\Mis documentos\Base97.mdb;" & _
"Jet OLEDB:Engine Type = 4;" & _
"Jet OLEDB:Database Password = Contraseña"
' Cadena de conexión de destino.
'
Dim connStringDestino
As String = _
"Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data source=C:\Mis documentos\Base2003.mdb;" & _
"Jet OLEDB:Engine Type = 5;" & _
"Jet OLEDB:Database Password = Contraseña"
' Creamos un nuevo objeto
JetEngine.
'
jro = New JRO.JetEngine()
' Compactamos la base de datos
'
jro.CompactDatabase(connStringOrigen, connStringDestino)
MessageBox.Show("Se ha compactado satisfactoriamente la base de datos.")
Catch ex As Exception
MessageBox.Show(ex.Message)
Finally
If (Not jro
Is Nothing) Then
' Disminuimos el contador de
referencias y liberamos el objeto.
Runtime.InteropServices.Marshal.ReleaseComObject(jro)
jro = Nothing
End If
End Try
Si todo ha ido bien, se habrá creado un nuevo archivo llamado Base2003 en la carpeta C:\Mis documentos.
Se puede obtener el mismo resultado especificando en el parámetro Provider de la cadena de conexión, el proveedor ACE OLEDB de Access 2007. Pero en éste supuesto, es necesario especificar también el parámetro Jet OLEDB:Engine Type, porque de no hacerlo, se obtendrá la excepción Argumento no válido. Insisto en que no se puede compactar una base de datos de Access 2007, o cuyo destino sea una base de Access 2007, con el proveedor ACE OLEDB de Access 2007, tal y como he indicado anteriormente.
La propiedad Provider indica el nombre del proveedor que se va a utilizar
para conectarse al origen de datos. Si no se especifica dicho parámetro, se
tomará por defecto el proveedor Microsoft.Jet.OLEDB.4.0, siempre y cuando éste
se encuentre debidamente instalado y registrado en el sistema. Si solamente se
encuentra instalado el proveedor Microsoft.ACE.OLEDB.12.0, tendrá que
especificarlo expresamente en el parámetro
Provider de la cadena de conexión, porque al no estar registrado el
proveedor del motor Jet 4.0, se obtendrá la excepción Clase no registrada.
Si una base de datos tiene contraseña, y queremos que la base de datos
resultante tenga la misma u otra nueva, tendremos que establecerla en la cadena
de conexión de destino, ya que de lo contrario, la base de datos resultante no
tendrá ninguna contraseña.
Hay que tener especial cuidado en no separar
con un espacio en blanco las palabras OLEDB: y Database Password, porque de hacerlo nos
encontraremos con el error No se pudo encontrar el archivo ISAM instalable.
Por tanto, la escritura correcta es OLEDB:Database Password, sin espacios en
blanco, lo que también es válido para cualquier otro nombre de propiedad que
comience por Jet OLEDB:.
La versión de la base de datos resultante de la compactación será la que corresponda con el motor de base de datos Microsoft Jet que tengamos instalado por defecto en nuestro sistema, por lo que no es necesario especificar la propiedad Jet OLEDB:Engine Type, salvo que deseemos modificar la versión de la base de datos resultante, en cuyo caso deberemos de especificar en la cadena de conexión el valor de dicha propiedad, la cual puede tomar uno de los siguientes valores, que corresponderá con los distintos tipos de motores OLEDB que puede utilizar:
Si el usuario tiene instalado en su sistema Microsoft Access 2002, el que la base de datos resultante de la compactación tenga el formato de Access 2000 o Access 2002 dependerá del formato de archivo predeterminado que tenga establecido como valor por defecto en el cuadro de diálogo Opciones de Microsoft Access, por tanto, si especificamos en la cadena de conexión el parámetro:
Jet OLEDB:Engine Type = 5
la base de datos creada tendrá formato Access 2000, si así lo tenemos especificado en nuestras Opciones; en caso contrario, la base de datos tendrá el formato de Access 2002.
Dicho valor se guarda en el parámetro Default File Format de la siguiente clave del registro de Windows, HKEY_CURRENT_USER\Software\Microsoft\Office\10.0\Access\Settings, el cual puede tomar uno de los siguientes valores DWORD:
Por último, si se indica una versión del motor OLE DB distinta de la versión de la base de datos que se desea compactar, se producirá el siguiente error: No se puede realizar esta operación; las características de esta versión no están disponibles para bases de datos con formatos más antiguos.
Otras propiedades que se pueden especificar, tanto en la cadena de conexión de origen como la de destino, son las siguientes:
Propiedad | Origen | Destino | Descripión |
User Id | X | El nombre de un usuario incluido en un archivo de información de grupos de trabajo. | |
Password | X | La contraseña del usuario. | |
Locale Identifier | X | Indica el identificador regional de la nueva base de datos. Si se omite, la base de datos de destino tendrá el mismo identificador regional que la de origen. | |
Jet OLEDB:Registry Path | X | Información acerca de la clave del Registro de Windows que contiene los valores para el motor Microsoft Jet. | |
Jet OLEDB:System Database | X | La ruta donde se encuentra el archivo de información de grupos de trabajo (archivo *.mdw). | |
Jet OLEDB:Encrypt Database | X | Indica si se va a cifrar la nueva base de datos. Si se omite este parámetro, la base de datos nueva tendrá el mismo cifrado que la de origen. El valor puede ser True/False. | |
Jet OLEDB:Don't Copy Locale on Compact | X | Indica que se debe utilizar la secuencia de ordenación de la base de datos, lo que suplanta cualquier configuración regional para las columnas. El valor puede ser True/False. | |
Jet OLEDB:Compact Without Relationships | X | Indica si se copiarán las relaciones en la nueva base de datos. El valor puede ser True/False. | |
Jet OLEDB:Compact Without Replica Repair | X | Indica si se intentarán probar otras réplicas para reparar las bases de datos replicadas que estén dañadas. El valor puede ser True/False. |
Los valores más comunes para el Identificador regional son los siguientes:
Descripción | LCID | |
General | 0x00000409 |
Comprende los siguientes idiomas: africaans, albano, árabe, vasco, búlgaro, bielorruso, catalán, holandés, inglés, faroés, persa, alemán (estándar), griego, hebreo, hindú, indonesio, italiano, malayo, portugués, ruso, serbio, suajili, urdú. |
Español tradicional | 0x0000040a | |
Español moderno | 0x00000c0a |
Para especificar un identificador regional de Español moderno, deberemos escribir en la cadena de conexión:
Locale Identifier = 0x00000c0a
Si ha ejecutado el ejemplo anterior, habrá observado que se ha creado un nuevo archivo como resultado de la compactación, pero la base de datos original, continúa teniendo su mismo tamaño; no se ha reducido en nada.
Si desea simular el comportación de la interfaz de usuario de Microsoft Access cuando compacta una base de datos, ese archivo que se crea como resultado de la compactación, tiene que renombrarlo para que se llame igual que el archivo original, previa eliminación física de éste, porque si no se elimina del disco, va a ser complicado renombrar un archivo ya existente.
A continuación voy a mostrar cómo compactar una base de datos Microsoft Access, y que el archivo resultante reemplace al archivo que se ha compactado.
En primer lugar, voy a utilizar un ejemplo que hace uso de la biblioteca JRO, por tanto, lo primero que tiene que hacer es referenciar en su proyecto de .NET la biblioteca COM Microsoft Jet and Replication Object 2.6 Library.
''' <summary>
''' Compacta una base de datos Microsoft Access hasta la versión 2003.
''' </summary>
''' <param name="connString">Cadena de conexión OleDb con la base
''' de datos que se desea compactar.</param>
''' <remarks></remarks>
Public
Sub CompactDatabaseAccessJRO(ByVal connString
As String)
Dim jro
As JRO.JetEngine =
Nothing
Try
If (connString.Length = 0)
Then _
Throw New
ArgumentNullException( _
"connString",
_
"No se ha
especificado ningún origen de datos.")
' Creamos un administrador para la
cadena de conexión de origen.
'
Dim sbOrigen
As New Data.OleDb.OleDbConnectionStringBuilder(connString)
' Creamos un administrador para la
cadena de conexión de destino.
'
Dim sbDestino
As New
Data.OleDb.OleDbConnectionStringBuilder(connString)
' Obtenemos la ruta completa del
archivo que se desea compactar.
'
Dim fileName
As String =
CStr(sbOrigen.Item("Data Source"))
' Obtenemos el nombre de un archivo
aleatorio.
'
Dim fileNameTemp
As String = _
IO.Path.GetDirectoryName(fileName) & "\~" & IO.Path.GetRandomFileName
' Le asignamos el nuevo parámetro
Data Source a la cadena
' de conexión de destino.
'
sbDestino.Item("Data Source") =
fileNameTemp
' Creamos una instancia del objeto
JRO
'
jro =
New JRO.JetEngine()
' Ejecutamos el método
CompactDatabase del objeto JRO, el
' cual necesita las cadenas de
conexión de origen y de destino.
'
jro.CompactDatabase(sbOrigen.ConnectionString, sbDestino.ConnectionString)
sbOrigen =
Nothing
sbDestino =
Nothing
' La base de datos se ha compactado,
creando un nuevo archivo
' con nombre aleatorio, en la misma
carpeta donde se encuentra
' la base de datos original.
'
' Eliminamos el archivo original...
'
IO.File.Delete(fileName)
' ... y lo sustituimos por el archivo
resultado de la compactación.
'
IO.File.Move(fileNameTemp, fileName)
Finally
If (Not jro
Is Nothing) Then
' Disminuimos el contador de
referencias y liberamos el objeto.
Runtime.InteropServices.Marshal.ReleaseComObject(jro)
jro = Nothing
End If
End Try
End Sub
Pero tampoco es sumamente necesario referenciar en nuestro proyecto la biblioteca COM Microsoft Jet and Replication Object 2.6 Library, porque podremos hacerlo en tiempo de ejecución mediante técnicas de reflexión, tal y como muestra el siguiente ejemplo, que es idéntico al anterior, salvo que utiliza la capa de interoperabilidad COM mediante las clases del espacio de nombres System.Reflection.
''' <summary>
''' Compacta una base de datos Microsoft Access hasta la versión 2003.
''' </summary>
''' <param name="connString">Cadena de conexión OleDb con la base
''' de datos que se desea compactar.</param>
''' <remarks></remarks>
Public Sub CompactDatabaseAccessInterop(ByVal connString
As String)
Dim jro As Object =
Nothing
Try
If (connString.Length = 0)
Then _
Throw New
ArgumentNullException( _
"connString",
_
"No se ha
especificado ningún origen de datos.")
' Creamos un administrador para la
cadena de conexión de origen.
'
Dim sbOrigen
As New
Data.OleDb.OleDbConnectionStringBuilder(connString)
' Creamos un administrador para la
cadena de conexión de destino.
'
Dim sbDestino
As New
Data.OleDb.OleDbConnectionStringBuilder(connString)
' Obtenemos la ruta completa del
archivo que se desea compactar.
'
Dim fileName
As String =
CStr(sbOrigen.Item("Data Source"))
' Obtenemos el nombre de un archivo
aleatorio.
'
Dim fileNameTemp
As String = _
IO.Path.GetDirectoryName(fileName) & "\~"
& IO.Path.GetRandomFileName
' Le asignamos el nuevo parámetro
Data Source a la cadena
' de conexión de destino.
'
sbDestino.Item("Data Source") =
fileNameTemp
' Creamos una instancia del objeto
JRO
'
jro =
Activator.CreateInstance(Type.GetTypeFromProgID("JRO.JetEngine"))
' Creamos un array con las cadenas de
conexión de
' origen y de destino.
'
Dim parametros()
As Object =
{sbOrigen.ConnectionString, sbDestino.ConnectionString}
sbOrigen =
Nothing
sbDestino =
Nothing
' Ejecutamos el método
CompactDatabase del objeto JRO, el
' cual necesita las cadenas de
conexión de origen y
' de destino.
'
jro.GetType().InvokeMember( _
"CompactDatabase", Reflection.BindingFlags.InvokeMethod, _
Nothing, jro,
parametros)
' La base de datos se ha compactado,
creando un nuevo archivo
' con nombre aleatorio, en la misma
carpeta donde se encuentra
' la base de datos original.
'
' Eliminamos el archivo original...
'
IO.File.Delete(fileName)
' ... y lo sustituimos por el archivo
resultado de la compactación.
'
IO.File.Move(fileNameTemp, fileName)
Finally
If (Not jro
Is Nothing) Then
' Disminuimos el contador de
referencias y liberamos el objeto.
Runtime.InteropServices.Marshal.ReleaseComObject(jro)
jro = Nothing
End If
End Try
End Sub
Para ejecutar cualquiera de los métodos indicados, simplemente tendríamos que pasar al procedimiento la cadena de conexión OleDb con la base de datos Microsoft Access que deseamos compactar:
Try
Dim connString
As String = _
"Provider = Microsoft.Jet.OLEDB.4.0;"
& _
"Data Source = C:\Mis
documentos\bd1.mdb;"
CompactDatabaseAccessInterop(connString)
' CompactDatabaseAccessJRO(connString)
MessageBox.Show("Se ha compactado satisfactoriamente la base
de datos.")
Catch ex As
Exception
If (ex.InnerException
Is Nothing) Then
MessageBox.Show(ex.Message)
Else
MessageBox.Show(ex.InnerException.Message)
End If
End Try
Enrique Martínez Montejo - 2010
NOTA: La información contenida en este artículo, así como el código fuente incluido en el mismo, se proporciona COMO ESTÁ, sin garantías de ninguna clase, y no otorga derecho alguno. Usted asume cualquier riesgo al poner en práctica, utilizar o ejecutar lo explicado, recomendado o sugerido en el presente artículo.
NOTE: The information contained in this article and source code included therein, is provided AS IS without warranty of any kind, and confers no rights. You assume any risk to implement, use or run it explained, recommended or suggested in this article.