Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Dataset e query designer

Lavorare con i dati in modalità disconnessa e creare query in modo visuale
Lavorare con i dati in modalità disconnessa e creare query in modo visuale
Link copiato negli appunti

Molto spesso il pattern tipico di accesso ai dati si riduce alle seguenti tre macro operazioni:

  • Caricare i dati in memoria
  • Visualizzarle, modificare, analizzare i dati in memoria
  • Aggiornare eventualmente il database con le modifiche effettuate

Per risolvere questo tipico scenario si può utilizzare un oggetto molto particolare chiamato DataSet semplicemente aggiungendolo al progetto con il menu "add file" e scegliendo come tipo di file Dataset come mostrato in Figura.

Figura 1. Aggiungere un dataset al progetto
Aggiungere un dataset al progetto

Un dataset fornisce un accesso ai dati secondo il noto pattern Table Module, dove per ogni tabella viene generato un oggetto corrispondente nel programma, in modo da potere elaborare i dati offline, in modalità disconnessa.

Una volta creato il DataSet possiamo importare lo schema delle tabelle che vogliamo utilizzare. Per farlo rapidamente possiamo sfruttare il "Server Explorer", scegliere di aggiungere una nuova Data Connection e connettersi con il database. Fatto questo possiamo possibile navigare tra gli oggetti del database.

Figura 2. Connettere un database in Visual Studio
Connettere un database in Visual Studio

Quando il database è connesso selezioniamo una o più tabelle e, con il drag and drop, le spostiamo nel Database Designer per importare in maniera automatica la struttura.

Figura 3. Rappresentazione tabellare nel dataset designer
Rappresentazione tabellare nel dataset designer

Osservando l'immagine notiamo un collegamento tra le tabelle Customers e Orders, che rappresenta la foreign key che esiste nel database. Visual Studio è infatti in grado di analizzare le relazioni tra tabelle e riportarle correttamente nella struttura del Dataset.

Il designer è una rappresentazione di una serie di classi create automaticamente da Visual Studio per l'accesso alle tabelle selezionate: nel namespace System.Data, l'oggetto DataSet è un contenitore di DataTable che a loro volta contengono DataRow, proprio come un database contiene Tabelle ed ogni tabella contiene righe o tuple.

Quando importiamo la struttura di una tabella nel designer, Visual Studio ne crea una rappresentazione sfruttando queste classi base.

Infine abbiamo il TableAdapter, elemento che ha lo scopo di trasferire i dati dal database al dataset e viceversa. Se controlliamo le proprietà del TableAdapter della tabella Customers troviamo la proprietà SelectCommand, che contiene un oggetto SqlCommand in grado di effettuare la query select con cui popolare il contenuto della tabella in memoria. Il TableAdapter svolge il ruolo di Table Data Gateway per il DataSet.

Dietro le quinte l'accesso viene sempre effettuato con oggetti SqlConnection e SqlCommand ed i vari Dataset, DataAdapter, etc, servono solamente a rendere più semplice il lavoro.

Caricare in memoria i dati utilizzando il Dataset è decisamente banale:

using (NorthWindDs northwind = new NorthWindDs()) {
  using (NorthWindDsTableAdapters.CustomersTableAdapter ta = new NorthWindDsTableAdapters.CustomersTableAdapter()) {
    ta.Fill(northwind.Customers);
    foreach (NorthWindDs.CustomersRow row in northwind.Customers)
    {
      Console.WriteLine("Selezionato cliente Id {0} nome {1}",
                         row.CustomerID,
                         row.CompanyName);
    }
	}
}

Anche qui gli oggetti sono racchiusi in clausole using, poiché dietro le quinte vengono utilizzati oggetti SqlConnection e SqlCommand che debbono essere correttamente rilasciati.

In primo luogo si deve creare un'istanza del DataSet, nel nostro esempio NorthwindDs, e un'istanza dell'oggetto CustomersTableAdapter, che altro non è che il DataAdapter relativo alla tabella Customer creato dal designer. A questo punto invochiamo il metodo Fill() del DataAdapter per trasferire i dati dal database nel Dataset.

Quando Fill() completa il lavoro, possiamo iterare su tutte le righe della tabella Customers e, a differenza dell'approccio con il SqlDataReader, in questo caso ogni riga contiene una proprietà per ogni campo della tabella, il ché oltretutto rende più agevole scrivere il codice: in questo caso l'intellisense elenca tutti i nomi di colonna della tabella.

Vediamo ora come utilizzare il DataAdapter per filtrare le righe effettivamente caricate nel DataSet.

Sempre nel database designer, cliccando col tasto destro sul TableAdapter scegliamo la voce di menù New Query che apre un query designer che ci permette di creare le nostre query in modo visuale. Questo pannello, ormai un classico di Visual Studio, si rivela particolarmente utile in caso di query complesse che coinvolgono più tabelle. Ad esempio creare una query con un filtro LIKE sul campo CustomerID è veramente banale:

Figura 4. Creare una query nel query designer
Creare una query nel query designer

Grazie a questo approccio si centralizzano nel designer le query rendendone più facile la gestione, inoltre l'applicativo è in questo modo coerente al pattern Table Data Gateway, poiché tutte le query sono centralizzate in un unico punto. Ogni nuova query può essere usata in due modi differenti: il primo serve per effettuare il caricamento di una DataTable esistente in memoria.

ta.FillByCustomerIdSearch(northwind.Customers, "A");

Il designer ha creato per noi una funzione che accetta come primo argomento la tabella da riempire e di seguito un parametro tipizzato per ogni SqlParameter inserito nella query. Confrontando questo snippet con il codice che fa uso diretto di SqlCommand si apprezza la compattezza e la semplicità di questo approccio; mentre con i SqlParameter è necessario specificare manualmente tutti i parametri, con il rischio di dimenticarne qualcuno, in questo modo ogni query viene tradotta in una semplice funzione ed anche in questo caso l'intellisense ci aiuta listando il tipo dei parametri. Oltre al metodo Fillxxxx è solitamente generato anche un metodo Createxxx che permette di eseguire la query e direttamente creare un oggetto DataTable tipizzato.

Naturalmente l'indiscusso vantaggio del Dataset rispetto all'accesso diretto è che i dati possono essere modificati in memoria e le modifiche possono essere poi propagate al database semplicemente chiamando il metodo Update del TableAdapter.

ta.FillByCustomerIdSearch(northwind.Customers, "A");
foreach (NorthWindDs.CustomersRow row in northwind.Customers)
{
	row.CompanyName += "ADDED";
}
ta.Update(northwind.Customers);

Dietro le quinte ogni DataSet mantiene in memoria la versione originale delle righe oltre che la versione modificata. Grazie a questa informazione il DataAdapter è in grado di analizzare tutte le righe per individuare quelle aggiunte, modificate o cancellate ed utilizzare per ognuna di essere il comando corrispondente (InsertCommand, UpdateCommand, DeleteCommand).

Ti consigliamo anche