Compilazione di un DataSet da un oggetto DataAdapter

DataSet di ADO.NET è una rappresentazione di dati residente in memoria che fornisce un coerente modello di programmazione relazionale indipendente dall'origine dati. DataSet rappresenta un insieme completo di dati incluse tabelle, vincoli e relazioni tra tabelle. Poiché è indipendente dall'origine dati, un DataSet può includere dati locali dell'applicazione nonché dati di più origini dati. L'interazione con le origini dati esistenti è controllata tramite DataAdapter.

In ogni provider di dati .NET Framework fornito con .NET Framework è incluso un oggetto DataAdapter: nel provider di dati .NET Framework per OLE DB è incluso un oggetto OleDbDataAdapter, nel provider di dati .NET Framework per SQL Server è incluso un oggetto SqlDataAdapter e nel provider di dati .NET Framework per ODBC è incluso un oggetto OdbcDataAdapter. L'oggetto DataAdapter viene utilizzato per recuperare i dati da un'origine dati e compilare le tabelle in un DataSet. Questo oggetto applica inoltre le modifiche apportate al DataSet nell'origine dati. L'oggetto DataAdapter utilizza l'oggetto Connection del provider di dati .NET Framework per effettuare la connessione a un'origine dati e gli oggetti Command per recuperare i dati e applicare le modifiche all'origine dati.

La proprietà SelectCommand di DataAdapter è un oggetto Command che recupera i dati da un'origine dati. Le proprietà InsertCommand, UpdateCommand e DeleteCommand di DataAdapter sono oggetti Command che gestiscono gli aggiornamenti ai dati nell'origine dati in base alle modifiche apportate nel DataSet. Queste proprietà sono descritte in modo più approfondito nella sezione Aggiornamento del database con un oggetto DataAdapter e il DataSet.

Il metodo Fill dell'oggetto DataAdapter viene utilizzato per compilare un DataSet con i risultati di SelectCommand di DataAdapter. Fill accetta come argomenti un DataSet da compilare e un oggetto DataTable oppure il nome del DataTable da riempire con le righe restituite da SelectCommand.

Nel metodo Fill viene utilizzato in modo implicito l'oggetto DataReader per restituire i nomi e i tipi delle colonne utilizzate per creare le tabelle nel DataSet, nonché i dati per compilare le righe delle tabelle nel DataSet. Le tabelle e le colonne vengono create solo se non esistono già; in caso contrario nel metodo Fill viene utilizzato lo schema DataSet esistente. I tipi di colonne vengono creati come tipi .NET Framework in base alle tabelle in Mapping di dati del provider di dati .NET sui tipi di dati .NET Framework. Le chiavi primarie non vengono create a meno che non siano già presenti nell'origine dati e che DataAdapter.MissingSchemaAction non sia impostato su MissingSchemaAction.AddWithKey. Se Fill rileva la presenza di una chiave primaria in una tabella, sovrascriverà i dati presenti nel DataSet con quelli prelevati dall'origine dati per quelle righe in cui i valori della colonna della chiave primaria corrispondono a quelli della riga restituita dall'origine dati. Se non vengono individuate chiavi primarie, i dati vengono aggiunti alle tabelle nel DataSet. Il metodo Fill utilizza qualsiasi TableMappings esistente durante la compilazione del DataSet. Per informazioni, vedere Impostazione dei mapping di DataTable e DataColumn.

Nota   Se SelectCommand restituisce i risultati di un OUTER JOIN, il DataAdapter non imposterà un valore PrimaryKey per il DataTable risultante. Per assicurarsi che le righe duplicate vengano risolte correttamente, sarà necessario definire la PrimaryKey autonomamente. Per ulteriori informazioni, vedere Definizione di una chiave primaria per una tabella.

Nell'esempio di codice seguente viene creata un'istanza di DataAdapter che utilizza un oggetto Connection al database Northwind di Microsoft SQL Server e viene compilato un DataTable in un DataSet con l'elenco dei clienti. L'istruzione SQL e gli argomenti Connection passati al costruttore DataAdapter vengono utilizzati per creare la proprietà SelectCommand di DataAdapter.

SqlClient

Dim nwindConn As SqlConnection = New SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind")

Dim selectCMD As SqlCommand = New SqlCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn)
selectCMD.CommandTimeout = 30

Dim custDA As SqlDataAdapter = New SqlDataAdapter
custDA.SelectCommand = selectCMD

nwindConn.Open()

Dim custDS As DataSet = New DataSet
custDA.Fill(custDS, "Customers")

