Comandi generati automaticamente

Nei casi in cui SelectCommand viene specificato in modo dinamico in fase di esecuzione, ad esempio mediante uno strumento per query che accetta un comando testuale dell'utente, potrebbe non essere possibile specificare l'appropriato InsertCommand, UpdateCommand o DeleteCommand in fase di progettazione. Se il DataTable esegue il mapping o viene generato da una singola tabella di database, è possibile utilizzare l'oggetto CommandBuilder per generare automaticamente DeleteCommand, InsertCommand e UpdateCommand di DataAdapter.

Come requisito minimo, è necessario impostare la proprietà SelectCommand affinché la generazione automatica del comando funzioni. Lo schema della tabella recuperato da SelectCommand determina la sintassi delle istruzioni INSERT, UPDATE e DELETE generate automaticamente.

CommandBuilder deve eseguire SelectCommand in modo da restituire i metadati necessari per costruire i comandi di inserimento, aggiornamento ed eliminazione. Di conseguenza, è necessario un ulteriore percorso all'origine dati che può ridurre le prestazioni. Per ottenere prestazioni ottimali, specificare i comandi in modo esplicito anziché utilizzare CommandBuilder.

SelectCommand deve restituire inoltre almeno una chiave primaria o una colonna univoca. In caso contrario, viene generata un'eccezione InvalidOperation e i comandi non vengono creati.

Quando è associato a un DataAdapter, CommandBuilder genera automaticamente le proprietà InsertCommand, UpdateCommand e DeleteCommand di DataAdapter, se queste sono riferimenti null. Se esiste già un Command per una proprietà, viene utilizzato il Command esistente.

Le viste di database create dal join di due o più tabelle non vengono considerate un'unica tabella di database. In questo caso non è possibile utilizzare CommandBuilder per generare automaticamente i comandi ed è necessario specificarli in modo esplicito. Per informazioni sull'impostazione esplicita dei comandi per applicare gli aggiornamenti di un DataSet nell'origine dati, vedere Aggiornamento del database con un oggetto DataAdapter e il DataSet.

È possibile eseguire il mapping dei parametri di output sulla riga aggiornata di un DataSet. Un'attività comune sarebbe il recupero del valore di un campo identità generato automaticamente o del timestamp da un'origine dati. Per impostazione predefinita, CommandBuilder non esegue il mapping dei parametri di output sulle colonne in una riga aggiornata. In questo caso è necessario specificare il comando in modo esplicito. Per un esempio di mapping di un campo identità generato automaticamente su una colonna di una riga inserita, vedere Recupero dei valori di identità o del contatore.

Regole per i comandi generati automaticamente

Nella tabella seguente vengono descritte le regole per generare automaticamente i comandi.

Comando Regola
InsertCommand Consente di inserire una riga nell'origine dati per ogni riga della tabella avente RowState uguale a DataRowState.Added. I valori vengono inseriti in tutte le colonne aggiornabili, quindi non nelle colonne di identità, espressioni o timestamp.
UpdateCommand Consente di aggiornare un riga dell'origine dati per ogni riga della tabella avente RowState uguale a DataRowState.Modified. I valori vengono aggiornati in tutte le colonne aggiornabili, quindi non nelle colonne di identità, espressioni o timestamp. Vengono aggiornate tutte le righe in cui i valori delle colonne nell'origine dati corrispondono ai valori nella colonna della chiave primaria della riga e in cui le colonne restanti nell'origine dati corrispondono ai valori originali della riga. Per ulteriori informazioni, vedere la sezione "Modello di concorrenza ottimistica per aggiornamenti ed eliminazioni" contenuta in questo argomento.
DeleteCommand Consente di eliminare una riga dall'origine dati per ogni riga della tabella avente RowState uguale a DataRowState.Deleted. Vengono eliminate tutte le righe in cui i valori delle colonne corrispondono ai valori delle colonne della chiave primaria della riga e in cui le restanti colonne dell'origine dati corrispondono ai valori originali della riga. Per ulteriori informazioni, vedere la sezione "Modello di concorrenza ottimistica per aggiornamenti ed eliminazioni" contenuta in questo argomento.

Modello di concorrenza ottimistica per aggiornamenti ed eliminazioni

La logica per generare automaticamente i comandi per le istruzioni UPDATE e DELETE si basa sulla concorrenza ottimistica. In altre parole, la modifica dei record non è bloccata e altri utenti o processi possono modificarli in qualsiasi momento. Poiché un record può essere modificato dopo che è stato restituito dall'istruzione SELECT, ma prima che sia eseguita l'istruzione UPDATE o DELETE, nell'istruzione UPDATE o DELETE generata automaticamente è contenuta una clausola WHERE, tale che una riga viene aggiornata solo se contiene tutti i valori originali e non è stata eliminata dall'origine dati. In questo modo si evita di sovrascrivere i nuovi dati. Nei casi in cui un comando Update generato automaticamente tenta di aggiornare una riga che è stata eliminata o che non contiene i valori originali rilevati nel DataSet, il comando non ha alcun effetto sui record e viene generato un DBConcurrencyException.

Se si desidera che le istruzioni UPDATE o DELETE vengano completate a prescindere dai valori originali, è necessario impostare in modo esplicito UpdateCommand per il DataAdapter e non utilizzare la generazione automatica dei comandi.

