Dela via


Generera kommandon med CommandBuilders

När egenskapen SelectCommand anges dynamiskt vid körning, till exempel via ett frågeverktyg som tar ett textkommando från användaren, kanske du inte kan ange lämplig InsertCommand, UpdateCommandeller DeleteCommand vid designtillfället. Om dina DataTable kartor till eller genereras från en enskild databastabell kan du dra nytta av DbCommandBuilder objektet för att automatiskt generera DeleteCommand, InsertCommandoch UpdateCommand av DbDataAdapter.

Som minimikrav måste du ange SelectCommand egenskapen för att automatisk kommandogenerering ska fungera. Tabellschemat som hämtas av SelectCommand egenskapen bestämmer syntaxen för de automatiskt genererade INSERT-, UPDATE- och DELETE-uttrycken.

DbCommandBuilder Måste köra SelectCommand för att returnera de metadata som krävs för att konstruera SQL-kommandona INSERT, UPDATE och DELETE. Därför krävs en extra resa till datakällan, vilket kan hindra prestanda. För att uppnå optimal prestanda anger du dina kommandon explicit i stället för att DbCommandBuilderanvända .

SelectCommand Måste också returnera minst en primärnyckel eller unik kolumn. Om inget finns genereras ett InvalidOperation undantag och kommandona genereras inte.

När de är associerade med en DataAdapterDbCommandBuilder genererar InsertCommandautomatiskt egenskaperna DataAdapter , UpdateCommandoch DeleteCommand för om de är null-referenser. Om en Command redan finns för en egenskap används den befintliga Command .

Databasvyer som skapas genom att koppla ihop två eller flera tabeller betraktas inte som en enda databastabell. I det här fallet kan du inte använda DbCommandBuilder för att automatiskt generera kommandon. Du måste uttryckligen ange dina kommandon. Information om hur du uttryckligen anger kommandon för att matcha uppdateringar till en DataSet tillbaka till datakällan finns i Uppdatera datakällor med DataAdapters.

Du kanske vill mappa utdataparametrar tillbaka till den uppdaterade raden i en DataSet. En vanlig uppgift är att hämta värdet för ett automatiskt genererat identitetsfält eller tidsstämpel från datakällan. DbCommandBuilder Kommer inte att mappa utdataparametrar till kolumner i en uppdaterad rad som standard. I det här fallet måste du uttryckligen ange kommandot. Ett exempel på hur du mappar ett automatiskt genererat identitetsfält tillbaka till en kolumn i en infogad rad finns i Hämta identitets- eller räknarevärden.

Regler för automatiskt genererade kommandon

I följande tabell visas reglerna för hur automatiskt genererade kommandon genereras.

Command Regel
InsertCommand Infogar en rad i datakällan för alla rader i tabellen med en RowState av Added. Infogar värden för alla kolumner som kan uppdateras (men inte kolumner som identiteter, uttryck eller tidsstämplar).
UpdateCommand Uppdateringar rader i datakällan för alla rader i tabellen med en RowState av Modified. Uppdateringar värdena för alla kolumner förutom kolumner som inte kan uppdateras, till exempel identiteter eller uttryck. Uppdateringar alla rader där kolumnvärdena i datakällan matchar primärnyckelkolumnvärdena för raden och där de återstående kolumnerna i datakällan matchar radens ursprungliga värden. Mer information finns i Optimistisk samtidighetsmodell för Uppdateringar och borttagningar senare i det här avsnittet.
DeleteCommand Tar bort rader i datakällan för alla rader i tabellen med en RowState av Deleted. Tar bort alla rader där kolumnvärdena matchar primärnyckelkolumnvärdena för raden och där de återstående kolumnerna i datakällan matchar de ursprungliga värdena för raden. Mer information finns i Optimistisk samtidighetsmodell för Uppdateringar och borttagningar senare i det här avsnittet.

Optimistisk samtidighetsmodell för Uppdateringar och borttagningar

Logiken för att generera kommandon automatiskt för UPDATE- och DELETE-instruktioner baseras på optimistisk samtidighet– det vill sa att poster inte är låsta för redigering och kan ändras av andra användare eller processer när som helst. Eftersom en post kunde ha ändrats efter att den returnerats från SELECT-instruktionen, men innan instruktionen UPDATE eller DELETE utfärdas, innehåller den automatiskt genererade UPDATE- eller DELETE-instruktionen en WHERE-sats, som anger att en rad endast uppdateras om den innehåller alla ursprungliga värden och inte har tagits bort från datakällan. Detta görs för att undvika att skriva över nya data. Om en automatiskt genererad uppdatering försöker uppdatera en rad som har tagits bort eller som inte innehåller de ursprungliga värdena som finns i DataSet, påverkar kommandot inte några poster och en DBConcurrencyException genereras.