nwindConn.Close()
[C#]
SqlConnection nwindConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");

SqlCommand selectCMD = new SqlCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn);
selectCMD.CommandTimeout = 30;

SqlDataAdapter custDA = new SqlDataAdapter();
custDA.SelectCommand = selectCMD;

nwindConn.Open();

DataSet custDS = new DataSet();
custDA.Fill(custDS, "Customers");

nwindConn.Close();

OleDb

Dim nwindConn As OleDbConnection = New OleDbConnection("Provider=SQLOLEDB;Data Source=localhost;" & _
                                                       "Integrated Security=SSPI;Initial Catalog=northwind")

Dim selectCMD As OleDbCommand = New OleDbCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn)
selectCMD.CommandTimeout = 30

Dim custDA As OleDbDataAdapter = New OleDbDataAdapter
custDA.SelectCommand = selectCMD

Dim custDS As DataSet = New DataSet
custDA.Fill(custDS, "Customers")
[C#]
OleDbConnection nwindConn = new OleDbConnection("Provider=SQLOLEDB;Data Source=localhost;" +
                                                "Integrated Security=SSPI;Initial Catalog=northwind");

OleDbCommand selectCMD = new OleDbCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn);
selectCMD.CommandTimeout = 30;

OleDbDataAdapter custDA = new OleDbDataAdapter();
custDA.SelectCommand = selectCMD;

DataSet custDS = new DataSet();
custDA.Fill(custDS, "Customers");

Odbc

Dim nwindConn As OdbcConnection = New OdbcConnection("Driver={SQL Server};Server=localhost;" & _
                                                     "Trusted_Connection=yes;Database=northwind")

Dim selectCMD As OdbcCommand = New OdbcCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn)
selectCMD.CommandTimeout = 30

Dim custDA As OdbcDataAdapter = New OdbcDataAdapter
custDA.SelectCommand = selectCMD

nwindConn.Open()

Dim custDS As DataSet = New DataSet
custDA.Fill(custDS, "Customers")

nwindConn.Close()
[C#]
OdbcConnection nwindConn = new OdbcConnection("Driver={SQL Server};Server=localhost;" +
                                              "Trusted_Connection=yes;Database=northwind");

OdbcCommand selectCMD = new OdbcCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn);
selectCMD.CommandTimeout = 30;

OdbcDataAdapter custDA = new OdbcDataAdapter();
custDA.SelectCommand = selectCMD;

nwindConn.Open();

DataSet custDS = new DataSet();
custDA.Fill(custDS, "Customers");

nwindConn.Close();

Si noti che nel codice, Connection non viene aperto e chiuso in modo esplicito. Il metodo Fill apre in modo implicito l'oggetto Connection utilizzato da DataAdapter, se rileva che la connessione non è già aperta. Se la connessione viene aperta dal metodo Fill, lo stesso metodo provvederà a chiuderla una volta terminato. Questa procedura consente di semplificare il codice, quando si esegue una singola operazione come Fill o Update. Tuttavia, se si eseguono più operazioni che richiedono una connessione aperta, per migliorare le prestazioni dell'applicazione è possibile chiamare in modo esplicito il metodo Open di Connection, eseguire le operazioni sull'origine dati, quindi chiamare il metodo Close di Connection. È necessario cercare di tenere aperte le connessioni con l'origine dati per un arco di tempo minimo, in modo da liberare le risorse che le altre applicazioni client devono utilizzare.

Gruppi di risultati multipli

Se l'oggetto DataAdapter individua gruppi di risultati multipli, crea più tabelle nel DataSet. Alle tabelle viene assegnato il nome predefinito incrementale TableN, che inizia con "Table" per Table0. Se il nome di una tabella viene passato come argomento al metodo Fill, alle tabelle viene assegnato il nome predefinito incrementale NomeTabellaN, che inizia con "NomeTabella" per NomeTabella0.

Compilazione di un DataSet da più DataAdapter

È possibile utilizzare un numero qualsiasi di DataAdapter insieme al DataSet. Ogni DataAdapter può essere utilizzato per riempire uno o più oggetti DataTable e risolvere gli aggiornamenti nell'origine dati pertinente. Gli oggetti DataRelation e Constraint possono essere aggiunti localmente al DataSet, creando così relazioni tra i dati provenienti da origini dati diverse. Un DataSet, ad esempio, può contenere dati di un database Microsoft SQL Server, un database IBM DB2 esposto tramite OLE DB e un'origine dati che crea un flusso XML. Uno o più oggetti DataAdapter possono gestire le comunicazioni con ciascuna origine dati.

