Conexión genérica para cualquier motor de base datos



Descripción general

Acceso a datos en .NET Conexión genérica para cualquier motor de base datos

[TOC] Tabla de Contenidos


↑↑↑

Introducción

Cuando trabajamos con ADO.NET y queremos realizar una conexión con una base de datos, debemos dar una serie de pasos:

En primer lugar determinar que proveedor vamos a usar, después y según que proveedor utilizar las clases correspondientes, Connection, Command, DataReader y Parameter un ejemplo

  1. SQL Server: SqlConnection, SqlCommand, SqlDataReader, y SqlParameter.
  2. SQL Server CE: SqlCeConnection, SqlCeCommand, SqlCeDataReader, y SqlCeParameter.
  3. Oracle (ODP.Net): OracleConnection, OracleCommand, OracleDataReader, y OracleParameter. Hay un proveedor de MS: Microsoft's .NET for Oracle Provider, pero el Oracle Data Provider for .NET, es el oficial de la gentita de Oracle.
  4. DB2: DB2Connection, DB2Command, DB2DataReader, y DB2Parameter.
  5. MySQL: MySqlConnection, MySqlCommand, MySqlDataReader, y MySqlParameter. Ejemplos: Connector/NET Examples and Usage Guide.
  6. PostgreSQL: NpgsqlConnection, NpgsqlCommand, NpgsqlDataReader, y NpgsqlParameter. Ejemplos: Npgsql 2.0 User Manual.
  7. VistaDB: VistaDBConnection, VistaDBCommand, VistaDBDataReader, y VistaDBParameter.
  8. OleDb: OleDbConnection, OleDbCommand, OleDbDataReader, y OleDbParameter.
  9. Odbc: OdbcConnection, OdbcCommand, OdbcDataReader, y OdbcParameter.
  10. Y así...., se entiende la idea?. Ya no pongo más proveedores, por que no acabo la entrada. No se pierda la saga: OleDb vs Odbc.

En el caso que este disponible un proveedor puntual para una fuente de datos, podemos usar OleDb, y si no esta disponible en está, podemos usar Odbc:

  1. Access. Ejemplo de conexión con OleDb. Ejemplo en código: Using ADO .NET - Access and OleDB Part 2. Más ejemplos.
  2. Excel: Ejemplo de conexión con OleDb. Ejemplos en código: Reading Excel (.xls) Files with ADO.NET, y Reading and Writing Excel Spreadsheets Using ADO.NET C# DbProviderFactory. Más ejemplos.
  3. Text Files (CSV, tab, custom): Ejemplo de conexión con OleDb. Ejemplo en código: Using OleDb to Import Text Files (tab, CSV, custom). Más ejemplos.
  4. Se entiende la idea?



↑↑↑

Una Solucion

La solución que propongo es Usar las clases de ADO.NET que están en el espacio de nombres System.Data.Common

Para ello necesito dar los siguientes pasos:

Localizar y establecer el proveedor que queremos usar. Para este trabajo, usaremos la clase [DBProviderFactories] que nos servirá para dos cosas: por una parte para enumerar (listar) los proveedores disponibles, y por otra para crear un objeto DbProviderFactory a partir del cual crearemos el resto de los objetos que necesitamos (Connection, Command, DataReader, etc)

El objeto DbProviderFactory es genérico pero sus método permiten crear objetos de la clase adecuada para conectar con el origen de datos, definir comandos, adaptadores de datos, etc. Estos métodos ( que vamos a utilizar) son:

En segundo lugar tenemos que tener la cadena de conexión con la base de datos. Este sigue siendo un requisito ineludible e imprescindible.

Y en tercer lugar realizar la conexión con la base de datos.

Un Ejemplo

