Share via


Cenni preliminari sui dataset in Visual Studio

Aggiornamento: novembre 2007

I dataset sono oggetti che contengono tabelle di dati in cui è possibile memorizzare temporaneamente i dati da utilizzare nell'applicazione. Se l'applicazione prevede che vengano utilizzati dei dati, è possibile caricarli in un dataset. In questo modo viene fornita all'applicazione una cache locale in memoria dei dati da utilizzare. I dati contenuti nel dataset possono essere utilizzati anche se l'applicazione viene disconnessa dal database. Le informazioni relative alle modifiche apportate ai dati del dataset vengono conservate all'interno di quest'ultimo così che, quando l'applicazione verrà riconnessa, gli aggiornamenti potranno essere rilevati e inviati al database.

Nella struttura di un oggetto DataSet, analoga a quella di un database relazionale, viene esposto un modello a oggetti gerarchico costituito da tabelle, righe, colonne, vincoli e relazioni.

I dataset possono essere tipizzati o non tipizzati. Per ulteriori informazioni, vedere più avanti la sezione "Dataset tipizzati e dataset non tipizzati". I primi derivano il relativo schema, ovvero la struttura di tabelle e colonne, dai file xsd e sono più semplici da utilizzare per la programmazione. Nelle applicazioni è possibile utilizzare entrambi i tipi di dataset. In Visual Studio è tuttavia disponibile un supporto degli strumenti più esteso per i dataset tipizzati e la programmazione con questi ultimi risulta semplificata e meno tendente agli errori.

I dataset tipizzati vengono creati eseguendo la Configurazione guidata origine dati oppure aggiungendo un elemento DataSet mediante il comando Aggiungi nuovo elemento del menu Progetto. Per ulteriori informazioni, vedere Procedura: creare un dataset tipizzato.

I dataset non tipizzati vengono creati trascinando degli elementi DataSet dalla Casella degli strumenti in Progettazione Windows Form o in Progettazione componenti.

Dopo aver creato i dataset, è possibile modificarli in Progettazione DataSet.

La creazione e l'utilizzo dei dataset tipizzati e non tipizzati è possibile grazie alle parti degli spazi dei nomi .NET Framework riportate di seguito.

I dataset si trovano nello spazio dei nomi System.Data

Spazio dei nomi del Dataset dei dati di sistema

Gli oggetti di un dataset vengono esposti all'utente mediante costrutti di programmazione standard, quali proprietà e insiemi. Di seguito è riportato un esempio:

Popolamento dei dataset con i dati

Per impostazione predefinita un dataset non contiene dati effettivi. Il riempimento di un dataset consiste in realtà nel caricamento dei dati nei singoli oggetti DataTable che costituiscono il dataset. Le tabelle dati vengono riempite mediante l'esecuzione di query TableAdapter o di comandi dell'adattatore dati, ad esempio SqlDataAdapter. Quando si riempie un dataset con dati, vengono generati diversi eventi, viene applicato il controllo dei vincoli e così via. Per ulteriori informazioni sul caricamento di dati in un dataset, vedere Recupero di dati nell'applicazione.

Il codice che consente di compilare un dataset viene aggiunto automaticamente al gestore eventi di caricamento dei form quando si trascinano elementi dalla Finestra Origini dati in un form dell'applicazione Windows. Per ulteriori informazioni, completare la seguente procedura: Procedura dettagliata: visualizzazione dei dati su un form in un'applicazione Windows.

Esempio di compilazione di un dataset con un oggetto TableAdapter:

Me.CustomersTableAdapter.Fill(Me.NorthwindDataSet.Customers)
this.customersTableAdapter.Fill(this.northwindDataSet.Customers);