Limiti della logica per la generazione automatica dei comandi

I limiti che seguono si riferiscono alla generazione automatica dei comandi.

Solo tabelle non correlate

La logica per la generazione automatica dei comandi genera istruzioni INSERT, UPDATE o DELETE per le tabelle autonome senza tenere conto delle relazioni con altre tabelle nell'origine dati. Di conseguenza, è possibile che venga rilevato un errore quando si chiama Update per inviare le modifiche a una colonna che è parte di un vincolo di chiave esterna nel database. Per evitare questa eccezione, non utilizzare CommandBuilder per aggiornare le colonne incluse in un vincolo di chiave esterna e specificare in modo esplicito le istruzioni utilizzate per eseguire l'operazione.

Nomi di tabelle e colonne

La logica per la generazione automatica dei comandi non riesce se i nomi delle colonne o delle tabelle contengono caratteri speciali quali spazi, punti, virgolette o altri caratteri alfanumerici, anche se racchiusi tra parentesi. Sono supportati nomi di tabella completi nel formato catalog.schema.table.

Utilizzo di CommandBuilder per generare automaticamente un'istruzione SQL

Per generare automaticamente le istruzioni SQL per un DataAdapter, impostare in primo luogo la proprietà SelectCommand di DataAdapter. Creare quindi un oggetto CommandBuilder e specificare come argomento il DataAdapter per il quale CommandBuilder genererà automaticamente le istruzioni SQL.

Dim custDA As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers", nwindConn)
Dim custCB As SqlCommandBuilder = New SqlCommandBuilder(custDA)
custCB.QuotePrefix = "["
custCB.QuoteSuffix = "]"

Dim custDS As DataSet = New DataSet

nwindConn.Open()
custDA.Fill(custDS, "Customers")

' Code to modify data in the DataSet here.

' Without the SqlCommandBuilder, this line would fail.
custDA.Update(custDS, "Customers")
nwindConn.Close()
[C#]
SqlDataAdapter custDA = new SqlDataAdapter("SELECT * FROM Customers", nwindConn);
SqlCommandBuilder custCB = new SqlCommandBuilder(custDA);
custCB.QuotePrefix = "[";
custCB.QuoteSuffix = "]";

DataSet custDS = new DataSet();

nwindConn.Open();
custDA.Fill(custDS, "Customers");

// Code to modify data in the DataSet here.

// Without the SqlCommandBuilder, this line would fail.
custDA.Update(custDS, "Customers");
nwindConn.Close();

Modifica di SelectCommand

Se si modifica CommandText di SelectCommand dopo la generazione automatica dei comandi di inserimento, aggiornamento o eliminazione, è possibile che venga generata un'eccezione. Se il SelectCommand.CommandText modificato contiene informazioni sullo schema che non sono coerenti con il SelectCommand.CommandText utilizzato durante la generazione automatica dei comandi di inserimento, aggiornamento o eliminazione, nelle future chiamate al metodo DataAdapter.Update potrebbero essere eseguito un tentativo di accesso a colonne che non esistono più nella tabella corrente a cui SelectCommand fa riferimento e verrà generata un'eccezione.

È possibile aggiornare le informazioni sullo schema utilizzate da CommandBuilder per generare automaticamente i comandi chiamando il metodo RefreshSchema di CommandBuilder.

Se si desidera conoscere il comando che è stato generato automaticamente, è possibile ottenere un riferimento ai comandi generati automaticamente tramite i metodi GetInsertCommand, GetUpdateCommand e GetDeleteCommand dell'oggetto CommandBuilder e selezionare la proprietà CommandText del Command associato.

Nell'esempio di codice seguente viene scritto sulla console il comando di aggiornamento che è stato generato automaticamente.

Console.WriteLine(custCB.GetUpdateCommand().CommandText)

Nell'esempio seguente viene ripreso il codice dell'esempio precedente, riportato nella sezione "Utilizzo di CommandBuilder per generare automaticamente un'istruzione SQL", e viene creata nuovamente la tabella Customers sostituendo la colonna CompanyName con la colonna ContactName. Il metodo RefreshSchema viene chiamato per aggiornare i comandi generati automaticamente con le informazioni sulla nuova colonna.

nwindConn.Open()

custDA.SelectCommand.CommandText = "SELECT CustomerID, ContactName FROM Customers"
custCB.RefreshSchema()

custDS.Tables.Remove(custDS.Tables("Customers"))
custDA.Fill(custDS, "Customers")

' Code to modify the new table in the DataSet here.

' Without the call to RefreshSchema, this line would fail.
custDA.Update(custDS, "Customers")

nwindConn.Close()
[C#]
nwindConn.Open();

custDA.SelectCommand.CommandText = "SELECT CustomerID, ContactName FROM Customers";
custCB.RefreshSchema();

custDS.Tables.Remove(custDS.Tables["Customers"]);
custDA.Fill(custDS, "Customers");

// Code to modify the new table in the DataSet here.

// Without the call to RefreshSchema, this line would fail.
custDA.Update(custDS, "Customers");

nwindConn.Close();

Vedere anche

Utilizzo di provider di dati .NET Framework per accedere ai dati | Classe OleDbDataAdapter | Classe OdbcDataAdapter | Classe SqlDataAdapter