- 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 |