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

DataSet tipizzati con Visual Studio

Generare visualmente sorgenti dati che rappresentano oggetti logici del DB
Generare visualmente sorgenti dati che rappresentano oggetti logici del DB
Link copiato negli appunti

La realizzazione di un livello per l'accesso ai dati (data-layer) per le nostre applicazioni web è ormai un passaggio fondamentale da compiere durante il corso dello sviluppo del sito, passaggio da affrontare con moltissima cura. Questo tipo di tecnica ci permette infatti di utilizzare dei meccanismi per la scrittura e la lettura dei dati del nostro database di cui possiamo tener traccia e modificarne la struttura in base alle esigenze evolutive dell'applicazione.

è anche vero però, che nella maggior parte delle occasioni, la realizzazione di questo livello risulta essere una scrittura ripetitiva di codice, classi e operazioni che abbiamo già fatto chissà quante volte. Nonostante ciò, non possiamo proprio evitare questo punto durante lo sviluppo del nostro sito web.

Qui, ci viene incontro Visual Studio, al suo interno è stato infatti introdotto un designer specifico per la creazione di strutture di dati tipizzate, a partire dallo schema di tabelle presente nella base di dati. Queste strutture, hanno preso il nome di DataSet tipizzati, in quanto derivano proprio dall'omonima classe presente all'interno del namespace System.Data (parte portante di tutta la tecnologia di ADO.NET).

Il designer si occupa di generare tutto il codice necessario per rappresentare gli oggetti del database e per effettuare le normali operazioni di lettura, aggiunta, modifica e cancellazione.

Cos'è un DataSet?

I DataSet tipizzati sono delle classi logiche create dal designer di Visual Studio. Queste classi, che derivano direttamente dalle classi DataSet, DataTable e DataRow del namespace System.Data, rappresentano il livello di accesso ai dati della nostra applicazione e i dati di business stessi che possiamo manipolare all'interno del sito.

Ogni DataSet generato dal designer, è memorizzato sul disco come un'XML Schema (con estensione .XSD); all'interno di questo file è presente l'intera struttura del nostro DataSet, tutti i relativi oggetti logici, come questi vengono descritti e le eventuali relazioni.

Visual Studio rappresenta graficamente le informazioni presenti nello schema, mentre il framework .NET, sottostante l'applicazione web, si occupa di generare ogni classe utile a rappresentare tutti gli oggetti logici descritti.

Perchè ASP.NET generi al volo le classi, è necessario salvare il DataSet tipizzato all'interno della directory "App_Code" della nostra applicazione. In fase di run-time, il framework, tramite la tecnica dei Build Providers (che associa ogni estensione ad una classe in grado di generare del codice .NET via CodeDom), legge tutti i file .XSD presenti e genera le relative classi, in modo tale da renderle disponibili all'intera applicazione.


Quello che stiamo facendo, in pratica, è definire un livello di astrazione dalla base di dati. Creiamo, attraverso la via dichiarativa, un insieme di tipi personalizzati in grado di contenere entità logiche di business e collezioni di entità, come se le avessimo scritte tutte a mano.

Un esempio pratico

Se la teoria appare un po' complicata, l'utilizzo pratico di questo strumento si rivela di una semplicità disarmante.

Come esempio, costruiamo un DataSet tipizzato per rappresentare le entità presenti all'interno del (notissimo) database "Northwind".

Nota: con la versione di SQL Server 2005 Express, il database non è compreso nell'installazione, ma può essere scaricato dal sito Microsoft e installato.

Per aggiungere il DataSet alla nostra applicazione, ci basta fare click con il tasto destro sulla directory App_Code, scegliere l'opzione "Add new item" e infine selezionare la voce "DataSet". In questo modo, Visual Studio .NET crea il file .xsd sul disco e fa partire il designer.

Figura 1. Creazione del DataSet
Creazione del DataSet

All'interno di ogni DataSet, è possibile inserire uno o più TableAdapter. Ogni TableAdapter è creato per svolgere la funzione di contenitore logico di una DataTable, ovvero il tipo di dato che rappresenta tabelle generate una una o più query al database.

Aprendo il dataset appena creato infatti, il designer avvia le procedure visuali per la creazione del primo TableAdapter; queste procedure ci permettono, tramite delle query testuali o delle stored procedure, di creare la nostra tabella logica (DataTable) e i vari metodi per la lettura e la scrittura dei dati nel database. Per esempio, specificando questa semplice query:

SELECT Customers.* FROM Customers

possiamo creare il TableAdapter per gestire la tabella dei clienti.