Sono disponibili diversi modi per compilare un dataset.

  • Se per la creazione del dataset sono stati utilizzati strumenti in fase di progettazione, quali le procedure guidate di gestione dei dati, chiamare il metodo Fill di un TableAdapter. I TableAdapter vengono creati con un metodo Fill predefinito, di cui è tuttavia possibile modificare il nome, così che il nome effettivo del metodo può essere diverso. Per ulteriori informazioni, vedere la sezione "Riempimento di un dataset mediante un TableAdapter" di Procedura: riempire un dataset.

  • Chiamare il metodo Fill di un DataAdapter. Per ulteriori informazioni, vedere Compilazione di un DataSet da un oggetto DataAdapter (ADO.NET).

  • È possibile inserire manualmente dati nelle tabelle del dataset creando oggetti DataRow e aggiungendoli all'insieme DataRowCollection della tabella. Questa operazione può essere eseguita solo in fase di esecuzione. L'insieme DataRowCollection non può essere infatti impostato in fase di progettazione. Per ulteriori informazioni, vedere Aggiunta di dati a una DataTable.

  • È possibile leggere un documento o un flusso XML nel dataset. Per ulteriori informazioni, vedere il metodo ReadXml. Per un esempio, vedere Procedura dettagliata: lettura dei dati XML in un dataset.

  • È possibile unire (copiare) il contenuto di due dataset. Questo metodo può rivelarsi utile se nell'applicazione vengono recuperati da origini diverse, ad esempio servizi Web diversi, dataset che devono essere consolidati in un unico dataset. Per ulteriori informazioni, vedere Unione del contenuto di un DataSet (ADO.NET).

  • È possibile unire (copiare) il contenuto di due DataTable.

Salvataggio dei dati di un dataset in un database

Le modifiche apportate ai record del dataset devono essere registrate nel database. Per inserire nel database le modifiche apportate al dataset, chiamare il metodo Update del TableAdapter o del DataAdapter con cui è gestita la comunicazione tra il dataset e il database corrispondente.

Quando si utilizzano gli strumenti di progettazione dati in Visual Studio, è possibile inviare i dati a un database chiamando il metodo Update di TableAdapter e passando la tabella di dati che si desidera salvare. Esempio:

CustomersTableAdapter.Update(NorthwindDataSet.Customers)
customersTableAdapter.Update(northwindDataSet.Customers);

Per un maggiore controllo sul processo di aggiornamento, chiamare uno dei metodi DBDirect di TableAdapter che consente di passare valori specifici per ogni riga di dati. Per ulteriori informazioni, vedere Procedura: aggiornare i dati mediante un TableAdapter e Procedura dettagliata: salvataggio di dati con i metodi DBDirect di TableAdapter.

La classe DataRow utilizzata per modificare i singoli record comprende la proprietà RowState, i cui valori indicano se la riga è stata modificata dopo il primo caricamento della tabella dati dal database e il tipo di modifiche apportate. I valori possibili sono Deleted, Modified, Added e Unchanged. I metodi Update del TableAdapter e del DataAdapter esaminano il valore della proprietà RowState per determinare i record da inserire nel database e il comando di database specifico (InsertCommand, UpdateCommand e DeleteCommand) da richiamare.

Per ulteriori informazioni sull'aggiornamento dei dati, vedere Salvataggio di dati.

Spostamento tra i record dei dataset

Dal momento che si tratta di contenitori di dati completamente disconnessi, i dataset non supportano il concetto di record corrente, a differenza dei recordset ADO. Tutti i record presenti nel dataset sono invece disponibili in qualsiasi momento.

In assenza di un record corrente, non esistono proprietà specifiche che puntano a un record corrente, né metodi o proprietà per lo spostamento tra record (vedere la nota riportata di seguito). È possibile accedere a singole tabelle nel dataset come oggetti. Ogni tabella espone infatti un insieme di righe. Il trattamento è analogo a quello riservato a qualsiasi altro insieme, ovvero è possibile accedere alle righe tramite l'indice dell'insieme o utilizzando istruzioni specifiche dell'insieme nel linguaggio di programmazione in uso.

È, ad esempio, possibile ottenere la quarta riga della tabella Customers con il seguente codice:

TextBox1.Text = NorthwindDataSet.Customers(3).ContactName
textBox1.Text = northwindDataSet.Customers[3].ContactName;
Nota:

Per l'associazione dei controlli di un form a un dataset, è possibile utilizzare il componente BindingNavigator per semplificare l'accesso ai singoli record. Per ulteriori informazioni, vedere Procedura: esplorare dati in Windows Form.

Da LINQ a DataSet

LINQ to DataSet attiva LINQ (Language-Integrated Query) su dati in un oggetto DataSet. Per ulteriori informazioni, vedere LINQ to DataSet.

Dataset e linguaggio XML