Nell'esempio di codice che segue viene compilato un elenco di clienti dal database Northwind di Microsoft SQL Server 2000 e un elenco di ordini dal database Northwind di Microsoft® Access 2000. Le tabelle compilate vengono collegate con un DataRelation e l'elenco dei clienti viene visualizzato con gli ordini relativi a ciascun cliente. Per ulteriori informazioni sugli oggetti DataRelation, vedere Aggiunta di una relazione tra tabelle e Esplorazione di una relazione tra tabelle.

Dim custConn As SqlConnection= New SqlConnection("Data Source=localhost;Integrated Security=SSPI;" & _
                                                 "Initial Catalog=northwind;")
Dim custDA As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers", custConn)

Dim orderConn As OleDbConnection = New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" & _
                                                       "Data Source=c:\Program Files\Microsoft Office\" & _
                                                       "Office\Samples\northwind.mdb;")
Dim orderDA As OleDbDataAdapter = New OleDbDataAdapter("SELECT * FROM Orders", orderConn)

custConn.Open()
orderConn.Open()

Dim custDS As DataSet = New DataSet()

custDA.Fill(custDS, "Customers")
orderDA.Fill(custDS, "Orders")

custConn.Close()
orderConn.Close()

Dim custOrderRel As DataRelation = custDS.Relations.Add("CustOrders", _
                                     custDS.Tables("Customers").Columns("CustomerID"), _ 
                                     custDS.Tables("Orders").Columns("CustomerID"))

Dim pRow, cRow As DataRow

For Each pRow In custDS.Tables("Customers").Rows
  Console.WriteLine(pRow("CustomerID").ToString())

  For Each cRow In pRow.GetChildRows(custOrderRel)
    Console.WriteLine(vbTab & cRow("OrderID").ToString())
  Next
Next 
[C#]
SqlConnection custConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind;");
SqlDataAdapter custDA = new SqlDataAdapter("SELECT * FROM Customers", custConn);

OleDbConnection orderConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" +
                                                "Data Source=c:\\Program Files\\Microsoft Office\\Office\\Samples\\northwind.mdb;");
OleDbDataAdapter orderDA = new OleDbDataAdapter("SELECT * FROM Orders", orderConn);

custConn.Open();
orderConn.Open();

DataSet custDS = new DataSet();

custDA.Fill(custDS, "Customers");
orderDA.Fill(custDS, "Orders");

custConn.Close();
orderConn.Close();

DataRelation custOrderRel = custDS.Relations.Add("CustOrders",
                              custDS.Tables["Customers"].Columns["CustomerID"],    
                              custDS.Tables["Orders"].Columns["CustomerID"]);

foreach (DataRow pRow in custDS.Tables["Customers"].Rows)
{
  Console.WriteLine(pRow["CustomerID"]);
   foreach (DataRow cRow in pRow.GetChildRows(custOrderRel))
    Console.WriteLine("\t" + cRow["OrderID"]);
}

Tipo decimal di SQL Server

In DataSet i dati vengono memorizzati utilizzando i tipi di dati di .NET Framework. Per la maggior parte delle applicazioni questi tipi consentono di rappresentare in modo adeguato le informazioni delle origini dati. Tuttavia, questo tipo di rappresentazione può provocare un problema quando il tipo di dati nell'origine dati è un decimal di SQL Server. Il tipo di dati decimal di .NET Framework consente un massimo di 28 cifre significative mentre il tipo di dati decimal di SQL Server consente 38 cifre significative. Se, durante un'operazione Fill, SqlDataAdapter determina che la precisione di un campo decimal di SQL Server è superiore a 28 caratteri, la riga corrente non viene aggiunta al DataTable. Viene generato invece un evento FillError che consente di determinare se si è verificata una perdita di precisione e quindi di rispondere in modo appropriato. Per ulteriori informazioni sull'evento FillError, vedere Utilizzo di eventi DataAdapter. Per ottenere il valore decimal di SQL Server, è anche possibile utilizzare un oggetto SqlDataReader e chiamare il metodo GetSqlDecimal.

Capitoli OLE DB