''' <summary>
'''     Realizar una consulta SELECT , obtener los datos y 
'''     devolverlos en un DataSet
''' </summary>
''' <returns> Un objeto [System.Data.DataSet]</returns>
Public Shared Function CargarUnDataSet() As System.Data.DataSet

    '-------------------------------------------------------------
    '   Nombre invariante del proveedor que se emplea para
    '   crear la clase factoria que crea las demas clases (genericas - System.Data.Common)
    '   para establecer una conexion a la base de datos
    '   corresponde a la columna InvariantName de una tabla que devuelve GetFactoryClasses.
    '   http://msdn.microsoft.com/es-es/library/system.data.common.dbproviderfactories.getfactoryclasses.aspx
    '-------------------------------------------------------------
    Dim NombreInvarianteProveedor As String = "System.Data.OleDb"
    '-------------------------------------------------------------
    ' La cadena de conexion
    ' Vamos a establecer una conexion con la base de datos [Northwind] 
    ' concretamente con la version generada por [Microsoft Office Access 2007]
    ' la version [Northwind 2007.accdb] 
    '-------------------------------------------------------------
    Dim CadenaConexion As String = _
    "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Users\Joaquin\Documents\Northwind 2007.accdb;Persist Security Info=False"
    '-------------------------------------------------------------
    ' Nombre de la tabla de la base de datos [Northwind] que vamos a listar
    Dim nombreTabla As String = "Clientes"
    '-------------------------------------------------------------
    ' la orden Sql para seleccionar todos los datos de la tabla
    Dim cadenaSelectSql As String = "SELECT * FROM " & nombreTabla
    '-------------------------------------------------------------


    '-------------------------------------------------------
    ' Definir los Objetos del espacio [System.Data.Common]
    '-------------------------------------------------------
    ' El Objeto Factoria Generica
    Dim objetoDbFactoria As Common.DbProviderFactory = Nothing
    ' Objeto conexion
    Dim objetoDbConexion As Common.DbConnection = Nothing
    ' Objeto para Montar la  cadena de conexion:
    Dim objetoConnectionStringBuilder As Common.DbConnectionStringBuilder = Nothing
    ' Objeto Command
    Dim objetoCommand As Common.DbCommand = Nothing
    '  un DataAdapter
    Dim objetoDataAdapter As Common.DbDataAdapter = Nothing
    '  un DataSet
    Dim objetoDataSet As DataSet = Nothing
    '-------------------------------------------------------
    Try
        '--------------------------------------
        ' El Objeto Factoria Generica
        objetoDbFactoria = Common.DbProviderFactories.GetFactory(NombreInvarianteProveedor)
        '--------------------------------
        ' El objeto que comprobara y montara la  cadena de conexion:
        objetoConnectionStringBuilder = objetoDbFactoria.CreateConnectionStringBuilder
        ' esta linea carga y comprueba que la cadena de conexion sea sintacticamente correcta
        objetoConnectionStringBuilder.ConnectionString = CadenaConexion
        '--------------------------------------
        ' Obtener una conexion
        objetoDbConexion = objetoDbFactoria.CreateConnection
        objetoDbConexion.ConnectionString = objetoConnectionStringBuilder.ConnectionString
        ' abrir la conexion
        objetoDbConexion.Open()
        '--------------------------------------
        ' crear comando
        objetoCommand = objetoDbConexion.CreateCommand
        objetoCommand.CommandType = CommandType.Text
        '      SELECT * FROM tb_empresa
        objetoCommand.CommandText = cadenaSelectSql ' del parametro
        '--------------------------------------------------
        ' Obtenemos  el DataAdapter siempre despues de fijar la consulta en Command
        objetoDataAdapter = objetoDbFactoria.CreateDataAdapter
        ' Adaptador enlazado a la consulta
        objetoDataAdapter.SelectCommand = objetoCommand
        ' Instanciamos el DataSet
        objetoDataSet = New DataSet
        ' Llenamos el DataSet con los datos obtenidos de la consulta
        objetoDataAdapter.Fill(objetoDataSet, nombreTabla)
        '--------------------------------------------------
        ' cerrar la conexion (En Finally)
        '--------------------------------------------------
        ' devolver El DataSet
        Return objetoDataSet
    Catch ex As Exception
        Using SW As New System.IO.StringWriter
            SW.WriteLine("Error del sistema")
            SW.WriteLine(ex.Message)
            SW.WriteLine("Proveedor          = " & NombreInvarianteProveedor)
            SW.WriteLine("Cadena Conexion    = " & objetoConnectionStringBuilder.ConnectionString)
            SW.WriteLine("Interrogacion SQL  = " & objetoCommand.CommandText)
            SW.WriteLine("Nombre de la tabla = " & nombreTabla)
            SW.Flush()
            Throw New Exception(SW.ToString, ex)
        End Using
    Finally
        '-----
        If Not (objetoDbFactoria Is Nothing) Then
            objetoDbFactoria = Nothing
        End If
        '-----
        If Not (objetoDbConexion Is Nothing) Then
            ' cerrar siempre la conexion
            objetoDbConexion.Close()
            objetoDbConexion.Dispose()
            ' destruir el objeto conexion local
            objetoDbConexion = Nothing
        End If
        '-----
        If Not (objetoConnectionStringBuilder Is Nothing) Then
            objetoConnectionStringBuilder = Nothing
        End If
        '-----
        If Not (objetoCommand Is Nothing) Then
            objetoCommand.Dispose()
            objetoCommand = Nothing
        End If
        '-----
        If Not (objetoDataSet Is Nothing) Then
            objetoDataSet.Dispose()
            objetoDataSet = Nothing
        End If
        '-----
        If Not (objetoDataAdapter Is Nothing) Then
            objetoDataAdapter.Dispose()
            objetoDataAdapter = Nothing
        End If
    End Try
    '----------------------
End Function

En el ejemplo que se muestra a continuación se indica cómo se puede establecer una conexión con una base de datos, concretamente con la base de datos [Northwind 2007.accdb] [Microsoft Office Access 2007], por medio de clases del espacio genérico

El código lo que hace es:

Los datos que se necesitan para establecer la conexión, se cargan en variables internas, de esta forma es más fácil y sencillo el ejemplo. Observa que se definen el proveedor, la cadena de conexión, la tabla que queremos leer de la base de daos y la cadena SQL que ejecutara la selección de datos en el objeto Command.

A continuación se definen los objetos

Después (y ya dentro del bloque TRY),

Ahora que tenemos los datos en el DatSet, podemos mostrarlos en un formulario en un control DataGridView.

El código que se muestra a continuación hace, precisamente, esa trabajo

''' <summary>
'''  Muestra un DataSet en un control DataGridView
''' </summary>
''' <param name="controlDataGridView">el control DataGridView que muestra los datos</param>
''' <param name="objDataSet">El Objeto DataSet que contiene los datos</param>
''' <param name="mostrarEnModoLectura">
'''     <para> Valor lógico que indica:</para>
'''     <para> TRUE..: Los datos se muestran en modo lectura, no se pueden modificar</para>
'''     <para> FALSE.: Los datos se muestran en modo edición, que permite añadir, borrar y/o modificar datos. </para>
'''     <para> Valor por defecto = [True], modo lectura</para>
''' </param>
Friend Shared Sub MostarEnDataGridView( _
          ByRef controlDataGridView As DataGridView, _
          ByVal objDataSet As DataSet, _
          Optional ByVal mostrarEnModoLectura As Boolean = True)
    Try
        '------------------------------------------------------
        ' Problema--> evitar el error cuando DataSet = nothing
        If objDataSet IsNot Nothing Then
            '------------------------------------------------------
            ' mostrarlo en el DataGridView
            With controlDataGridView
                ' para que se generen automaticamente las columnas
                .AutoGenerateColumns = True
                ' borrar todos los datos del control DataGridView
                .Columns.Clear()
                ' Modo virtual NO
                .VirtualMode = False
                ' Modo lectura o edicion
                If mostrarEnModoLectura = True Then
                    ' Solo Lectura de datos
                    .ReadOnly = True
                    ' No se permite al usuario añadir datos
                    .AllowUserToAddRows = False
                    ' no se permite al usuario Borrar datos
                    .AllowUserToDeleteRows = False
                Else
                    .ReadOnly = False
                    .AllowUserToAddRows = True
                    .AllowUserToDeleteRows = True
                End If
                ' enlazar el DataGridView1 con la tabla de datos
                .DataSource = objDataSet
                ' proporcionar el nombre de la tabla de datos
                ' Problema--> evitar el error cuando no hay tablas en el DataSet
                If objDataSet.Tables.Count > 0 Then
                    .DataMember = objDataSet.Tables.Item(0).TableName
                End If
                ' ajustar el ancho de la columna al texto mas largo
                .AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells)
                ' Mostrar toda la linea seleccionada
                .SelectionMode = DataGridViewSelectionMode.RowHeaderSelect
                ' permitir el redimensionamiento de las columnas
                .AllowUserToResizeColumns = True
                ' Mostrar errores
                .ShowCellErrors = True
                ' activar estilos visuales
                .EnableHeadersVisualStyles = True
                ' alternar colores   
                .RowsDefaultCellStyle.BackColor = Drawing.Color.White
                .AlternatingRowsDefaultCellStyle.BackColor = Drawing.Color.AliceBlue
            End With
        End If
    Catch ex As Exception
        Throw
    End Try