Per dataset si intende una visualizzazione relazionale di dati che può essere rappresentata in linguaggio XML. Questa relazione tra i dataset e XML consente di usufruire delle funzionalità dei dataset riportate di seguito.

  • La struttura di un dataset, incluse tabelle, colonne, relazioni e vincoli, può essere definita in uno schema XML. Con i dataset è possibile leggere e scrivere schemi contenenti informazioni strutturate mediante i metodi ReadXmlSchema e WriteXmlSchema. Se non è disponibile alcuno schema, il dataset è in grado di ricavarne uno tramite il metodo InferXmlSchema, utilizzando i dati contenuti in un documento XML con struttura relazionale. Per ulteriori informazioni sugli schemi XML, vedere Generazione di schemi XML.

  • È possibile generare una classe di dataset in cui siano incorporate le informazioni sullo schema necessarie per definirne la struttura dei dati. Tale classe viene definita dataset tipizzato. Per informazioni sulla creazione di un dataset tipizzato, vedere Procedura: creare un dataset tipizzato.

  • È possibile leggere un flusso o documento XML in un dataset e scrivere quest'ultimo come XML rispettivamente utilizzando il metodo ReadXml e WriteXml del dataset stesso. Dal momento che XML è un formato standard di interscambio dei dati tra applicazioni diverse, è possibile caricare un dataset con informazioni in formato XML inviate da altre applicazioni. Allo stesso modo, i dati di un dataset possono essere convertiti in un flusso o in un documento XML per la condivisione con altre applicazioni o semplicemente per l'archiviazione in un formato standard.

  • È possibile creare una visualizzazione XML (un oggetto XmlDataDocument) del contenuto di un dataset o di una tabella dati, quindi visualizzare e modificare i dati utilizzando metodi relazionali, mediante il dataset, o metodi XML. In caso di modifica, le due visualizzazioni vengono sincronizzate automaticamente.

Dataset tipizzati e dataset non tipizzati

Per dataset tipizzato si intende un dataset derivato inizialmente da una classe DataSet base, al quale vengono aggiunte successivamente le informazioni di Progettazione DataSet, contenute in un file XSD, per generare una nuova classe DataSet fortemente tipizzata. Le informazioni dello schema (tabelle, colonne e così via) vengono generate e compilate in questa nuova classe Dataset come un insieme di proprietà e oggetti di prima classe. Dal momento che un dataset tipizzato eredita dalla classe DataSet base, la classe tipizzata ne assume tutte le funzionalità e può essere utilizzata con i metodi che accettano come parametro un'istanza della classe DataSet.

Al contrario, un dataset non tipizzato non è dotato di uno schema incorporato corrispondente. Così come i dataset tipizzati, i dataset non tipizzati contengono tabelle, colonne e così via, che tuttavia vengono esposti solo come insiemi. Dopo aver creato manualmente le tabelle e altri elementi di dati in un dataset non tipizzato, è tuttavia possibile esportarne la struttura come schema mediante il relativo metodo WriteXmlSchema.

Accesso ai dati nei dataset tipizzati e non tipizzati

La classe di un dataset tipizzato presenta un modello a oggetti nel quale le relative proprietà hanno il nome delle tabelle e delle colonne. Se si utilizza un dataset tipizzato, ad esempio, è possibile fare riferimento a una colonna utilizzando il seguente codice:

' This accesses the CustomerID column in the first row of the Customers table.
Dim customerIDValue As String = NorthwindDataSet.Customers(0).CustomerID
// This accesses the CustomerID column in the first row of the Customers table.
string customerIDValue = northwindDataSet.Customers[0].CustomerID;

Al contrario, se si utilizza un dataset non tipizzato, il codice equivalente sarà il seguente:

Dim customerIDValue As String = _
    CType(dataset1.Tables("Customers").Rows(0).Item("CustomerID"), String)
string customerIDValue = (string)
    dataset1.Tables["Customers"].Rows[0]["CustomerID"];

Oltre a offrire una maggiore semplicità di lettura, l'accesso tipizzato è completamente supportato da IntelliSense nell'editor di codice di Visual Studio. In aggiunta a una maggiore facilità di utilizzo, la sintassi per i dataset tipizzati consente il controllo dei tipi in fase di compilazione, riducendo significativamente la possibilità di errori nell'assegnazione dei valori ai membri del dataset. Se si modifica il nome di una colonna nel DataSet e si procede alla compilazione dell'applicazione, viene visualizzato un errore di compilazione. Facendo doppio clic su tale errore nell'Elenco attività, è possibile passare direttamente alla riga o alle righe di codice che fanno riferimento al nome di colonna precedente. In un dataset tipizzato l'accesso alle tabelle e alle colonne si rivela, inoltre, leggermente più veloce in fase di esecuzione, in quanto viene determinato in fase di compilazione anziché in fase di esecuzione, tramite insiemi.

