|
- Accedere a DBMS diversi con lo stesso
codice - |
|||
| COSA SERVE PER QUESTO TUTORIAL | |||
| Download | Chiedi sul FORUM | Glossario | Un IDE per .Net - un server MySql - un server SqlServer (anche Express) - conoscenze basiche di VB .Net | ||
| Le interfacce comuni di System.Data | |||
LE INTERFACCE IDBCONNECTION E IDBCOMMAND DI ADO.NET Come accedere a diversi DBMS sacrificando i DbDataAdapter.
In questo articolo vedremo come accedere a tre DBMS diversi (Access,
MySql e SqlServer ma in teoria anche tutti gli altri compatibili con
ADO.NET) senza dover fare eccessive modifiche al nostro codice. Certo è
comodo utilizzare i vari oggetti DBMS-specifici, ad esempio qualunque
programmatore .Net sa quanto sia semplice usare DbDataAdapter (System.Data.Odbc.OdbcDataAdapter,
System.Data.OleDb.OleDbDataAdapter o altri) per eseguire delle query
SQL, ma se si utilizzano questi oggetti e si intende supportare DBMS
diversi bisognerà mettere mettere blocchi If ovunque e questa non è certamente una buona
pratica.
Public Enum SourceType
MDB
MySql
SqlServer
End Enum
Private Function GetConnection(ByVal Source As SourceType) As IDbConnection
Dim cntDBIndipendent As IDbConnection
Select Case Source
Case SourceType.MDB
'Stringa di connessione OLEDB per un database Access
cntDBIndipendent = New OleDb.OleDbConnection( _
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & GetEXEDirectory() & _
"test.mdb")
Case SourceType.MySql
'Stringa di connessione ODBC per un database MySql
'È necessario impostare la password manualmente
cntDBIndipendent = New Odbc.OdbcConnection( _
"DRIVER={MySQL ODBC 3.51 Driver};Server=arcadi67.startlogicmysql.com;Database=test;" & _
"UID=root;pwd=pass;")
Case SourceType.SqlServer
'Stringa di connessione SqlConnection per un database SqlServer
cntDBIndipendent = New SqlClient.SqlConnection( _
"Data Source=FIGHTER\SQLEXPRESS;Initial Catalog=test;" & _
"Integrated Security=True;")
End Select
'Tutti gli oggetti precedentemente usati implementano l'interfaccia IDbConnection:
'lo restituiamo senza sapere quale sia il caso specifico.
Return cntDBIndipendent
End Function
Il codice in questione è molto semplice, si tratta solo di vedere che sorgente di dati è stata richiesta e dunque istanziare la classe corretta (OleDbConnection, OdbcConnection o SqlConnection) con la relativa stringa di connessione. Il risultato viene poi messo in cntDBIndipendent, variabile di tipo IDbConnection, interfaccia, come già detto, implementata da tutti gli oggetti di connessione ADO.NET. IDbConnection è un'interfaccia molto semplice i cui metodi più interessanti sono Open(), Close() (che, come è ovvio, aprono e chiudono la connessione) ma sopratutto CreateCommand().
Public Function GetData(ByVal Source As SourceType) As DataSet
'Otteniamo la connessione del tipo desiderato e la mettiamo
'in una variabile di tipo "neutro" (interfaccia indipendente
'dal DBMS)
Dim cntConnection As IDbConnection = GetConnection(Source)
'Apriamo la connessione
cntConnection.Open()
'Creiamo l'oggetto che eseguirà il comando
Dim cmdCommand As IDbCommand = cntConnection.CreateCommand()
'Impostiamo il testo della query
cmdCommand.CommandText = "SELECT * FROM Test"
'Leggiamo tutti i dati dal DataReader e li mettiamo in un DataSet
Dim dsResult As DataSet
dsResult = FillDataSet(cmdCommand.ExecuteReader())
'Chiudiamo la connessione
cntConnection.Close()
Return dsResult
End Function
CreateCommand(), come è facilmente intuibile crea un oggetto-comando,
ovvero istanzia la classe che permette di eseguire query. Esso restituisce un oggetto
IDbCommand,
interfaccia implementata da OleDbCommand, OdbcCommand e SqlCommand, in
questo modo potremo eseguire query su tutti questi (e altri) DBMS senza
neppure sapere a quale ci stiamo riferendo.
Private Function FillDataSet(ByVal rdrReader As System.Data.IDataReader) As DataSet
Dim dsOutput As New DataSet
'Ciclo per la lista delle tabelle
Do
Dim dtSchema As DataTable = rdrReader.GetSchemaTable()
Dim dtBuffer As New DataTable
If Not dtSchema Is Nothing Then
'Ciclo della tabella contenente la lista delle colonne
'della tabella che sta per essere letta
For CRows As Integer = 0 To dtSchema.Rows.Count - 1
'Compila la descrizione della tabella che sta per essere letta
Dim drBuffer As DataRow = dtSchema.Rows(CRows)
Dim strColumnName As String = DirectCast(drBuffer("ColumnName"), String)
'Crea la colonna con nome e tipo di dati forniti e la aggiunge alla
'lista delle colonne della tabella che sta per essere letta
Dim clnBuffer As New DataColumn(strColumnName, _
DirectCast(drBuffer("DataType"), Type))
dtBuffer.Columns.Add(clnBuffer)
Next CRows
'Aggiunge al DataSet la tabella, per ora vuota
dsOutput.Tables.Add(dtBuffer)
'Legge (e copia) dal DataReader riga per riga i valori
'dei campi della tabella corrente
'e li copia nella DataTable appena creata
Do While rdrReader.Read()
Dim drBuffer As DataRow = dtBuffer.NewRow()
'Aggiunge un campo alla volta nella colonna rispettiva
For CFields As Integer = 0 To rdrReader.FieldCount - 1
drBuffer(CFields) = rdrReader.GetValue(CFields)
Next CFields
dtBuffer.Rows.Add(drBuffer)
Loop
End If
'Continua il ciclo finchè non vi sono più tabelle
Loop While rdrReader.NextResult()
'Se non c'è alcuna tabella restituisce Nothing
If dsOutput.Tables.Count > 0 Then Return dsOutput Else Return Nothing
End Function
Spiegare nel dettaglio questa funzione va oltre lo scopo di questo
articolo, ma in sintesi essa legge una tabella alla volta, di ogni
tabella prende la struttura attraverso il metodo GetSchemaTable di
System.Data.IDataReader, prepara una DataTable e poi vi
inserisce i
dati forniti. Si viene così ad avere un DataSet completo di tutte le
tabelle richieste dalla query con nomi di campo e tipi corretti.
Solitamente questo compito di lettura viene delegato ad un DbDataAdapter,
ma
nel nostro caso, per ragioni già spiegate, questa soluzione non è
percorribile.
|
|||
| << INDIETRO | by VeNoM00 | ||