End Sub

Lo que falta es crear un formulario que realice estas dos operaciones para ello en tu Visual Estudio, añade un nuevo formulario, y ponle un control [DataWGridView]. Añade un botón (llamado Prueba) y en su evento clic escribe el siguiente código

Dim objDataSet As DataSet = Nothing
objDataSet = CargarUnDataSet
MostarEnDataGridView(DataGridView1, objDataSet, True)


↑↑↑

A modo de resumen

Esta forma de trabajar permite escribir código independientemente del proveedor que vayamos a utilizar, si observa atentamente, todas las clases que se generan, dependen del objeto [DbProviderFactory] Por lo que si cambiamos el valor del [Nombre invariante del proveedor], cambiaremos de forma automática en todo nuestro código el motor de Base de datos empleado. Es decir, con un simple cambio de una línea de código, podemos cambiar de un proveedor Odbc a un proveedor SQL Server.

Como puede suponer esto no es exactamente cierto, porque las parejas Claves-Valor de la cadena de conexión no son estándar para todos los proveedores, pero después de realizar este segundo cambio (si es necesario), el código funcionara perfectamente bien sin necesidad de realizar ningún otro cambio

Vale... Pero... ¿Es realmente necesario todo esto? Pues, la verdad es que con el paso del tiempo, las aplicaciones van creciendo, los sistemas van mejorando, y es, (relativamente) frecuente que haya que adaptar toda una aplicación a otro gestor de base de datos al que la empresa ha migrado, por lo que no es ninguna tontería escribir nuestro código con estas clases por tres razones.