Sebbene siano numerosi i vantaggi offerti dai dataset, i dataset non tipizzati possono rivelarsi utili in numerose circostanze. L'esempio più evidente è rappresentato dal caso in cui non sia disponibile uno schema per il dataset. Questo può verificarsi se l'applicazione interagisce con un componente da cui viene restituito un dataset del quale non si conosce in anticipo la struttura. Analogamente, se si utilizzano dati che non sono caratterizzati da una struttura statica prevedibile, non è opportuno utilizzare un dataset tipizzato, in quanto sarebbe necessario rigenerare la classe Dataset tipizzata per ogni modifica apportata alla struttura dei dati.

Più in generale, esistono numerosi casi in cui può essere creato un dataset in modo dinamico, in assenza di uno schema. In tal caso, il dataset è solo una struttura utile in cui memorizzare le informazioni, a condizione che sia possibile una rappresentazione relazionale dei dati. Allo stesso tempo, è possibile usufruire delle funzionalità offerte dal dataset, quali la possibilità di serializzare le informazioni da passare a un altro processo oppure di scrivere un file XML.

Distinzione tra maiuscole e minuscole nei dataset

Per impostazione predefinita, i nomi delle colonne e delle tabelle di un dataset non presentano alcuna distinzione tra maiuscole e minuscole. In altre parole, è anche possibile utilizzare "customers" per fare riferimento a una tabella di un dataset denominata "Customers". In questo caso vengono rispettate le convenzioni di denominazione di numerosi database, incluso il comportamento predefinito di SQL Server, in cui non è possibile distinguere i nomi degli elementi di dati solo in base alla combinazione di maiuscole/minuscole.

Nota:

A differenza dei dataset, per i documenti XML e di conseguenza per i nomi degli elementi di dati definiti negli schemi viene fatta distinzione tra maiuscole e minuscole. A seconda del protocollo, lo schema può definire una tabella denominata "Customers" e un'altra tabella denominata "customers". Ciò può determinare conflitti di nome quando per generare una classe di dataset si utilizza uno schema che contiene elementi che si distinguono solo per la combinazione maiuscole/minuscole.

La distinzione tra maiuscole e minuscole, tuttavia, può influire sull'interpretazione dei dati all'interno del dataset. Se, ad esempio, si filtrano i dati in una tabella del dataset, i criteri di ricerca possono restituire risultati diversi a seconda che il confronto venga effettuato con o senza distinzione tra maiuscole o minuscole. Per controllare la distinzione tra maiuscole e minuscole nelle operazioni di filtro, ricerca e ordinamento è possibile impostare la proprietà CaseSensitive del dataset. Per impostazione predefinita, il valore di questa proprietà viene ereditato da tutte le tabelle del dataset. Per eseguire l'override di questa proprietà per ogni tabella è possibile impostare la relativa proprietà CaseSensitive.

Tabelle correlate e oggetti DataRelation

Se in un dataset sono presenti più tabelle, le relative informazioni possono essere correlate. Per un dataset il riconoscimento di tali relazioni non è implicito. Per gestire i dati contenuti in tabelle correlate è quindi possibile creare oggetti DataRelation in cui siano descritte le relazioni tra le tabelle del dataset. Per ulteriori informazioni, vedere Procedura: accedere ai record di DataTable correlate. Gli oggetti DataRelation possono essere utilizzati per recuperare a livello di codice i record figlio di un record padre e un record padre da un record figlio. Per ulteriori informazioni, vedere Relazioni nei dataset. Se il database contiene relazioni tra due o più tabelle, gli oggetti DataRelation verranno creati automaticamente dagli strumenti di progettazione.

Si immagini l'esempio dei dati sul cliente (customer) e l'ordine (order) come quelli contenuti nel database Northwind. La tabella Customers potrebbe contenere record simili al seguente:

CustomerID   CompanyName               City
ALFKI        Alfreds Futterkiste       Berlin
ANTON        Antonio Moreno Taquerias  Mexico D.F.
AROUT        Around the Horn           London

Il dataset può, inoltre, comprendere un'altra tabella con le informazioni relative agli ordini. La tabella Orders contiene un ID cliente come colonna di chiave esterna. Selezionando solo alcune colonne della tabella Orders è possibile ottenere quanto segue:

OrderId    CustomerID    OrderDate
10692      ALFKI         10/03/1997
10702      ALFKI         10/13/1997
10365      ANTON         11/27/1996
10507      ANTON         4/15/1997

