Una libreria per MySql - parte seconda
a cura di Lino Aiello (requisiti: conoscenza generica di .Net e di MySql)Premessa
Dopo aver trattato, nella prima parte di questa esposizione della libreria per MySql, circa le intestazioni, le proprietà, la connessione, le varie query sia di selezione e modifica, e da ultimo, delle stored procedures, ci occuperemo, in questa seconda ed ultima parte, ci occuperemo dei seguenti argomenti:
- Funzioni
- Utilità
- Backup e restore
- Transazioni
Inoltre, alla fine dell'articolo, verrà riportato un semplicissimo programmino che utilizza alcune delle funzioni di base della libreria, il cui scopo è quello di familiarizzarsi con essa.
In aggiunta, verrà proposta - in formato installabile dato il numero elevato di righe di codice e di form - una shell di gestione per MySql (MySqlAdmin.msi), costruita intorno alla libreria di cui discutiamo, che ne illustra meglio le potenzialità.
- N.B. - Alcune funzioni si servizio non verranno riportate per brevità di trattazione.
Il lettore potrà prenderne visione dal codice di MyClient.vb.Funzioni
Public Function MySqlFunction(ByVal Testo As String, ByVal Dati As ArrayList) As String Dim i As Integer = 0 Dim q As String = "" Dim qTemp As String = "" If Not Flag Then Return Nothing Exit Function End If Try If Dati(0) Is Nothing Then Return Nothing Exit Function End If For i = 0 To Dati.Count - 1 If IsDBNull(MySqlPar(Dati(i))) Then qTemp = "NULL" Else qTemp = MySqlPar(Dati(i)).ToString End If q = q + qTemp + "," Next q = Mid(q, 1, q.Length - 1) q = "SELECT " + Testo + "(" + q + ");" Dim ret As Object = Nothing myCommand.CommandText = q ret = myCommand.ExecuteScalar() If ret Is DBNull.Value Then Return "" Else Return ret.ToString End If Catch ex As MySqlException Throw End Try End FunctionTutti i databases relazionali hanno la possibilità di creare e utilizzare funzioni.
Ma cosa sono le funzioni? Sono particolari procedure (assimilabili alle stored) che permettono di ampliare le potenzialità del linguaggio SQL, il quale, com'è noto, non possiede in modo nativo molte funzioni che sono proprie dei linguaggi ad oggetti (VB, C#, ecc.).
Per realizzare questi costrutti si ha necessità di conoscere il linguaggio proprio del motore che si sta usando, per cui si rinvia alla documentazione tecnica di MySql per i dettagli.
Le funzioni restituiscono un unico valore, che rappresenta il risultato delle operazioni fatte nel corpo della funzione medesima, le quali possono essere anche molto complesse al loro interno.Qualunque sia il tipo restituito, il metodo MySqlFunction restituisce sempre un valore di tipo String, per cui sarà cura dello sviluppatore operare le opportune conversioni.
Il metodo effettua alcuni controlli per verificare che la connessione sia attiva (campo Flag) e che siano stati trasferiti i parametri (obbligatori).
Successivamente sottopone i parametri alle opportune conversioni tramite la funzione di servizio MySqlPar già vista, costruisce la stringa da passare alla linea di comando del motore di MySql (parametro q), e raccoglie il valore di ritorno (scalare, trattandosi di un solo parametro) in ret.Sintassi: string = Classe.MySqlFunction(string, arraylist)Esempio:
Sia Moltiplica il nome di una banalissima funzione che restituisce il prodotto di due parametri interi.
Siano i due parametri 4 e 5.Dim cl As New MySqlDataConnect.MyClient Dim w As New arraylist w.Add(4) w.Add(5) Dim s As String = cl.MySqlFunction("Moltiplica", w)Dopo l'esecuzione del codice, s conterrà il valore "20"
Utility
Public Sub MySqlSender(ByVal Testo As String) If Not Flag Then Exit Sub End If Try myCommand.CommandType = CommandType.Text myCommand.CommandText = Trim(Testo) myCommand.ExecuteNonQuery() Catch ex As MySqlException Throw End Try End Sub Public Function MySqlShowCreateTable(ByVal Testo As String) As String '//L'unico modo per leggere il campo che contiene la definizione della tabella, in '//modalità 'Option strict on', è quello di utilizzare un dataread ( e non un '//datatable che non sembra in grado di leggere un campo LONGTEXT che viene '//immagazzinato da MySql come System.Byte[]) Try Dim dr As MySqlDataReader Dim s As String = "" myCommand.CommandType = CommandType.Text myCommand.CommandText = "SHOW CREATE TABLE " + Testo + " " dr = myCommand.ExecuteReader dr.Read() s = dr.GetString(1) dr.Close() s = Replace(s, Chr(10), ControlChars.CrLf) Return s Catch ex As MySqlException Throw End Try End Function Public Function MySqlShowCreateStored(ByVal Testo As String) As String '//L'unico modo per leggere il campo che contiene la definizione della stored, in '//modalità 'Option strict on', è quello di utilizzare un dataread ( e non un '//datatable che non sembra in grado di leggere un campo LONGTEXT che viene '//immagazzinato da MySql come System.Byte[]) Try Dim dr As MySqlDataReader Dim s As String = "" myCommand.CommandType = CommandType.Text myCommand.CommandText = "SHOW CREATE PROCEDURE " + Testo + " " dr = myCommand.ExecuteReader dr.Read() s = dr.GetString(2) dr.Close() s = Replace(s, Chr(10), ControlChars.CrLf) Return s Catch ex As MySqlException Throw End Try End Function Public Function MySqlShowCreateFunction(ByVal Testo As String) As String '//Esattamente uguale a MySqlShowCreateStored, ma per le funzioni Try Dim dr As MySqlDataReader Dim s As String = "" myCommand.CommandType = CommandType.Text myCommand.CommandText = "SHOW CREATE FUNCTION " + Testo + " " dr = myCommand.ExecuteReader dr.Read() s = dr.GetString(2) dr.Close() s = Replace(s, Chr(10), ControlChars.CrLf) Return s Catch ex As MySqlException Throw End Try End Function Public Function MySqlShowCreateTrigger(ByVal Testo As String) As String '//Esattamente uguale a MySqlShowCreateStored, ma per i triggers '//Questa funzione è stata introdotta a partire dalla versione 5.1.21 di '//MySql. Se usata con versioni inferiori, ritorna un errore di sintassi. '//Per le versioni anteriori alla 5.1.21, è possibile ottenere lo schema del trigger '/ricostruendolo dalla tabella "Triggers" di information_schema Try Dim dr As MySqlDataReader Dim s As String = "" myCommand.CommandType = CommandType.Text myCommand.CommandText = "SHOW CREATE TRIGGER " + Testo + " " dr = myCommand.ExecuteReader dr.Read() s = dr.GetString(2) dr.Close() s = Replace(s, Chr(10), ControlChars.CrLf) Return s Catch ex As MySqlException Throw End Try End Function Public Sub MySqlChangeDatabase(ByVal NomeDb As String) Try If Flag Then Me.myConnection.ChangeDatabase(NomeDb) End If Catch ex As MySqlException Throw End Try End SubCiascun metodo di questo gruppo ha una sua specifica utilità.
Alcuni sono più utili di altri; alcuni sono necessari per cui vanno assolutamente inclusi in una procedura gestionale, ad esempio, altre meno. Il più importante di tutti è sicuramente .La struttura del metodo MySqlSender è quanto di più semplice si possa pensare: esso infatti è costituito da un semplice Command, il cui testo si limita a trasmettere delle istruzioni a MySql, agendo in tal modo come linea di comando del database (per intenderci, come fosse l'utente a trasmettere comandi a mezzo tastiera).
Poiché l'invio è da considerare unidirezionale, viene utilizzato ExecuteNonQuery.
Per mezzo di MySqlSender è possibile creare o distruggere oggetti come tabelle, stored, viste, funzioni; inviare comandi di settaggio (se non tutti, un gran numero); creare ed eliminare utenti; assegnare o modificare password; gestire i privilegi sugli oggetti dei databases; bloccare o sbloccare tabelle; modificare il comportamento di MySql ecc.Il motivo per cui il metodo MySqlSender dovrebbe essere sempre incluso in un eseguibile è ben spiegato nel caso di tabelle temporanee.
Le tabelle temporanee sono quegli oggetti del database che hanno vita solo per la durata della connessione; spariscono alla chiusura della stessa.
Spesso vengono utilizzate per creare tabelle di appoggio che servono come fonte dati per altre operazioni. Non possono essere create in sede di pianificazione del database perché, come detto, sono distrutte alla chiusura della connessione.
Sebbene sia possibile ricorrere a stored procedure deputate alla creazione di tabelle temporanee, spesso è molto più comodo costruirle 'al volo' all'interno del codice, al momento del loro utilizzo.
Dovendo quindi creare una tabella temporanea, è sufficiente scrivere il seguente codice:Classe.MySqlSender("CREATE TABLE #Tabella(......)")La tabella è creata, potrà essere manipolata con le usuali istruzioni e verrà distrutta al termine della connessione.
I tre metodi "Show" e cioè:
MySqlShowCreateTable(string) MySqlShowCreateStored(string) MySqlShowCreateFunction(string)sono simili tra loro e restituiscono in una stringa lo script dell'oggetto relativo, invocando l'omonimo metodo di MySql.
Essi raccolgono il risultato della chiamata in un DataReader, e restituiscono un valore String.
Questi metodi sono utilizzati principalmente nella procedura di backup (vedere nel seguito), e sono veramente necessari solo nel caso di applicativi prettamente dedicati alla gestione di MySql (come, ad esempio, la shell che viene qui proposta).
L'ultimo metodo presente in questo gruppo, MySqlChangeDatabase(string), come si intuisce, serve a cambiare il database corrente, qualora ve ne fosse bisogno.
Ovviamente, l'operazione avrà successo solo nel caso si posseggano i privilegi relativi.Backup
Public Sub MySqlBackupSingleDB(ByVal Testo As String) '//Testo = percorso completo del file di backup '// es. c:\MiaDir\miobackup[.estensione] '//E' compito de programma chiamante, costruire la stringa esatta. Const MSG_00 As String = "Autore: P.Aiello - 2007" Const MSG_01 As String = "Utente: " Const MSG_02 As String = "Server: " Const MSG_11 As String = "Applicazione: " Const MSG_12 As String = "Database: " Const MSG_15 As String = "DBMS: MySql v. " Const MSG_16 As String = "Struttura tabella: " Const MSG_17 As String = "Dati tabella: " Const MSG_18 As String = "Fine Backup: " Dim i As Integer = 0 Dim q As Integer = 0 Dim j As Integer = 0 Dim y As Integer = 0 Dim nameApp As String = "" Dim nameTableArray As New ArrayList Dim nameViewArray As New ArrayList Dim nameStoredArray As New ArrayList Dim nameFuncArray As New ArrayList Dim totRecords As Long = 0 Dim numCurrentRecords As Long = 0 Dim overLongProgress As Long = 0 Dim sCarrier As New System.Text.StringBuilder("") Dim mysqlversion As String = "" Dim InsertGroup As String = "" Dim RecCounter As Integer = 0 Dim strFlush As String = "" Dim strColumnsName As String = "" Dim recFlag As Boolean = False Dim dt As New DataTable Dim rows() As DataRow Dim dColumnsName As New DataTable Dim rowsColumnsName() As DataRow Try Testo = Testo.Trim If My.Computer.FileSystem.FileExists(Testo) = True Then My.Computer.FileSystem.DeleteFile(Testo, FileIO.UIOption.OnlyErrorDialogs, _ FileIO.RecycleOption.SendToRecycleBin, _ FileIO.UICancelOption.ThrowException) End If nameApp = My.Application.Info.AssemblyName + " v: " + My.Application.Info.Version.ToString dt = Me.MySqlDirectQuery("SHOW VARIABLES LIKE 'version'") rows = dt.Select() mysqlversion = CStr(rows(0).Item("value")) sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("-- " + MSG_00 + ControlChars.CrLf) sCarrier.Append("-- " + ControlChars.CrLf) sCarrier.Append("-- " + MSG_01 + Me.MySqlUID + ControlChars.CrLf) sCarrier.Append("-- " + MSG_02 + Me.MySqlServer + ControlChars.CrLf) sCarrier.Append("-- " + MSG_11 + nameApp + ControlChars.CrLf) sCarrier.Append("-- " + MSG_12 + Me.MySqlDataBase + ControlChars.CrLf) sCarrier.Append("-- " + MSG_15 + mysqlversion + ControlChars.CrLf) sCarrier.Append(ControlChars.CrLf) sCarrier.Append(ControlChars.CrLf) sCarrier.Append(ControlChars.CrLf) '//Prevenzione degli errori per violazione delle foreign key durate il processo di restore sCarrier.Append("-- " + ControlChars.CrLf) sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("SET FOREIGN_KEY_CHECKS=0;" + ControlChars.CrLf) sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("CREATE DATABASE IF NOT EXISTS " + Me.MySqlDataBase + ";" + ControlChars.CrLf) sCarrier.Append("USE " + Me.MySqlDataBase + ";" + ControlChars.CrLf) sCarrier.Append(ControlChars.CrLf) sCarrier.Append(ControlChars.CrLf) sCarrier.Append(ControlChars.CrLf) '/Cicla nel database ed assume il nome di tutte le tabelle in un arraylist dt = Me.MySqlDirectQuery("SHOW TABLE STATUS WHERE Engine IS NOT NULL") rows = dt.Select() For i = 0 To rows.GetUpperBound(0) If Not rows(i) Is DBNull.Value Then nameTableArray.Add(rows(i).Item("Name")) totRecords += CLng(rows(i).Item("Rows")) End If Next '//Per ogni elemento dell'arraylist, legge la struttura For i = 0 To nameTableArray.Count - 1 sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("-- " + ControlChars.CrLf) sCarrier.Append("-- " + MSG_16 + nameTableArray(i).ToString + ControlChars.CrLf) sCarrier.Append("-- " + ControlChars.CrLf) sCarrier.Append("DROP TABLE IF EXISTS " + nameTableArray(i).ToString + ";" + ControlChars.CrLf) sCarrier.Append(Me.MySqlShowCreateTable(nameTableArray(i).ToString) + ";" + ControlChars.CrLf) sCarrier.Append(ControlChars.CrLf) Dim currentTable As String = nameTableArray(i).ToString Dim strBuffer As String = "" Dim strCurLine As String = "" '//Legge i nomi delle colonne dalla tabella dColumnsName = Me.MySqlDirectQuery("SHOW COLUMNS FROM " + Me.MySqlDataBase + "." + currentTable) rowsColumnsName = dColumnsName.Select For q = 0 To rowsColumnsName.GetUpperBound(0) If Not rowsColumnsName(q) Is DBNull.Value Then strColumnsName += rowsColumnsName(q)(0).ToString + "," End If Next strColumnsName = Mid(strColumnsName, 1, strColumnsName.Length - 1) '//Legge tutti i campi della tabella dt = Me.MySqlDirectQuery("SELECT * FROM " + currentTable + " ") sCarrier.Append("-- " + ControlChars.CrLf) sCarrier.Append("-- " + MSG_17 + currentTable + ControlChars.CrLf) sCarrier.Append("-- " + ControlChars.CrLf) sCarrier.Append("ALTER TABLE " + currentTable + " DISABLE KEYS;" + ControlChars.CrLf) sCarrier.Append("LOCK TABLES " + currentTable + " WRITE;" + ControlChars.CrLf) My.Computer.FileSystem.WriteAllText(Testo, sCarrier.ToString, True) '///////////////LETTURA RECORDS INIZIO 'Azzera le variabili di gruppo sCarrier.Length = 0 InsertGroup = "" RecCounter = 0 'Se esistono righe nella tabella corrente... rows = dt.Select If rows.Length > 0 Then InsertGroup = "INSERT INTO " + currentTable + "(" + strColumnsName + ") VALUES " + _ ControlChars.CrLf sCarrier.Append(InsertGroup) 'Per ogni riga (j) della tabella corrente, legge i campi (y)... For j = 0 To rows.GetUpperBound(0) For y = 0 To rows(j).ItemArray.GetUpperBound(0) strBuffer = ParBackup(rows(j).ItemArray(y)) If strBuffer.Length <> 0 Then strCurLine += strBuffer + "," Else strCurLine += "NULL" + "," End If Next y If strCurLine.Length <> 0 Then strCurLine = Mid(strCurLine, 1, strCurLine.Length - 1) strCurLine = "(" + strCurLine + ")," + ControlChars.CrLf sCarrier.Append(strCurLine) recFlag = True End If strBuffer = "" strCurLine = "" numCurrentRecords += 1 overLongProgress = CLng(numCurrentRecords * 100 / totRecords) If overLongProgress > 100 Then overLongProgress = 100 End If RaiseEvent SendProgressBackup(overLongProgress) RecCounter += 1 'Scrive i records a gruppi pari al valore di RecCounter If RecCounter >= 20 Then strFlush = Mid(sCarrier.ToString, 1, sCarrier.ToString.Length - 3) + ";" + _ ControlChars.CrLf My.Computer.FileSystem.WriteAllText(Testo, strFlush, True) sCarrier.Length = 0 sCarrier.Append(InsertGroup) RecCounter = 0 recFlag = False End If Next j End If 'Prima di passare alla tabella successiva, verifica se ci sono record da scrivere nel buffer 'di(sCarrier) If Not recFlag Then sCarrier.Length = 0 Else '// Ci sono records da scrivere strFlush = Mid(sCarrier.ToString, 1, sCarrier.ToString.Length - 3) + ";" + ControlChars.CrLf My.Computer.FileSystem.WriteAllText(Testo, strFlush, True) sCarrier.Length = 0 recFlag = False End If sCarrier.Append("UNLOCK TABLES;" + ControlChars.CrLf) sCarrier.Append("ALTER TABLE " + currentTable + " ENABLE KEYS;" + ControlChars.CrLf) My.Computer.FileSystem.WriteAllText(Testo, sCarrier.ToString, True) sCarrier.Length = 0 strColumnsName = "" Next i '/////////////// LETTURA RECORDS FINE '//Se esistono View nel database, ne scrive la struttura dt = Me.MySqlDirectQuery("SHOW TABLE STATUS WHERE Engine IS NULL") rows = dt.Select() If rows.Length > 0 Then sCarrier.Append("-- " + ControlChars.CrLf) sCarrier.Append("-- Definizione delle viste" + ControlChars.CrLf) sCarrier.Append("-- " + ControlChars.CrLf) sCarrier.Append("" + ControlChars.CrLf) For i = 0 To rows.GetUpperBound(0) If Not rows(i) Is DBNull.Value Then nameViewArray.Add(rows(i).Item("Name")) sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("-- Struttura della vista " + nameViewArray(i).ToString + ControlChars.CrLf) sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("DROP VIEW IF EXISTS " + nameViewArray(i).ToString + ";" + ControlChars.CrLf) sCarrier.Append(Me.MySqlShowCreateTable(nameViewArray(i).ToString) + ";" + ControlChars.CrLf) My.Computer.FileSystem.WriteAllText(Testo, sCarrier.ToString, True) sCarrier.Length = 0 End If Next End If '//Se esistono Stored procedures nel database, ne scrive la struttura dt = Me.MySqlDirectQuery("SHOW PROCEDURE STATUS WHERE DB='" + Me.MySqlDataBase + "'") rows = dt.Select() If rows.Length > 0 Then sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("-- " + ControlChars.CrLf) sCarrier.Append("-- Definizione delle stored procedures" + ControlChars.CrLf) sCarrier.Append("-- " + ControlChars.CrLf) sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("" + ControlChars.CrLf) For i = 0 To rows.GetUpperBound(0) If Not rows(i) Is DBNull.Value Then nameStoredArray.Add(rows(i).Item("Name")) sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("-- Struttura della stored procedure " + nameStoredArray(i).ToString + _ ControlChars.CrLf) sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("DROP PROCEDURE IF EXISTS " + nameStoredArray(i).ToString + ";" + _ ControlChars.CrLf) sCarrier.Append(Me.MySqlShowCreateStored(nameStoredArray(i).ToString) + ";" + _ ControlChars.CrLf) My.Computer.FileSystem.WriteAllText(Testo, sCarrier.ToString, True) sCarrier.Length = 0 End If Next End If '//Se esistono funzioni nel database, ne scrive la struttura dt = Me.MySqlDirectQuery("SHOW FUNCTION STATUS WHERE DB='" + Me.MySqlDataBase + "'") rows = dt.Select() If rows.Length > 0 Then sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("-- " + ControlChars.CrLf) sCarrier.Append("-- Definizione delle funzioni" + ControlChars.CrLf) sCarrier.Append("-- " + ControlChars.CrLf) sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("" + ControlChars.CrLf) For i = 0 To rows.GetUpperBound(0) If Not rows(i) Is DBNull.Value Then nameFuncArray.Add(rows(i).Item("Name")) sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("-- Struttura della funzione " + nameFuncArray(i).ToString + _ ControlChars.CrLf) sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("DROP FUNCTION IF EXISTS " + nameFuncArray(i).ToString + ";" + _ ControlChars.CrLf) sCarrier.Append(Me.MySqlShowCreateFunction(nameFuncArray(i).ToString) + ";" + _ ControlChars.CrLf) My.Computer.FileSystem.WriteAllText(Testo, sCarrier.ToString, True) sCarrier.Length = 0 End If Next End If '//Riallinea le foreign key e termina sCarrier.Length = 0 sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("SET FOREIGN_KEY_CHECKS=1;" + ControlChars.CrLf) sCarrier.Append("--" + ControlChars.CrLf) sCarrier.Append("--" + ControlChars.CrLf) sCarrier.Append("" + ControlChars.CrLf) sCarrier.Append("-- " + MSG_18 + Format(Today, "dd/MM/yyyy") + " " + _ Format(TimeOfDay, "HH:mm:ss") + ControlChars.CrLf) My.Computer.FileSystem.WriteAllText(Testo, sCarrier.ToString, True) RaiseEvent SendProgressBackup(100) Catch ex As OperationCanceledException Exit Sub Catch ex As MySqlException Throw Finally If Not dt Is Nothing Then dt.Dispose() End Try End SubPerché la necessità di un una funzione di backup? MySql non è fornito di una procedura all'uopo destinata?
Sì, esiste una procedura nativa in MySql che si chiama mysqldump. Ma tale programma non è perfettamente integrato nel motore principale, bensì risiede in una propria locazione della quale bisogna preliminarmente conoscere il percorso. Funziona unicamente dalla linea di comando e non può essere raggiunto tramite la connessione. E', in pratica, un programma a parte, indipendente dal resto. Invece, normalmente, nei programmi che si occupano di gestione delle basi di dati, non dovrebbe essere richiesto di uscire dalla propria procedura per effettuare la copia degli archivi, ma il tutto dovrebbe essere perfettamente integrato nel software che si sta usando.
Questo è il motivo per cui, in MySql, si rende necessario scrivere una routine di backup.Per fortuna il backup di MySql è costituito da un semplice file di testo nel quale sono riportate le strutture degli oggetti ed i dati in essi contenuti.
Il metodo di libreria MySqlBackupSingleDB fa proprio questo: legge il database e scrive in un file di testo, gestito tramite l'oggetto My, sia la struttura delle tabelle, viste, stored ecc, ed i dati in tali oggetti contenuti.
Tale metodo è in grado di eseguire il backup singolo dei database operativi.
Ciò vuol dire che non sarà possibile ottere il backup del motore mysql, né il backup complessivo di tutto l'ambiente.
Nonostante l'apparente complessità del tutto, non bisogna lasciarsi ingannare dalla lunghezza del codice. Infatti, tutte le righe di codice che iniziano con "- -" sono dei commenti che potrebbero essere omessi ai fini della funzionalità della routine.
Al metodo va passato il nome che si vuole dare al file di backup (compreso di percorso). Il codice, dopo aver aperto in scrittura un file di testo (tramite l'oggetto My), scrive in esso una serie di intestazioni (in forma di commenti, quindi omissibili).
Tutte le operazioni di scrittura vengono effettuate ricorrendo all'oggetto StringBuilder, che risulta più adatto, allo scopo, della semplice String.
Togliendo il superfluo dal metodo, il funzionamento, in sintesi, è il seguente, avendo cura di notare che ogni operazione viene scritta nel file di testo creato dall'oggetto My:
- Azzeramento delle FOREIGN_KEY se esistono
- Creazione del database (CREATE DATABASE)
- Creazione dell'elenco dei nomi delle tabelle (SHOW TABLE STATUS...), e creazione di un ciclo basato sul nome delle singole tabelle.
- Istruzione di cancellazione della tabella (DROP TABLE IF EXISTS...)
- Lettura della struttura della tabella (MySqlShowCreateTable) e successiva scrittura della stessa
- Prelevamento dei nomi delle colonne della prima tabella (SHOW COLUMNS FROM...)
- Caricamento in una DataTable di tutti i dati della tabella (SELECT FROM...)
- Disabilitazione delle chiavi (ALTER TABLE...DISABLE KEYS)
- Blocco delle tabelle necessario per motori MyISAM (LOCK TABLES...)
- Scrittura dei records a blocchi di 20 (INSERT INTO...), utilizzando i nomi di colonna sopra prelevati
- Attivazione dell'evento SendProgressBackup per il pilotaggio di una barra di avanzamento
- Dopo aver scritto tutti i record, sblocco della tabella (UNLOCK TABLES..)
- Riattivazione delle chiavi (ALTER TABLE...ENABLE KEYS)
- Passaggio alla tabella successiva
Dopo aver salvato tutte le tabelle, nella loro struttura e dati, analizza il database per verificare la presenza di altri oggetti quali viste, stored e funzioni.
Se tali oggetti sono presenti, ne crea un elenco, attiva un ciclo basato sul nome, scrive nel file una direttiva di cancellazione (DROP VIEW|PROCEDURE|FUNCTION IF EXISTS...) e ne riscrive la struttura (solamente, perché questi oggetti non contengono dati) mediante i metodi rispettivi (MySqlShowCreateTable, MySqlShowCreateStored, MySqlShowCreateFunction).
Giunti a questo punto, non rimane che riattivare le FOREIGN_KEY e scrivere alcuni commenti di chiusura (per esempio, la data del backup).Esempio d'uso di backup:
' VB Option Strict On Public Class Form1 '// Aprire un riferimento a MySqlDataConnect.dll Dim cl As New MySqlDataConnect.MyClient Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load '//Aprire la connessione (cambiare la password, se necessario) AddHandler cl.SendProgressBackup, AddressOf VediEventoB Try cl.MySqlServer = "localhost" cl.MySqlUID = "root" cl.MySqlPWD = "root" cl.MySqlDataBase = "prova" cl.MySqlConnect() Catch ex As Exception MessageBox.Show("Errore", ex.Message) End Try End Sub '//Fine connessione Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click Try cl.MySqlBackupSingleDB("C:\backup\B1.sql") MessageBox.Show("Backup effettuato con successo", "Fine backup", MessageBoxButtons.OK, MessageBoxIcon.Information) Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub '//PB1 è una ProgressBar pilotata dall'evento SendProgressBackup Private Sub VediEventoB(ByVal barValue As Long) PB1.Value = CInt(barValue) End Sub End Class//C# using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace backup { // Aprire un riferimento a MySqlDataConnect.dll public partial class Form1 : Form { //Creare un riferimento alla libreria MySqlDataConnect.MyClient cl = new MySqlDataConnect.MyClient(); public Form1() { //Associazione evento al gestore eventi cl.SendProgressBackup += new MySqlDataConnect.MyClient.SendProgressBackupEventHandler(VediEventoB); InitializeComponent(); init(); } //Aprire la connessione (cambiare la password, se necessario) private void init() { try { cl.MySqlServer = "localhost"; cl.MySqlUID = "root"; cl.MySqlPWD = "root"; cl.MySqlDataBase = "prova"; cl.MySqlConnect(); } catch (System.Exception e) { MessageBox.Show("Errore" + e.Message); } }//Fine connessione private void button1_Click_1(object sender, EventArgs e) { try { cl.MySqlBackupSingleDB(@"c:\backup\B2.sql"); MessageBox.Show("Backup effettuato con successo", "Fine backup", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (System.Exception ex) { MessageBox.Show("Errore" + ex.Message); } } //PB1 è una ProgressBar pilotata dall'evento SendProgressBackup private void VediEventoB(long barValue) { PB1.Value = (int)barValue; } } }Restore
Public Sub MySqlRestoreSingleDB(ByVal Testo As String) Try Dim sr As StreamReader = New StreamReader(Testo) Dim lines As String = "" Dim s As New System.Text.StringBuilder("") Dim t As New System.Text.StringBuilder("") Dim infoReader As System.IO.FileInfo Dim fileLen As Long = 0 Dim lenLine As Long = 0 Dim isStored As Boolean = False '//Ottiene la lunghezza in byte del file infoReader = My.Computer.FileSystem.GetFileInfo(Testo) fileLen = infoReader.Length Do lines = sr.ReadLine() Select Case Mid(lines, 1, 1) Case Is = "" Continue Do Case Is = "-" Continue Do Case Is = "/" Continue Do Case Else If lines.StartsWith("CREATE DEFINER") Then isStored = True End If Select Case isStored Case False s.Append(lines) If lines.EndsWith(";") Then lenLine += s.ToString.Length Me.MySqlSender(s.ToString) s.Length = 0 RaiseEvent SendProgressRestore(CLng(lenLine * 100 / fileLen)) End If Case True t.Append(lines + ControlChars.CrLf) If lines.ToUpper = "END;" Then lenLine += t.ToString.Length Me.MySqlSender(Mid(t.ToString, 1, t.ToString.Length - 1)) t.Length = 0 isStored = False RaiseEvent SendProgressRestore(CLng(lenLine * 100 / fileLen)) End If End Select End Select Loop Until lines Is Nothing RaiseEvent SendProgressRestore(100) sr.Close() Catch ex As MySqlException Throw End Try End SubIl restore è molto più semplice, e si basa sulle seguenti considerazioni.
Tutte le righe nel file di testo create con il backup, se iniziano con "CREATE DEFINER" terminano con "END;" e sono relative alle stored ed alle funzioni. Altrimenti, terminano con il solo carattere ";" e sono relative alle tabelle, ai dati delle stesse ed alle viste.
Nel primo caso, dopo aver aperto uno Stream sul file di testo, si analizza l'inizio della linea.
Se inizia con "CREATE DEFINER" è una procedura (stored o funzione), per cui si continua a leggere fino a che non si incontra un "END;". Una variabile di tipo booleano (isStored) si occupa di operare la discriminazione.
Uno StringBuilder viene caricato con il blocco di istruzioni fino al termine delle stesse ("END;") e viene inviato, tramite MySqlSender, alla linea di comando per la scrittura.
Nel contempo viene attivato il conteggio delle linee, il cui valore viene recuperato dall'evento SendProgessRestore, per il pilotaggio della barra di avanzamento.
Se invece la linea prelevata dallo Stream non inizia con "CREATE DEFINER", essa è relativa ad una tabella, vista o dati di tabella create con "INSERT INTO..." e terminerà con un ";".
Di nuovo, viene caricata uno StringBuilder con un blocco di dati terminati da un ";" che verranno inviati al motore MySql, sempre tramite MySqlSender, per la scrittura.
Anche in questo caso, si attiverà l'evento SendProgressRestore, per l'avanzamento della barra.
E così si proseguirà fino alla fine del file.Esempio di restore (speculare a quello del backup mostrato sopra):
' VB Option Strict On Public Class Form1 '// Aprire un riferimento a MySqlDataConnect.dll Dim cl As New MySqlDataConnect.MyClient Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load '//Aprire la connessione (cambiare la password, se necessario) '//Associazione dell'evento al gestore eventi AddHandler cl.SendProgressRestore, AddressOf VediEventoR Try cl.MySqlServer = "localhost" cl.MySqlUID = "root" cl.MySqlPWD = "root" cl.MySqlDataBase = "prova" cl.MySqlConnect() Catch ex As Exception MessageBox.Show("Errore", ex.Message) End Try End Sub '//Fine connessione Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click Try cl.MySqlRestoreSingleDB("C:\backup\B1.sql") MessageBox.Show("Restore effettuato con successo", "Fine restore", MessageBoxButtons.OK, _ MessageBoxIcon.Information) Catch ex As Exception MessageBox.Show(ex.Message) End Try End Sub '//PB1 è una ProgressBar pilotata dall'evento SendProgressRestore Private Sub VediEventoR(ByVal barValue As Long) PB1.Value = CInt(barValue) End Sub End ClassData l'identità con il backup, si omette il codice in C#
Transazioni
Prima di affrontare il tema delle transazioni, sono necessarie alcune precisazioni.
Lo storage engine di default di MySql è MyISAM. Questo motore di database non supporta le transazioni (almeno per il momento) ma soltanto il LOCK sulle tabelle.
Affinché sia possibile usufruire delle transazioni, è necessario l'uso dello storage engine InnoDB o BDB. Vi sono pure altri motori utilizzabili con MySql, ma tutto ciò esula dalla presente trattazione, per cui si rinvia alla letteratura tecnica specifica coloro i quali volessero approfondire l'argomento. Sebbene sia possibile utilizzare, nello stesso database, tabelle impostate su diversi storage engine, si sconsiglia l'uso di questa pratica.
Nell'illustrare l'uso delle transazioni, si farà riferimento alle tabelle InnoDB, sicuramente le più usate a tale scopo in ambiente MySql.
Per creare tabelle InnoDB, è sufficiente aggiungere la stringa "ENGINE=InnoDB;" dopo la parentesi di chiusura della definizione dello script di tabella.
Per utilizzare le transazioni, faremo riferimento a due proprietà (MySqlIsolation, MySqlTransIsPending) e a tre metodi (MySqlBeginTrans, MySqlCommit, MySqlRollback).MySqlIsolation
Imposta e restituisce il valore dello stato di isolamento della transazione
I valori che può assumere la proprietà, sono i seguenti:
REPETEABLE READ Specifica che le istruzioni non possono leggere dati modificati da altre transazioni di cui non è ancora stato eseguito il commit e che nessun'altra transazione può modificare i dati letti dalla transazione corrente, fino al completamento della transazione stessa. READ COMMITTED Specifica che le istruzioni non possono leggere le righe modificate da altre transazioni ma di cui non è ancora stato eseguito il commit. In questo modo si evitano letture dirty. Altre transazioni possono modificare i dati nell'intervallo tra le singole istruzioni della transazione corrente, con conseguenti letture irripetibili e la presenza di dati fantasma. READ UNCOMMITTED Specifica che le istruzioni possono leggere le righe modificate da altre transazioni ma di cui non è ancora stato eseguito il commit. SERIALIZABLE E' il caso più restrittivo. La lettura di un dato provoca il blocco totale degli aggiornamenti fino alla chiusura della transazione. Il valore di default della proprietà, cioè il valore che assume la transazione in atto, in assenza di attivazione della proprietà stessa, è REPETEABLE READ.
I rimanenti valori che può assumere la proprietà, e cioè Chaos, Snapshot e Unspecified, poichè non supportati da MySql, sono settati automaticamente al valore di default.
Una volta impostata la proprietà a un valore specifico, essa rimane per tutta la durata della connessione, salvo nuovo assegnamento in prossimità di altra transazione.Sintassi: Classe.MySqlIsolation = IsolationLevel.[valore]Esempi:
'VB Dim cl As New MyClient '... cl.MySqlIsolation = IsolationLevel.Serializable cl.MySqlBeginTrans() '... ' (varie istruzioni) '... cl.MySqlCommit()//C# //... cl.MySqlIsolation = IsolationLevel.Serializable; cl.MySqlBeginTrans(); //... // (varie istruzioni) //... cl.MySqlCommit();MySqlBeginTrans
Public Sub MySqlBeginTrans() Try If IsPending Then Exit Sub Select Case Me.m_MySqlIsolation.ToString Case "16" 'Chaos Me.MySqlSender("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ") Case "16777216" 'Snapshot Me.MySqlSender("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ") Case "-1" 'Unspecified Me.MySqlSender("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ") Case "4096" ' ReadCommitted Me.MySqlSender("SET TRANSACTION ISOLATION LEVEL READ COMMITTED") Case "256" ' ReadUncommitted Me.MySqlSender("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED") Case "65536" ' RepeatableRead ---Default Me.MySqlSender("SET TRANSACTION ISOLATION LEVEL REPEATABLE READ") Case "1048576" ' Serializable Me.MySqlSender("SET TRANSACTION ISOLATION LEVEL SERIALIZABLE") End Select Me.MySqlSender("START TRANSACTION") IsPending = True Catch ex As MySqlException Throw End Try End SubIl metodo inizia una nuova transazione.
All'inizio del codice viene analizzata la variabile IsPending, impostata dalla proprietà MySqlTransIsPending. Se vale True, significa che è già attiva un'altra transazione, per cui impedisce l'avvio della nuova e abbandona. Altrimenti, recupera il valore del livello di isolamento corrente dalla proprietà MySqlIsolation e la trasmette al server (tramite MySqlSender), subito dopo attiva la transazione propriamente detta, tramite la trasmissione al server di "START TRANSACTION" (sempre tramite MySqlSender). IsPending viene settata a True, a indicare una transazione in corso.
Per gli esempi, si fa riferimento a quanto riportato sopra per MySqlIsolation.MySqlCommit e MySqlRollback
Public Sub MySqlCommit() If Not IsPending Then Exit Sub Try Me.MySqlSender("COMMIT") Catch ex As MySqlException Me.MySqlRollback() Throw Finally IsPending = False End Try End Sub Public Sub MySqlRollback() If Not IsPending Then Exit Sub Try Me.MySqlSender("ROLLBACK") Catch ex As MySqlException Throw Finally IsPending = False End Try End SubLe due routine sono identiche, per cui verranno trattate insieme.
La prima delle due, MySqlCommit, consolida la transazione, mentre MySqlRollback l'annulla.
Ambedue agiscono se è attiva una transazione, cioè se IsPending vale True. Una volta eseguito il comando, IsPending viene di nuovo posta a False, ad indicare la conclusione della transazione corrente.Esempio applicativo
L'esempio che segue - che utilizza solo alcune delle funzioni basilari della libreria - sia per VB che per C#, presuppone l'utilizzo della libreria MySqlDataConnect.dll, da scaricare e già pronta per l'uso.
E' sufficiente aprire un riferimento alla detta libreria, in quanto la stessa ricomprende al suo interno la libreria MySql MySql.Data.Dll.
Qualora invece, si volesse utilizzare la classe MyClient in sorgente, è necessario scaricare la libreria MySql.Data.Dll dal sito di MySql (utilizzare almeno la versione 5.1.3.0), impostare una direttiva Imports (o using per C#) a MySql.Data.MySqlClient e referenziare la classe MyClient.
In ambedue i casi, creare un form con una casella di testo multilinea da chiamare txtTesto, una DataGridView da chiamare Grid1 ed un bottone da chiamare cmdEsegui. Quindi incollare il codice ed avviare il programma, dopo aver preso nota dei commenti esplicativi.'VB Option Strict On Public Class Form1 '/* Apre un riferimento a MySqlDataConnect.dll */ Dim cl As New MySqlDataConnect.MyClient Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load '//Aprire la connessione (cambiare la password, se necessario) Try cl.MySqlServer = "localhost" cl.MySqlUID = "root" cl.MySqlPWD = "root" cl.MySqlDataBase = "mysql" cl.MySqlConnect() demo() Catch ex As Exception MessageBox.Show("Errore", ex.Message) End Try End Sub '//Fine connessione Private Sub demo() '/* Crea un nuovo database, chiamato 'DBTest', con una tabella chiamata 'tab1' ' * che contiene quattro campi: stringa, data, double e un campo contatore */ Try cl.MySqlSender("CREATE DATABASE IF NOT EXISTS DBTest") '//Si crea la tabella, se non esiste, con Engine InnoDb Dim s As String = "CREATE TABLE IF NOT EXISTS DBTest.tab1" + _ "(nome VARCHAR(25) default NULL," + _ "data DATE default NULL," + _ "importo DOUBLE default NULL," + _ "id INT NOT NULL AUTO_INCREMENT," + _ "PRIMARY KEY(id)) ENGINE=InnoDB" cl.MySqlSender(s) '/* Si crea ora, un utente del database 'DBTest', a cui si assegnano tutti '* i privilegi sul database 'DBTest', ad eccezione della possibilità di trasferire '* ad altri i propri privilegi. L'utente ha nome 'vbuser' e password 'vb2007' '* Notare che il server viene definito come '%' (wildcard), ciò significa '* che l 'accesso per vbuser potrà avvenire da qualsiasi client in rete */ s = "GRANT ALL PRIVILEGES ON DBTest.* TO 'vbuser'@'%' IDENTIFIED BY 'vb2007'" cl.MySqlSender(s) '/*A questo punto, è stato creato il database operativo, la tabella ed un utente ' * abilitato ad operare su di esso. La connessione all'utente 'root' non è più necessaria ' * quindi può essere chiusa ed aperta sul nuovo utente creato. ' * (Ovviamente, la vecchia connessione potrebbe essere conservata sull'utente ' * 'root', ed aprire una nuova connessione sul nuovo utente) */ cl.MySqlConnectionClose() '/* A titolo di esempio, si utilizzi un metodo alternativo per aprire la nuova '* connessione. Se l'accesso non avviene da 'localhost', indicare il nome '* del server */ cl.MySqlConnect("Persist Security Info=false;server=localhost;user id=vbuser;" + _ "password=vb2007;database=DBTest") ' /*La connessione è aperta sul nuovo utente e sul nuovo database. ' * E' ora possibile operare sulla tabella tab1, inserendo i comandi ' * nella casella di testo, ed inviandoli tramite il pulsante "cmdEsegui" */ Catch ex As Exception MessageBox.Show("Errore" + ex.Message) End Try End Sub ' //Fine creazione oggetti database '/*Si inseriranno dei dati nella tabella utilizzando una query parametrica. '* Nella istruzione INSERT, da scrivere nella casella di testo, '* indicare i parametri con il segnaposto "?". '* Es. INSERT INTO tab1(nome,data,importo) values(?,?,?). '* I parametri verranno trasportati da un ArrayList. '* Se la prima lettera della stringa nella casella di testo è una 'S' o 's', '* si tratterà di una query di selezione, altrimenti sarà di modifica. '* Se si tratta di una query di selezione, a titolo di esempio, verrà '* utilizzata una query diretta (senza parametri), e quindi scrivere nella casella di testo '* qualcosa come "SELECT * FROM Tab1" oppure "SELECT data FROM tab1 '* WHERE nome='D'Azeglio'" ecc. '* SIA CHE SI TRATTI DI SELECT O INSERT, UPDATE ecc., I PARAMETRI '* SE PRESENTI DOVRANNO ESSERE TUTTI UTILIZZATI E NELLA SEQUENZA '* 1 A 1 */ Private Sub cmdEsegui_Click(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles cmdEsegui.Click() Try Grid1.AutoGenerateColumns = True Dim dt As DataTable Dim s As String = txtTesto.Text If (s.StartsWith("S", StringComparison.InvariantCultureIgnoreCase)) Then dt = cl.MySqlDirectQuery(s) Grid1.DataSource = dt Else Dim w As New ArrayList() w.Add("Rossini") w.Add(System.Convert.ToDateTime("29/02/1792")) w.Add(126598.52) '//modifica la tabella e successivamente effettua una select generale cl.MySqlDirectMod(s, w) dt = cl.MySqlDirectQuery("select * from tab1") Grid1.DataSource = dt w.Clear() End If Catch ex As Exception MessageBox.Show("Errore", ex.Message) End Try End Sub Private Sub Form1_FormClosed(ByVal sender As Object, _ ByVal e As System.Windows.Forms.FormClosedEventArgs) _ Handles Me.FormClosed cl.MySqlConnectionClose() End Sub End Class//C# using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace WindowsApplication1 { /* Aprire un riferimento a MySqlDataConnect.dll */ public partial class Form1 : Form { //Crea un riferimento alla libreria MySqlDataConnect.MyClient cl = new MySqlDataConnect.MyClient(); public Form1() { InitializeComponent(); init(); demo(); } //Aprire la connessione (cambiare la password, se necessario) private void init() { try { cl.MySqlServer = "localhost"; cl.MySqlUID = "root"; cl.MySqlPWD = "root"; cl.MySqlDataBase = "mysql"; cl.MySqlConnect(); } catch (System.Exception e) { MessageBox.Show("Errore" + e.Message); } } //Fine connessione /* Crea un nuovo database, chiamato 'DBTest', con una tabella chiamata 'tab1' che contiene quattro campi: stringa, data, double e un campo contatore */ private void demo() { try { cl.MySqlSender("CREATE DATABASE IF NOT EXISTS DBTest"); //Si crea la tabella, se non esiste, con Engine InnoDb string s = "CREATE TABLE IF NOT EXISTS DBTest.tab1" + "(nome VARCHAR(25) default NULL," + "data DATE default NULL," + "importo DOUBLE default NULL," + "id INT NOT NULL AUTO_INCREMENT," + "PRIMARY KEY(id)) ENGINE=InnoDB"; cl.MySqlSender(s); /* Si crea ora, un utente del database 'DBTest', a cui si assegnano tutti i privilegi sul database 'DBTest', ad eccezione della possibilità di trasferire ad altri i propri privilegi. L'utente ha none 'c#user' e password 'c#2007' Notare che il server viene definito come '%' (wildcard), ciò significa che l'accesso per c#user potrà avvenire da qualsiasi client in rete */ s = "GRANT ALL PRIVILEGES ON DBTest.* TO 'c#user'@'%' IDENTIFIED BY 'c#2007'"; cl.MySqlSender(s); /*A questo punto, è stato creato il database operativo, la tabella ed un utente * abilitato ad operare su di esso. La connessione all'utente 'root' non è più necessaria * quindi può essere chiusa ed aperta sul nuovo utente creato. * (Ovviamente, la vecchia connessione potrebbe essere conservata sull'utente * 'root', ed aprire una nuova connessione sul nuovo utente) */ cl.MySqlConnectionClose(); /* A titolo di esempio, si utilizzi un metodo alternativo per aprire la nuova * connessione. Se l'accesso non avviene da 'localhost', indicare il nome * del server */ cl.MySqlConnect("Persist Security Info=false;server=localhost;user id=c#user;" + "password=c#2007;database=DBTest"); /*La connessione è aperta sul nuovo utente e sul nuovo database. * E' ora possibile operare sulla tabella tab1, inserendo i comandi * nella casella di testo, ed inviandoli tramite il pulsante "cmdEsegui" */ } catch (System.Exception e) { MessageBox.Show("Errore" + e.Message); } } //Fine creazione oggetti database /*Si inseriranno dei dati nella tabella utilizzando una query parametrica. * Nella istruzione INSERT, da scrivere nella casella di testo, * indicare i parametri con il segnaposto "?". * Es. INSERT INTO tab1(nome,data,importo) values(?,?,?). * I parametri verranno trasportati da un ArrayList. * Se la prima lettera della stringa nella casella di testo è una 'S' o 's', * si tratterà di una query di selezione, altrimenti sarà di modifica. * Se si tratta di una query di selezione, a titolo di esempio, verrà * utilizzata una query diretta (senza parametri), e quindi scrivere nella casella di testo * qualcosa come "SELECT * FROM Tab1" oppure "SELECT data FROM tab1 * WHERE nome='D'Azeglio'" ecc. * SIA CHE SI TRATTI DI SELECT O INSERT, UPDATE ecc., I PARAMETRI * SE PRESENTI DOVRANNO ESSERE TUTTI UTILIZZATI E NELLA SEQUENZA * 1 A 1 */ private void cmdEsegui_Click_1(object sender, EventArgs e) { try { Grid1.AutoGenerateColumns = true; DataTable dt = new DataTable(); string s = txtTesto.Text; if (s.StartsWith("S", StringComparison.InvariantCultureIgnoreCase)) { dt = cl.MySqlDirectQuery(s); Grid1.DataSource = dt; } else { ArrayList w = new ArrayList(); w.Add("D'Azeglio"); w.Add(System.Convert.ToDateTime("10/10/1813")); w.Add(126598.52); //modifica la tabella e successivamente effettua una select generale cl.MySqlDirectMod(s, w); dt = cl.MySqlDirectQuery("select * from tab1"); Grid1.DataSource = dt; w.Clear(); } } catch (System.Exception ex) { MessageBox.Show("Errore" + ex.Message); } } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { cl.MySqlConnectionClose(); } } }Conclusioni
La trattazione della libreria MyClient è così terminata.
Nel file.zip a corredo dell'articolo, scaricabile dall'area download, è compreso non solo il sorgente della classe MyClient (MyClient.vb), ma anche il file di setup per la shell per MySql (MySqlAdmin.msi), che consiglio di installare, concepita quale test della libreria, anch'essa fornita (MySqlDataConnect.dll), onde valutarne le possibilità complessive.
Nella speranza di aver dato un piccolo contributo alla comunità degli sviluppatori, resto a disposizione all'indirizzo email lino.aiello@gmail.com per chiarimenti, consigli e quant'altro (non dimenticando gli errori!).Note sull'Autore
Pasquale Aiello (detto Lino) vive e lavora a Pescara, dove è nato molto tempo fa (1947), e dove svolge la professione di Dottore Commercialista - Revisore dei Conti.
Si occupa di informatica fin dai primi anni 80', e ha utilizzato quasi tutti gli ambienti di programmazione, a partire da MSBasic, Clipper, C/C++ ed altri. A causa del suo lavoro, è stato impegnato principalmente in ambito gestionale. Ha realizzato procedure informatiche per Comuni ed altri Enti Pubblici. Attualmente ha focalizzato la sua attività lavorativa, come CTU/CTP, nel campo del contenzioso bancario (Anatocismo, reverse banking, modifica condizioni di utilizzo e ricalcolo su C/C, ecc.ecc.) utilizzando procedure proprietarie.
Nel poco tempo libero, coltiva come hobbies la lettura (saggistica e varia umanità) e la musica (preferibilmente classica).