Om du vill att UPDATE eller DELETE ska slutföras oavsett ursprungliga värden måste du uttryckligen UpdateCommand ange för DataAdapter och inte förlita dig på automatisk kommandogenerering.

Begränsningar för logik för automatisk kommandogenerering

Följande begränsningar gäller för automatisk kommandogenerering.

Endast orelaterade tabeller

Logiken för automatisk kommandogenerering genererar INSERT-, UPDATE- eller DELETE-instruktioner för fristående tabeller utan att ta hänsyn till några relationer till andra tabeller i datakällan. Därför kan det uppstå ett fel när du anropar Update för att skicka ändringar för en kolumn som deltar i en sekundärnyckelbegränsning i databasen. Undvik det här undantaget genom att inte använda DbCommandBuilder för att uppdatera kolumner som ingår i ett villkor för sekundärnyckel. Ange i stället uttryckligen de instruktioner som används för att utföra åtgärden.

Tabell- och kolumnnamn

Logik för automatisk kommandogenerering kan misslyckas om kolumnnamn eller tabellnamn innehåller specialtecken, till exempel blanksteg, punkter, citattecken eller andra icke-numeriska tecken, även om de avgränsas med hakparenteser. Beroende på providern kan inställningen av parametrarna QuotePrefix och QuoteSuffix göra det möjligt för generationslogik att bearbeta blanksteg, men det kan inte undkomma specialtecken. Fullständigt kvalificerade tabellnamn i form av catalog.schema.table stöds.

Använda CommandBuilder för att generera en SQL-instruktion automatiskt

Om du vill generera SQL-uttryck automatiskt för en DataAdapteranger du SelectCommand först egenskapen DataAdapterför och skapar sedan ett CommandBuilder -objekt och anger som ett argument DataAdapter för vilket SQL-uttrycken CommandBuilder automatiskt ska genereras.

' Assumes that connection is a valid SqlConnection object
' inside of a Using block.  
Dim adapter As SqlDataAdapter = New SqlDataAdapter( _  
  "SELECT * FROM dbo.Customers", connection)  
Dim builder As SqlCommandBuilder = New SqlCommandBuilder(adapter)  
builder.QuotePrefix = "["  
builder.QuoteSuffix = "]"  
// Assumes that connection is a valid SqlConnection object  
// inside of a using block.  
SqlDataAdapter adapter = new SqlDataAdapter(  
  "SELECT * FROM dbo.Customers", connection);  
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);  
builder.QuotePrefix = "[";  
builder.QuoteSuffix = "]";  

Ändra SelectCommand

Om du ändrar kommandona CommandText SelectCommand INSERT, UPDATE eller DELETE har genererats automatiskt kan ett undantag inträffa. Om den ändrade SelectCommand.CommandText innehåller schemainformation som är inkonsekvent med den SelectCommand.CommandText som användes när kommandona infoga, uppdatera eller ta bort genererades automatiskt, kan framtida anrop till DataAdapter.Update metoden försöka komma åt kolumner som inte längre finns i den aktuella tabellen som refereras till av SelectCommand, och ett undantag utlöses.

Du kan uppdatera schemainformationen CommandBuilder som används av för att automatiskt generera kommandon genom att anropa RefreshSchema metoden för CommandBuilder.

Om du vill veta vilket kommando som genererades automatiskt kan du hämta en referens till de automatiskt genererade kommandona med hjälp GetInsertCommandGetUpdateCommandav - och GetDeleteCommand -metoderna för CommandBuilder objektet och kontrollera CommandText egenskapen för det associerade kommandot.

I följande kodexempel skrivs uppdateringskommandot som genererades automatiskt till konsolen.

Console.WriteLine(builder.GetUpdateCommand().CommandText)  
Console.WriteLine(builder.GetUpdateCommand().CommandText);

I följande exempel återskapas Customers tabellen i datamängden custDS . Metoden RefreshSchema anropas för att uppdatera automatiskt genererade kommandon med den här nya kolumninformationen.

' Assumes an open SqlConnection and SqlDataAdapter inside of a Using block.  
adapter.SelectCommand.CommandText = _  
  "SELECT CustomerID, ContactName FROM dbo.Customers"  
builder.RefreshSchema()  
  
custDS.Tables.Remove(custDS.Tables("Customers"))  
adapter.Fill(custDS, "Customers")  
// Assumes an open SqlConnection and SqlDataAdapter inside of a using block.  
adapter.SelectCommand.CommandText =
  "SELECT CustomerID, ContactName FROM dbo.Customers";  
builder.RefreshSchema();  
  
custDS.Tables.Remove(custDS.Tables["Customers"]);  
adapter.Fill(custDS, "Customers");  

Se även