↑↑↑

Sobre el autor

Autobombo del autor (25K)
  • Joaquín Medina Serrano [Web]
  • Programador Senior
  • Fotógrafo erótico y conceptual
  • Autor de artículos sobre Programación Orientada a Objetos, y Visual Basic .NET
  • El último curso de capacitación realizado ha sido el Máster en Servicios Web, Seguridad Informática y Aplicaciones de Comercio Electrónico de la [Universidad de Zaragoza ]

↑↑↑

A.2.Enlaces

[Para saber mas]
[Grupo de documentos]
[Documento Index]
[Documento Start]
[Imprimir el Documento]

↑↑↑

A.3.Información del documento

Título
Conexión genérica para cualquier motor de base datos
Autor
Palabras claves de busqueda
ADO.NET, 'cadena de conexión', Command, 'conexión con una base de datos', Connection, DataReader, 'establecer una conexión con una base de datos', 'nombre invariante del proveedor'
Contenido del documento
Acceso a datos en .NET Conexión genérica para cualquier motor de base datos
Tabla de contenidos
[ Introducción ], [ Una Solucion ], [ A modo de resumen ]
Archivado en:
informática\lenguajes\NET\ado_net
Fechas
Fecha Creación
2009-02-08T11:10:19 [domingo, 08 de febrero de 2009 a las 11:10:19 horas]
Fecha Publicación
2009-02-08T11:10:19 [domingo, 08 de febrero de 2009 a las 11:10:19 horas]
Fecha de la última actualización en disco
Fecha última Modificación
2009-02-08T11:10:19 [domingo, 08 de febrero de 2009 a las 11:10:19 horas]
Naturaleza del recurso
Text
IMT (Internet Media Type)
text/xhtml+xml
Juego de caracteres)
ISO 8859-1
Idioma
es-ES [es = Español] [ES = España]
Copyright
Texto con los derechos
© Copyright Joaquin 'jms32®' Medina Serrano 1.997-2009 - Reservados todos los derechos.
Información obtenida con JavaScript
Situación de ESTE documento en la red
¿ Quien ha llamado a ésta página ?
Navegador empleado para ver ésta página
© 1997 - - La Güeb de Joaquín
Joaquin Medina Serrano
Ésta página es española