Se scegliamo l'opzione di auto-generazione delle query CRUD (Create, Retrive, Update, Delete), Visual Studio .NET 2005 creerà in automatico tutte le strutture per effettuare le normali operazioni di inserimento, modifica e cancellazione dei dati relativi alla tabella che abbiamo interfacciato con il nostro TableAdapter.

Figura 2. Esempio di TableAdapter
Esempio di TableAdapter

Nota: alla creazione di un TableAdapter, l'IDE legge l'intera struttura della tabella e la riversa in questo contenitore logico. Vengono quindi riportati tutti i vincoli impostati in ogni colonna della tabella mappata (tipo di dato, lunghezza massima, etc.), i vincoli di chiave primaria e chiave esterna, le relazioni, etc.

Una volta creato il nostro TableAdapter, possiamo effettuare delle operazioni di modifica in modo tale da personalizzare ulteriormente tale contenitore logico ed adattarlo alle esigenze della nostra applicazione. Possiamo infatti aggiungere nuove colonne, aggiungere nuovi vincoli di chiave primaria o di chiave esterna, aggiungere nuove relazioni con altri TableAdapter oppure possiamo aggiungere nuove query; tutte queste modifiche però, risulteranno staccate dalla base di dati.

Dopo aver creato questa prima struttura, possiamo già utilizzarla in una pagina web. Con pochi passaggi, possiamo creare una pagina che stampi a video l'elenco di tutti i clienti presi dal nostro database di prova. L'elenco sarà filtrabile e ordinabile per ogni colonna, conterrà una paginazione dei record e ci darà la possibilità di gestire in automatico eventuali modifiche ai dati, o cancellazioni.

Tutto ciò grazie ai controlli GridView e ObjectDataSource. Il primo dei due fornisce la presentazione delle informazioni (quindi il sorting e il paging dei dati), mentre il secondo legge le informazioni dalla base di dati tramite il nostro DataSet (attraverso la proprietà TypeName) per poi fornirli direttamente alla griglia di presentazione.

Esempio di Gridview popolata con ObjectDataSource

<asp:GridView ID="gvCustomers" runat="server" AllowPaging="True" AllowSorting="True" AutoGenerateColumns="False"
      DataKeyNames="CustomerID" DataSourceID="dataset">

  <Columns>
    <asp:BoundField DataField="CustomerID" HeaderText="CustomerID" ReadOnly="True" SortExpression="CustomerID" />
    <asp:BoundField DataField="ContactName" HeaderText="ContactName" SortExpression="ContactName" />
    <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
  </Columns>
</asp:GridView>

<asp:ObjectDataSource ID="dataset" runat="server"
      DeleteMethod="Delete" InsertMethod="Insert"
      SelectMethod="GetData UpdateMethod="Update"
      OldValuesParameterFormatString="original_{0}"
      TypeName="NorthwindTableAdapters.CustomersTableAdapter">
      
  <DeleteParameters><!-- elenco dei parametri di delete --></DeleteParameters>
  <UpdateParameters><!-- elenco dei parametri di update --></UpdateParameters>
  <InsertParameters><!-- elenco dei parametri di insert --></InsertParameters>
</asp:ObjectDataSource>

La medesima operazione di visualizzazione dei dati, che prima abbiamo effettuato tramite il designer di Visual Studio .NET 2005, la possiamo compiere scrivendo il codice per il databind della griglia all'interno del file di code-behind relativo alla nostra pagina.

Come abbiamo detto precedentemente, infatti, il runtime di ASP.NET, in fase di esecuzione, si occupa di trasformare le strutture dati che vede descritte all'interno del nostro dataset in classi .NET che vengono aggiunte al dominio dell'applicazione, in modo tale da darci la possibilità di eseguire operazioni predefinite sulla base di dati, da tutti i punti del nostro sito web, evitando lo sforzo di scrivere ogni volta il codice necessario alla connessione al database e alla lettura o scrittura di dati.

Esempio di codice generato automaticamente

protected void Page_Load(object sender, EventArgs e)
{
  NorthwindTableAdapters.CustomersTableAdapter tableAdapter =
        new NorthwindTableAdapters.CustomersTableAdapter();

  Northwind.CustomersDataTable dataTable = tableAdapter.GetData();

  gvCustomers.DataSource = dataTable;
  gvCustomers.DataBind();
}

Nota: il namespace NorthwindTableAdapters contiene tutti le classi che rappresentano i TableAdapter creati all'interno del dataset. Invece, il namespace Northwind contiene tutte le classi che rappresentano ogni tabella logica contenuta dai vari TableAdapter; avremo quindi una classe per rappresentare la DataTable dei clienti (Nortwind.CustomersDataTable) e una classe per rappresentare una singola riga di tale tabella (Northwind.CustomersRow).