Dal momento che a un cliente possono corrispondere più ordini, tra clienti e ordini esiste una relazione uno-a-molti. Nella tabella sopra riportata, ad esempio, al cliente ALFKI sono associati due ordini.

L'oggetto DataRelation consente di ottenere record correlati da una tabella padre o da una tabella figlio. Se, ad esempio, si utilizza il record relativo al cliente ANTON, è possibile ottenere l'insieme dei record contenenti le descrizioni degli ordini di tale cliente. Per ulteriori informazioni, vedere GetChildRows. Analogamente, quando si utilizza il record che descrive l'ID ordine 10507, è possibile spostarsi verso l'alto nell'oggetto relazione per ottenere il record relativo all'elemento padre associato, ANTON. Per ulteriori informazioni, vedere GetParentRow.

Vincoli

Così come nella maggior parte dei database, nei dataset sono supportati dei vincoli per garantire l'integrità dei dati. I vincoli sono regole che vengono applicate quando si inseriscono, aggiornano o eliminano righe in una tabella. È possibile definire due tipi di vincoli:

  • Vincoli UNIQUE che consentono di verificare l'univocità dei nuovi valori di una colonna all'interno della tabella.

  • Vincoli foreign-key con cui vengono definite le regole per l'aggiornamento dei record figlio correlati quando viene aggiornato o eliminato un record di una tabella principale. Un vincolo foreign-key verifica, ad esempio, la presenza di un record padre prima di consentire la creazione di eventuali record figlio.

In un dataset i vincoli possono essere associati a singole tabelle (vincoli della chiave esterna) oppure a singole colonne (vincoli univoci che garantiscono l'univocità dei valori della colonna). I vincoli vengono implementati come oggetti di tipo UniqueConstraint o ForeignKeyConstraint. Vengono quindi aggiunti all'insieme Constraints di una DataTable. Un metodo alternativo per specificare un vincolo UNIQUE consiste nell'impostare la proprietà Unique di una DataColumn su true.

Il dataset stesso supporta una proprietà booleana EnforceConstraints che consente di specificare se i vincoli verranno attivati. Per impostazione predefinita, questa proprietà è impostata su true. Talvolta però risulta più utile disattivare temporaneamente i vincoli, soprattutto nei casi in cui si modifica un record in modo da causare temporaneamente uno stato non valido. Al termine della modifica viene ripristinato uno stato valido ed è, quindi, possibile riattivare i vincoli.

In Visual Studio i vincoli vengono creati implicitamente quando viene definito un dataset. Aggiungendo una chiave primaria a un dataset, viene infatti implicitamente creato un vincolo univoco per la colonna di chiave primaria. È, inoltre, possibile specificare vincoli UNIQUE per le altre colonne impostando la relativa proprietà Unique su true.

I vincoli foreign-key vengono definiti creando un oggetto DataRelation nel dataset. Oltre a consentire di ottenere informazioni sui record correlati a livello di codice, un oggetto DataRelation permette di definire regole di vincolo foreign-key.

Proprietà estese del dataset

Le proprietà estese forniscono i mapping dei nomi quando si verificano conflitti di denominazione durante il processo di generazione del dataset da un file XSD. Quando un identificatore contenuto nel file XSD è diverso dal nome calcolato creato dal generatore del dataset, viene aggiunta una proprietà estesa al dataset nello spazio dei nomi msprop. Nella tabella seguente sono riportate le proprietà estese che possono essere generate.

Oggetto

Proprietà estesa

DataSet

msprop:Generator_UserDSName

msprop:Generator_DataSetName

DataTable

msprop:Generator_UserTableName

msprop:Generator_TablePropName

msprop:Generator_TableVarName

msprop:Generator_TableClassName

msprop:Generator_RowClassName

msprop:Generator_RowEvHandlerName

msprop:Generator_RowEvArgName

DataColumn

msprop:Generator_UserColumnName

msprop:Generator_ColumnPropNameInTable

msprop:Generator_ColumnVarNameInTable

msprop:Generator_ColumnPropNameInRow

Vedere anche

Altre risorse

Preparazione dell'applicazione al ricevimento di dati

Guida introduttiva all'accesso ai dati

Connessione ai dati in Visual Studio

Recupero di dati nell'applicazione

Visualizzazione di dati su form nelle applicazioni Windows

Modifica di dati nell'applicazione

Convalida dei dati

Salvataggio di dati