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
, UpdateCommand
eller 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
, InsertCommand
och 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 DataAdapter
DbCommandBuilder genererar InsertCommand
automatiskt egenskaperna DataAdapter
, UpdateCommand
och 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 DataAdapter
anger du SelectCommand
först egenskapen DataAdapter
fö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 GetInsertCommand
GetUpdateCommand
av - 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");