Aggiunta di una query parametrica

A ciascun TableAdapter creato all'interno del nostro DataSet, possiamo aggiungere una o più query. Se ad esempio abbiamo la necessità di selezionare un singolo cliente, oppure di cambiare al volo la città con cui vogliamo filtrare la nostra query di selezione, dobbiamo affidarci alle query parametriche.

Le query parametriche contengono dei parametri all'interno della sintassi SQL, in modo tale che il risultato della selezione dipenda dal valore del parametro passato.
In SQL Server 2005, i parametri si indicano preceduti da una chiocciola (@):

Query parametrica con SQL Server

SELECT Customers.* FROM Customers WHERE Customers.City = @City

Nota: ogni dbms ha la propria sintassi per la descrizione di un parametro. In SQL Server si utilizza la chiocciola (@) seguita dal nome del parametro, mentre in MS Access e MySql si utilizza il punto interrogativo (?) senza alcun nome. In questo caso risulta importante l’ordine con cui vengono specificati i parametri di selezione.

Query parametrica con MS Access (file .mbd)

SELECT Customers.* FROM Customers WHERE Customers.City = ?

In questo modo abbiamo creato una nuova query nel TableAdapter e deciso che questa query può essere eseguita solamente attraverso il passaggio di un parametro. Questo parametro può essere passato in tanti modi, tramite la sessione, tramite un cookie, prelevato dalla querystring oppure dal valore di una proprietà di un altro controllo.

Il wizard per la configurazione del controllo ObjectDataSource che abbiamo visto in precedenza, ci aiuta nella configurazione del parametro.

Figura 3. Impostazione del parametro dal Wizard
Impostazione del parametro dal Wizard

All'interno della pagina, il parametro viene descritto sotto l'elemento <SelectParameters> del controllo ObjectDataSource:

<SelectParameters>
  <asp:ControlParameter
      ControlID="ddlCity" Name="City" PropertyName="SelectedValue" Type="String" />
</SelectParameters>

Inoltre, le classi create dal runtime, di fronte ad una query parametrica, rispondono con la creazione di un metodo che ha come parametri, quelli definiti all'interno della nostra query:

protected void Page_Load(object sender, EventArgs e)
{
  NorthwindTableAdapters.CustomersTableAdapter tableAdapter =
        new NorthwindTableAdapters.CustomersTableAdapter();
  
  Northwind.CustomersDataTable dt = tableAdapter.GetDataByCity("London");

  gvCustomers.DataSource = dt;
  gvCustomers.DataBind();
}

DataSet o Business Objects ?

Il data-layer della nostra applicazione può essere realizzato anche senza il supporto del designer di Visual Studio e l'utilizzo dei DataSet tipizzati. Possiamo scrivere ed utilizzare delle classi, dette classi di Business, create proprio per rappresentare gli oggetti logici presenti all'interno del database e per fornire metodi di lettura e scrittura dei dati al loro interno.

Questa scelta, tra l'utilizzo di DataSet tipizzati e i Business Objects, ha dato luogo a dibattiti molto accesi ancora non conclusi. Inoltre, con l'avvento della tecnica ORM, la discussione si è allargata e sta prendendo più che mai piede.

I DataSet tipizzati hanno dalla loro una grande semplicità di creazione e utilizzo. Forniscono tantissime feature già implementate come il sorting dei dati, i filtri, il paging e la ricerca, caratteristiche che nella realizzazione degli oggetti di business vanno implementate tutte a mano.

I DataSet però, non sono perfetti. Per esempio, con l'utilizzo di strutture di dati molto complicate, e per la gestione di grosse quantità di dati, si ha un calo notevole delle performance, cosa che, attraverso i business objects, è facilmente evitabile utilizzando le collection messe a disposizione dal framework, e facendo una gestione della memoria ad hoc.

Per poter scegliere tra una tecnica e l'altra, è necessaria un'analisi preliminare dell'applicazione molto accurata.

Conclusioni

I DataSet tipizzati sono uno strumento veramente utile, proprio per evitare la scrittura meccanica di codice per l'accesso al database e per la lettura/scrittura dei dati. Inoltre, il designer di Visual Studio .NET 2005, ci permette la gestione di questi oggetti in maniera facile ed intuitiva.

Allo stesso tempo però non bisogna abusarne, in quanto in presenza di basi di dati con strutture molto complicate, contenenti grosse moli di informazioni, si può notare un calo di prestazioni nella nostra applicazione.

Ti consigliamo anche