Guida al Visual Basic .NET
Capitolo 74° - Dalle relazioni agli oggetti Parte I
Usare queries per manipolare il database è un mezzo molto efficacie, anche se il processo per creare una query sottoforma di stringa
può risultare alquanto macchinoso in alcuni casi. A questo proposito, vorrei invitarvi a leggere le prime lezioni del tutorial che
ho scritto riguardo a LINQ, il linguaggio di querying integrato disponibile dalla versione 2008 del linguaggio (framework v3.5).
Vedremo ora solo il primo approccio, poiché il secondo è trattato già nel tutorial menzionato prima. DataSet
La classe DataSet ha lo scopo di rappresentare un database. Mediante un apposito oggetto, detto Adapter (che analizzeremo in seguito), è
possibile travasare tutti i dati del database in un oggetto DataSet e quindi operare su questo senza bisogno di query. Una volta terminate
le elaborazioni, si esegue il processo inverso aggiornando il database con le nuove modifiche apportate al DataSet. Questo è il
principio di base con cui si affronta il passaggio dalle relazioni agli oggetti.
DataTable
Se un DataSet rappresenta un database, allora un oggetto di tipo DataTable rappresenta un singola tabella, composta di righe e colonne. Nessun nuovo concetto da introdurre, quindi: si tratta solo di una classe che rappresenta ciò che abbiano visto fin ora per una relazione. I suoi membri sono pressoché simili a quelli di DataSet, con l'aggiunta delle proprietà Columns, Rows, PrimaryKey e del metodo AddRow (ho menzionato solo quelli di uso più frequente). Caricamento e binding
Ora possiamo caricare i dati in un DataSet ed eseguire un binding verso un controllo. Abbiamo già il concetto di binding nei capitoli sulla reflection, in riferimento alla possibilità di legare un identificatore a un valore. In questo caso, pur essendo fondamentalmente la stessa cosa, il concetto è leggermente differente. Noi vogliamo legare un certo insieme di valori ad un controllo, in modo che esso li visualizzi senza dover scrivere un codice particolare per inserirli. Il controllo che, per eccellenza, rende graficamente nel modo migliore le tabelle è DataGridView. Assumendo, quindi, di avere nel form solo un controllo DataGridView1, possiamo scrivere questo codice: Imports MySql.Data.MySqlClient Class Form1 Private Data As New DataSet Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim Conn As New MySqlConnection("Server=localhost; Database=appdata; Uid=root; Pwd=root;") Dim Adapter As New MySqlDataAdapter Conn.Open() Adapter.SelectCommand = New MySqlCommand("SELECT * FROM Customers;", Conn) Adapter.Fill(Data) Conn.Clone() DataGridView1.DataSource = Data.Tables(0) End Sub End Class
DataGridView1 verrà riempito con tutti i dati presenti nella prima (e unica) tabella del dataset. DataSet tipizzati
Nel prossimo esempio vedremo di accennare alla costruzione di una semplice applicazione per gestire brani musicali con un database, ed
eventualmente introdurrò un po' di codice per la riproduzione audio. In questo esempio, però, non useremo un generico
database, ma uno specifico database di cui conosciamo le proprietà e della cui esistenza siamo certi. Quindi faremo a meno di usare
un generico DataSet, ma ne creeremo uno specifico per quel database, che sia più semplice da manipolare. Useremo, quindi,
un DataSet tipizzato. Non dovremo scrivere alcuna riga di codice per far questo, poiché basterà "disegnare" la struttura del
database con uno specifico strumento che il nostro IDE mette a disposizioni, e che si chiama Table Designer. Mediante quest'ultimo, possiamo
delinare lo schema di un database e delle sue tabelle, e l'ambiente di sviluppo provvederà a scrivere un codice adeguato per creare
un dataset tipizzato specifico per quel database. A livello pratico, un dataset tipizzato non è altro che una classe derivata da
DataSet che definisce alcune proprietà e metodi atti a semplificare la scrittura di codice. Ad esempio, invece di referenziare la
prima cella della prima riga di una tabella, ottenerne il valore e convertirlo in intero, la versione tipizzata del dataset espone direttamente
una proprietà ID (ad esempio) che fa tutto questo. C'è solo un difetto nel codice autogenerato, ma lo illustrerò in
seguito. CREATE TABLE `albums` ( `ID` int(11) NOT NULL AUTO_INCREMENT, `Name` char(255) NOT NULL, `Year` int(11) DEFAULT NULL, `Description` text, `Image` text, PRIMARY KEY (`ID`) ); CREATE TABLE `authors` ( `ID` int(11) NOT NULL AUTO_INCREMENT, `Name` char(255) NOT NULL, `Nickname` char(255) DEFAULT NULL, `Description` text, `Image` text, PRIMARY KEY (`ID`) ); CREATE TABLE `songs` ( `ID` int(11) NOT NULL AUTO_INCREMENT, `Path` char(255) NOT NULL, `Title` char(255) DEFAULT NULL, `Author` int(11) DEFAULT NULL, `Album` int(11) DEFAULT NULL, PRIMARY KEY (`ID`) );
[Gli accenti tonici sono stati aggiunti da SQLyog, e sono obbligatori solo se il nome della colonna o della tabella contiene degli spazi.] Musica, maestro!
Ecco l'interfaccia del programma:
Public Class Form1 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim Conn As New MySqlConnection("Server=localhost; Database=appdata; Uid=root; Pwd=root;") Dim Adapter As New MySqlDataAdapter Conn.Open() 'Carica le tabelle nel dataset. Le tabelle sono ora 'accessibili mediante omonime proprietà dal 'dataset tipizzato Adapter.SelectCommand = New MySqlCommand("SELECT * FROM Songs;", Conn) Adapter.Fill(AppDataSet.Songs) Adapter.SelectCommand = New MySqlCommand("SELECT * FROM Authors;", Conn) Adapter.Fill(AppDataSet.Authors) Adapter.SelectCommand = New MySqlCommand("SELECT * FROM Albums;", Conn) Adapter.Fill(AppDataSet.Albums) Conn.Clone() End Sub Private Sub lstSongs_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lstSongs.SelectedIndexChanged If lstSongs.SelectedIndex < 0 Then Exit Sub End If 'Trova la riga con ID specificato. Il tipo SongsRow è stato 'definito dall'IDE durante la creazione del dataset tipizzato. Dim S As AppDataSet.SongsRow = AppDataSet.Songs.FindByID(lstSongs.SelectedValue) lblName.Text = S.Title tabAuthor.Tag = Nothing 'Anche il metodo IsAuthorNull è stato definito dall'IDE. 'In generale, per ogni proprietà per cui non è stata 'specificata la clausola NOT NULL, l'IDE crea un metodo per 'verificare se quel dato attributo contiene un valore 'nullo. Equivale a chiamare S.IsNull(3). If Not S.IsAuthorNull() Then 'Ottiene un array che contiene tutte le righe della 'tabella Authors che soddisfano la relazione definita 'tra Songs e Authors. Dato che la chiave esterna della 'tabella figlio era un ID, la realzione, pur essendo 'teoricamente uno-a-molti, è in realtà 'uno-a-uno. Perciò, se questo array ha almeno 'un elemento, ne avrà solo uno. Dim Authors() As AppDataSet.AuthorsRow = S.GetAuthorsRows() 'Come IsNull, questo metodo equivale a chiamare 'S.GetChildRows("Songs_Authors") If Authors.Length > 0 Then Dim Author As AppDataSet.AuthorsRow = Authors(0) lblAuthorName.Text = Author.Name If Not Author.IsNicknameNull() Then lblAuthorName.Text &= vbCrLf & Chr(34) & Author.Nickname & Chr(34) End If If Not Author.IsImageNull() Then imgAuthor.Image = Image.FromFile(Author.Image) Else imgAuthor.Image = Nothing End If If Not Author.IsDescriptionNull() Then txtAuthorDescription.Text = Author.Description Else txtAuthorDescription.Text = "" End If tabAuthor.Tag = Author.ID End If End If tabAlbum.Tag = Nothing If Not S.IsAlbumNull() Then Dim Albums() As AppDataSet.AlbumsRow = S.GetAlbumsRows() If Albums.Length > 0 Then Dim Album As AppDataSet.AlbumsRow = Albums(0) lblAlbumName.Text = Album.Name If Not Album.IsYearNull() Then lblAlbumYear.Text = Album.Year Else lblAlbumYear.Text = "" End If If Not Album.IsImageNull() Then imgAlbum.Image = Image.FromFile(Album.Image) Else imgAlbum.Image = Nothing End If If Not Album.IsDescriptionNull() Then txtAlbumDescription.Text = Album.Description Else txtAlbumDescription.Text = "" End If tabAlbum.Tag = Album.ID End If End If End Sub Private Sub btnSearch_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSearch.Click If Not String.IsNullOrEmpty(txtSearch.Text) Then 'La proprietà Filter di un binding source è come 'una condizione SQL. In questo caso cerchiamo tutte le 'canzoni il cui titolo contenga la stringa specificata. SongsBindingSource.Filter = String.Format("title like '%{0}%'", txtSearch.Text) Else SongsBindingSource.Filter = "" End If End Sub End Class
C#, TypeScript, java, php, EcmaScript (JavaScript), Spring, Hibernate, React, SASS/LESS, jade, python, scikit, node.js, redux, postgres, keras, kubernetes, docker, hexo, etc...
|