Automatisch generierte Befehle
Wenn die SelectCommand-Eigenschaft dynamisch zur Laufzeit angegeben wird, beispielweise durch ein Abfragetool, das einen Textbefehl des Benutzers verwendet, können Sie die entsprechende Eigenschaft InsertCommand, UpdateCommand oder DeleteCommand u. U. nicht zur Entwurfszeit angeben. Wenn die DataTable einer einzelnen Datenbanktabelle zugeordnet ist oder daraus erstellt wurde, können Sie das CommandBuilder-Objekt verwenden, um automatisch DeleteCommand, InsertCommand und UpdateCommand für das DataAdapter-Objekt zu generieren.
Damit Befehle automatisch generiert werden können, muss in jedem Fall die SelectCommand-Eigenschaft festgelegt werden. Das von der SelectCommand-Eigenschaft abgerufene Tabellenschema legt die Syntax der automatisch generierten INSERT-, UPDATE- und DELETE-Anweisungen fest.
Das CommandBuilder-Objekt muss den SelectCommand ausführen, um die Metadaten zurückzugeben, die zum Erstellen der Befehle für das Einfügen, Aktualisieren und Löschen von Zeilen benötigt werden. Dies macht zusätzlichen Zugriff auf die Datenquelle erforderlich, was eine langsamere Leistung zur Folge haben kann. Eine optimale Leistung erzielen Sie, indem Sie die Befehle explizit angeben statt das CommandBuilder-Objekt zu verwenden.
Der SelectCommand muss außerdem mindestens einen Primärschlüssel oder eine eindeutige Spalte zurückgeben. Ist dies nicht der Fall, wird eine InvalidOperation-Ausnahme ausgelöst, und die Befehle können nicht generiert werden.
In Verbindung mit einem DataAdapter generiert das CommandBuilder-Objekt automatisch die Eigenschaften InsertCommand, UpdateCommand und DeleteCommand des DataAdapter-Objekts, wenn sie Nullverweise sind. Wenn bereits ein Command für eine Eigenschaft vorhanden ist, wird der vorhandene Command verwendet.
Datenbankansichten, die durch die Verknüpfung von zwei oder mehr Tabellen entstehen, gelten nicht als eine Datenbanktabelle. In diesem Fall können Sie das CommandBuilder-Objekt nicht zur automatischen Generierung von Befehlen verwenden und müssen die Befehle explizit angeben. Informationen dazu, wie Sie Befehle explizit angeben, um DataSet-Aktualisierungen in die Datenquelle zu übernehmen, finden Sie unter Aktualisieren der Datenbank mit einem DataAdapter und dem DataSet.
Unter Umständen möchten Sie der aktualisierten Zeile eines DataSets wieder Ausgabeparameter zuweisen. Eine allgemeine Aufgabe wäre das Abrufen des Wertes eines automatisch generierten Identitätsfelds oder Timestamps aus der Datenquelle. Den Spalten in einer aktualisierten Zeile werden nicht standardmäßig Ausgabeparameter vom CommandBuilder-Objekt zugeordnet. Für diesen Fall müssen Sie den Befehl explizit angeben. Ein Beispiel für die Zuordnung eines automatisch generierten Identitätsfelds zurück zu einer Spalte einer eingefügten Zeile finden Sie unter Abrufen von Identitäts- oder AutoWert-Werten.
Regeln für automatisch generierte Befehle
In der folgenden Tabelle finden Sie die Regeln für die Erstellung von automatisch generierten Befehlen.
Befehl | Regel |
---|---|
InsertCommand | Fügt in der Datenquelle für alle Zeilen in der Tabelle mit einem RowState von DataRowState.Added eine Zeile ein. Fügt Werte für alle Spalten ein, die aktualisiert werden können (außer Spalten wie Identitäten, Ausdrücke oder Timestamps). |
UpdateCommand | Aktualisiert Zeilen in der Datenquelle für alle Zeilen in der Tabelle mit einem RowState von DataRowState.Modified. Aktualisiert Werte für alle Spalten, außer für Spalten, die nicht aktualisierbar sind, wie Identitäten oder Ausdrücke. Aktualisiert alle Zeilen, wenn die Spaltenwerte in der Datenquelle den Werten der Primärschlüsselspalte der Zeile entsprechen und wenn die verbleibenden Spalten in der Datenquelle den Ausgangswerten der Zeile entsprechen. Weitere Informationen finden Sie im Abschnitt "Vollständiges Parallelitätsmodell für Aktualisierungen und Löschvorgänge" unter diesem Thema. |
DeleteCommand | Löscht die Zeilen in der Datenquelle für alle Zeilen in der Tabelle mit einem RowState von DataRowState.Deleted. Löscht alle Zeilen, wenn die Spaltenwerte den Werten der Primärschlüsselspalte der Zeile entsprechen und wenn die verbleibende Spalten in der Datenquelle den Ausgangswerten der Zeile entsprechen. Weitere Informationen finden Sie im Abschnitt "Vollständiges Parallelitätsmodell für Aktualisierungen und Löschvorgänge" unter diesem Thema. |
Vollständiges Parallelitätsmodell für Aktualisierungen und Löschvorgänge
Die Logik beim automatischen Generieren von Befehlen für UPDATE- und DELETE-Anweisungen basiert auf der vollständigen Parallelität. Das bedeutet, Datensätze sind nicht für die Bearbeitung gesperrt und können jederzeit von anderen Benutzern oder Prozessen geändert werden. Da ein Datensatz u. U. geändert wurde, nachdem er von der SELECT-Anweisung zurückgegeben wurde, aber bevor die UPDATE- oder DELETE-Anweisung ausgegeben wird, enthält die automatisch generierte UPDATE- oder DELETE-Anweisung eine WHERE-Klausel, damit eine Zeile nur aktualisiert wird, wenn sie nur Ausgangswerte enthält und nicht aus der Datenquelle gelöscht wurde. Dadurch wird verhindert, dass neue Daten überschrieben werden. In Fällen, wo ein automatisch generierter Aktualisierungsbefehl versucht, eine Zeile zu aktualisieren, die gelöscht wurde oder keine im DataSet gefundenen Ausgangswerte enthält, hat der Befehl keine Auswirkungen auf Datensätze, und es wird eine DBConcurrencyException ausgelöst.
Wenn die Aktualisierung oder der Löschvorgang unabhängig von den Ausgangswerten durchgeführt werden soll, müssen Sie die UpdateCommand-Eigenschaft explizit für das DataAdapter-Objekt festlegen und auf die automatische Generierung von Befehlen verzichten.
Einschränkungen der Logik der automatischen Generierung von Befehlen
Folgende Einschränkungen gelten für die automatische Generierung von Befehlen.
Nur nichtverknüpfte Tabellen
Die Logik der automatischen Generierung von Befehlen generiert INSERT-, UPDATE- oder DELETE-Anweisungen für eigenständige Tabellen. Beziehungen zu anderen Tabellen in der Datenquelle werden nicht berücksichtigt. Folglich kann ein Fehler auftreten, wenn Sie die Update-Methode aufrufen, um Änderungen für eine Spalte zu übergeben, für die eine Fremdschlüsseleinschränkung in der Datenbank gilt. Diese Ausnahme können Sie vermeiden, indem Sie zum Aktualisieren von Spalten mit Fremdschlüsseleinschränkungen nicht das CommandBuilder-Objekt verwenden, sondern explizit die erforderlichen Anweisungen angeben.
Tabellen- und Spaltennamen
Die Logik der automatischen Generierung von Befehlen versagt, wenn Spalten- oder Tabellennamen Sonderzeichen enthalten, z. B. Leerzeichen, Punkte, Anführungszeichen oder andere nicht alphanumerische Zeichen, auch dann, wenn die Sonderzeichen in Klammern gesetzt werden. Voll gekennzeichnete Tabellennamen im Format catalog.schema.table
werden unterstützt.
Verwenden des CommandBuilder-Objekts zur automatischen Generierung einer SQL-Anweisung
Zur automatischen Generierung von SQL-Anweisungen für ein DataAdapter-Objekt müssen Sie zuerst die SelectCommand-Eigenschaft für das DataAdapter-Objekt festlegen. Erstellen Sie anschließend ein CommandBuilder-Objekt, und geben Sie als Argument das DataAdapter-Objekt an, für das das CommandBuilder-Objekt automatisch SQL-Anweisungen generiert.
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();
Bearbeiten der SelectCommand-Eigenschaft
Wenn Sie den CommandText der SelectCommand-Eigenschaft bearbeiten, nachdem die Befehle zum Einfügen, Aktualisieren oder Löschen automatisch generiert wurden, wird u. U. eine Ausnahme ausgelöst. Wenn der bearbeitete SelectCommand.CommandText Schemainformationen enthält, die nicht mit dem SelectCommand.CommandText übereinstimmen, der beim automatischen Generieren der Befehle zum Einfügen, Aktualisieren oder Löschen verwendet wurde, kann es passieren, dass bei zukünftigen Aufrufen der DataAdapter.Update-Methode versucht wird, auf Spalten zuzugreifen, die nicht mehr in der aktuellen Tabelle vorhanden sind, auf die die SelectCommand-Eigenschaft verweist und dass deshalb eine Ausnahme ausgelöst wird.
Sie können die Schemainformationen aktualisieren, die vom CommandBuilder zum automatischen Generieren von Befehlen verwendet werden, indem Sie die RefreshSchema-Methode des CommandBuilder-Objekts aufrufen.
Wenn Sie wissen möchten, welcher Befehl automatisch generiert wurde, können Sie mit den Methoden GetInsertCommand, GetUpdateCommand und GetDeleteCommand des CommandBuilder-Objekts einen Verweis auf die automatisch generierten Befehle abrufen und die CommandText-Eigenschaft des jeweiligen Commands überprüfen.
Das folgende Codebeispiel schreibt den Aktualisierungsbefehl, der automatisch generiert wurde, in die Konsole.
Console.WriteLine(custCB.GetUpdateCommand().CommandText)
Das folgende Beispiel führt den Code aus dem vorherigen Beispiel (im Abschnitt "Verwenden des CommandBuilder-Objekts zur automatischen Generierung einer SQL-Anweisung") fort und erstellt die Customers-Tabelle neu. Dabei wird die CompanyName-Spalte durch die ContactName-Spalte ersetzt. Die RefreshSchema-Methode wird aufgerufen, um die automatisch generierten Befehle mit diesen neuen Spalteninformationen zu aktualisieren.
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();
Siehe auch
Datenzugriff mit .NET Framework-Datenprovidern | OleDbDataAdapter-Klasse | OdbcDataAdapter-Klasse | SqlDataAdapter-Klasse