I rowset gerarchici, o capitoli (tipo OLE DB DBTYPE_HCHAPTER, tipo ADO adChapter), possono essere utilizzati per riempire un DataSet. Quando DataAdapter rileva una colonna con capitoli durante un'operazione Fill, viene creato un DataTable per la colonna e la tabella viene riempita con le colonne e le righe del capitolo. Il nome della tabella creata per la colonna con capitoli viene assegnato utilizzando il nome della tabella padre e il nome della colonna con capitoli nel formato "NomeTabellaPadreNomeColonnaCapitolo". Se nel DataSet esiste già una tabella con un nome corrispondente al nome della colonna con capitoli, la tabella corrente viene riempita con i dati del capitolo. Se in una tabella esistente non sono presenti colonne che corrispondono alla colonna rilevata nel capitolo, viene aggiunta una nuova colonna.

Prima che le tabelle nel DataSet siano riempite con i dati delle colonne con capitoli, viene creata una relazione tra le tabelle padre e figlio del rowset gerarchico aggiungendo una colonna di valori integer sia alla tabella padre e che alla tabella figlio, impostando l'incremento automatico della colonna padre e creando un DataRelation con le colonne aggiunte dalle due tabelle. Il nome della relazione aggiunta viene assegnato utilizzando i nomi della tabella padre e della colonna con capitoli nel formato "NomeTabellaPadreNomeColonnaConCapitoli".

Si osservi che la colonna correlata esiste solo nel DataSet. Nelle successive operazioni di inserimento dati da un'origine dati, verranno aggiunte nuove righe alle tabelle anziché aggiornare le righe esistenti in base alle modifiche.

Si osservi inoltre che se si utilizza l'overload DataAdapter.Fill che accetta un DataTable, viene riempita solo quella tabella. Una colonna di valori integer con incremento automatico verrà comunque aggiunta alla tabella, ma non verrà creata o riempita alcuna tabella figlio e non verrà creata alcuna relazione.

Nell'esempio seguente viene utilizzato il provider MSDataShape per generare una colonna di ordini con capitoli per ogni cliente presente nell'elenco di clienti. Un DataSet viene quindi riempito con i dati.

Dim nwindConn As OleDbConnection = New OleDbConnection("Provider=MSDataShape;Data Provider=SQLOLEDB;" & _
                                         "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind")

Dim custDA As OleDbDataAdapter = New OleDbDataAdapter("SHAPE {SELECT CustomerID, CompanyName FROM Customers} " & _
                                      "  APPEND ({SELECT CustomerID, OrderID FROM Orders} AS Orders " & _
                                      "  RELATE CustomerID TO CustomerID)", nwindConn)

Dim custDS As DataSet = New DataSet()

custDA.Fill(custDS, "Customers")
[C#]
OleDbConnection nwindConn = new OleDbConnection("Provider=MSDataShape;Data Provider=SQLOLEDB;" +
                                  "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind");

OleDbDataAdapter custDA = new OleDbDataAdapter("SHAPE {SELECT CustomerID, CompanyName FROM Customers} " +
                                      "  APPEND ({SELECT CustomerID, OrderID FROM Orders} AS Orders " +
                                      "  RELATE CustomerID TO CustomerID)", nwindConn);

DataSet custDS = new DataSet();
custDA.Fill(custDS, "Customers");

Al termine dell'operazione Fill, nel DataSet sono presenti due tabelle: Customers e CustomersOrders, dove CustomersOrders rappresenta la colonna con capitoli. Alla tabella Customers viene aggiunta una colonna denominata Orders e alla tabella CustomersOrders viene aggiunta una colonna denominata CustomersOrders. Nella colonna Orders della tabella Customers viene impostato l'incremento automatico. Viene creata una DataRelation, CustomersOrders, utilizzando le colonne aggiunte alle tabelle con Customers come tabella padre. Nelle tabelle seguenti sono illustrati alcuni risultati di esempio.

TableName: Customers

CustomerID CompanyName Orders
ALFKI Alfreds Futterkiste 0
ANATR Ana Trujillo Emparedados y helados 1

TableName: CustomersOrders

CustomerID OrderID CustomersOrders
ALFKI 10643 0
ALFKI 10692 0
ANATR 10308 1
ANATR 10625 1

Vedere anche

Utilizzo di provider di dati .NET Framework per accedere ai dati | Mapping dei tipi di dati dei provider di dati .NET Framework sui tipi di dati .NET Framework | Classe DataSet | Classe DataTable | Classe OleDbCommand | Classe OleDbConnection | Classe OleDbDataAdapter | Classe OdbcCommand | Classe OdbcConnection | Classe OdbcDataAdapter | Classe SqlCommand | Classe SqlConnection | Classe SqlDataAdapter