Aktualisieren von Datenquellen mit 'DataAdapters' (ADO.NET)

Zum Aktualisieren von Datenquellen mit den Änderungen, die an einem DataSet vorgenommen wurden, wird die Update-Methode des DataAdapter aufgerufen. Als Argumente akzeptiert die Update-Methode, genau wie die Fill-Methode, eine Instanz eines DataSet sowie ein optionales DataTable-Objekt oder einen DataTable-Namen. Die DataSet-Instanz ist das DataSet, das die vorgenommenen Änderungen enthält, und der DataTable-Wert gibt die Tabelle an, aus der die Änderungen abgerufen werden sollen. Wenn keine DataTable angegeben ist, wird die erste DataTable im DataSet verwendet.

Wenn die Update-Methode aufgerufen wird, analysiert der DataAdapter die vorgenommenen Änderungen und führt dann den entsprechenden Befehl (INSERT, UPDATE oder DELETE) aus. Wenn der DataAdapter eine Änderung an einer DataRow feststellt, verwendet er zum Verarbeiten der Änderung den InsertCommand, den UpdateCommand oder den DeleteCommand. Dies gibt Ihnen die Gelegenheit, die Leistung der ADO.NET-Anwendung zu optimieren, indem Sie in der Entwurfsphase eine Befehlssyntax festlegen und, sofern möglich, gespeicherte Prozeduren verwenden. Sie müssen die Befehle vor dem Aufrufen von Update explizit festlegen. Wenn Update aufgerufen wird und der entsprechende Befehl für ein bestimmtes Update nicht vorhanden ist (wenn z. B. DeleteCommand für gelöschte Zeilen fehlt), wird eine Ausnahme ausgelöst.

HinweisHinweis

Wenn Sie zum Bearbeiten oder Löschen von Daten mit einem DataAdapter gespeicherte SQL Server-Prozeduren verwenden, müssen Sie sicherstellen, dass in der Definition der gespeicherten Prozedur nicht SET NOCOUNT ON verwendet wird.Anderenfalls ist die zurückgegebene Anzahl der betroffenen Zeilen gleich null (0), was der DataAdapter als Parallelitätskonflikt interpretiert.In diesem Fall wird eine DBConcurrencyException ausgelöst.

Command-Parameter können verwendet werden, um Ein- und Ausgabewerte für eine SQL-Anweisung oder eine gespeicherte Prozedur für jede geänderte Zeile in einem DataSet anzugeben. Weitere Informationen finden Sie unter 'DataAdapter'-Parameter (ADO.NET).

HinweisHinweis

Wichtig ist dabei, zwischen dem Löschen einer Zeile in einer DataTable und dem Entfernen der Zeile zu unterscheiden.Wenn Sie die Remove-Methode oder die RemoveAt-Methode aufrufen, wird die Zeile sofort entfernt.Wenn Sie anschließend die DataTable oder das DataSet an einen DataAdapter übergeben und Update aufrufen, bleiben die entsprechenden Zeilen in der Datenquelle unangetastet.Wenn Sie die Methode Delete verwenden, bleibt die Zeile in der DataTable erhalten, wird aber als zu löschen markiert.Das anschließende Übergeben der DataTable oder des DataSet an einen DataAdapter und das Aufrufen von Update führt dazu, dass die entsprechende Zeile in der Datenquelle gelöscht wird.

Wenn Ihre DataTable einer einzelnen Datenbanktabelle zugeordnet ist oder aus einer einzelnen Datenbanktabelle generiert wurde, können Sie mithilfe des DbCommandBuilder-Objekts automatisch das DeleteCommand-, das InsertCommand- und das UpdateCommand-Objekt für den DataAdapter generieren. Weitere Informationen finden Sie unter Generieren von Befehlen mit 'CommandBuilder'-Objekten (ADO.NET).

Verwenden von "UpdatedRowSource" zum Zuordnen von Werten zu einem "DataSet"

Mit der UpdatedRowSource-Eigenschaft eines DbCommand-Objekts können Sie steuern, wie die von der Datenquelle zurückgegebenen Werte nach einem Aufruf der Update-Methode eines DataAdapter der DataTable erneut zugeordnet werden. Durch Festlegen eines der UpdateRowSource-Enumerationswerte für die UpdatedRowSource-Eigenschaft kann gesteuert werden, ob die von den DataAdapter-Befehlen zurückgegebenen Ausgabeparameter ignoriert oder auf die geänderte Zeile im DataSet angewendet werden. Es kann auch festgelegt werden, ob die erste zurückgegebene Zeile (wenn vorhanden) auf die geänderte Zeile in der DataTable angewendet wird.

In der folgenden Tabelle werden die verschiedenen Werte der UpdateRowSource-Enumeration und deren Auswirkungen auf das Verhalten eines mit einem DataAdapter verwendeten Befehls beschrieben.

"UpdatedRowSource"-Enumeration

Beschreibung

Both

Sowohl die Ausgabeparameter als auch die erste Zeile eines zurückgegebenen Resultsets können der geänderten Zeile im DataSet zugeordnet werden.

FirstReturnedRecord

Nur die Daten in der ersten Zeile eines zurückgegebenen Resultset können der geänderten Zeile im DataSet zugeordnet werden.

None

Alle Ausgabeparameter oder Zeilen eines zurückgegebenen Resultset werden ignoriert.

OutputParameters

Der geänderten Zeile im DataSet können nur Ausgabeparameter zugeordnet werden.

Die Update-Methode aktualisiert die Datenquelle mit den vorgenommenen Änderungen. Die Daten in der Datenquelle können aber seit dem letzten Füllen des DataSet durch andere Clients geändert worden sein. Wenn Sie das DataSet mit den aktuellen Daten aktualisieren möchten, verwenden Sie den DataAdapter und die Fill-Methode. Der Tabelle werden neue Zeilen hinzugefügt, und aktualisierte Informationen werden in die vorhandenen Zeilen eingefügt. Die Fill-Methode überprüft die Primärschlüsselwerte der Zeilen im DataSet und der vom SelectCommand zurückgegebenen Zeilen und bestimmt so, ob eine neue Zeile hinzugefügt oder die bestehende Zeile aktualisiert werden soll. Wenn die Fill-Methode einen Primärschlüsselwert für eine Zeile im DataSet findet, der mit einem Primärschlüsselwert einer Zeile in den vom SelectCommand zurückgegebenen Ergebnissen übereinstimmt, aktualisiert sie die vorhandene Zeile mit den Informationen aus der vom SelectCommand zurückgegebenen Zeile und legt den RowState der vorhandenen Zeile auf Unchanged fest. Wenn der Primärschlüsselwert einer vom SelectCommand zurückgegebenen Zeile keinem der Primärschlüsselwerte der Zeilen im DataSet entspricht, fügt die Fill-Methode eine neue Zeile mit dem RowState Unchanged hinzu.

HinweisHinweis

Wenn der SelectCommand die Ergebnisse eines OUTER JOIN zurückgibt, legt der DataAdapter keinen PrimaryKey-Wert für die resultierende DataTable fest.Sie müssen den PrimaryKey selbst definieren, um sicherzustellen, dass doppelte Zeilen ordnungsgemäß aufgelöst werden.Weitere Informationen finden Sie unter Definieren von Primärschlüsseln (ADO.NET).

Zur Behandlung von Ausnahmen, die beim Aufrufen der Update-Methode auftreten können, können Sie das RowUpdated-Ereignis verwenden, um auf auftretende Fehler beim Aktualisieren von Zeilen zu reagieren (siehe Umgang mit 'DataAdapter'-Ereignissen (ADO.NET)). Sie können aber auch für DataAdapter.ContinueUpdateOnError den Wert true festlegen, bevor Sie Update aufrufen, und auf die in der RowError-Eigenschaft einer bestimmten Zeile gespeicherten Fehlerinformationen reagieren, wenn das Update abgeschlossen ist (siehe Zeilenfehlerinformationen).

Hinweis:   Wenn AcceptChanges für das DataSet, die DataTable oder die DataRow aufgerufen wird, werden alle Original-Werte einer DataRow mit den Current-Werten dieser DataRow überschrieben. Wenn die Feldwerte, mit denen die Zeile als eindeutig identifiziert wird, geändert wurden, stimmen die Original-Werte nicht mehr mit den Werten in der Datenquelle überein, nachdem AcceptChanges aufgerufen wurde. AcceptChanges wird während eines Aufrufs der Update-Methode eines DataAdapter automatisch für jede Zeile aufgerufen. Sie können die Originalwerte während eines Aufrufs der Update-Methode beibehalten, indem Sie zuerst die AcceptChangesDuringUpdate-Eigenschaft des DataAdapter auf false setzen oder indem Sie einen Ereignishandler für das RowUpdated-Ereignis erstellen und den Status auf SkipCurrentRow festlegen. Weitere Informationen dazu finden Sie unter Zusammenführen von 'DataSet'-Inhalten (ADO.NET) und Umgang mit 'DataAdapter'-Ereignissen (ADO.NET).

Beispiel

Die folgenden Beispiele zeigen, wie geänderte Zeilen aktualisiert werden können, indem der UpdateCommand eines DataAdapter-Objekts explizit festgelegt und dessen Update -Methode aufgerufen wird. Beachten Sie, dass der in der WHERE-Klausel der UPDATE-Anweisung festgelegte Parameterwert angibt, dass der Original-Wert der SourceColumn verwendet wird. Dies ist wichtig, weil der Current-Wert möglicherweise geändert wurde und u. U. nicht mehr mit dem Wert in der Datenquelle übereinstimmt. Beim Original-Wert handelt es sich um den Wert, mit dem die DataTable aus der Datenquelle aufgefüllt wurde.

Private Sub AdapterUpdate(ByVal connectionString As String)

    Using connection As SqlConnection = New SqlConnection( _
       connectionString)

        Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
          "SELECT CategoryID, CategoryName FROM dbo.Categories", _
          connection)

        adapter.UpdateCommand = New SqlCommand( _
          "UPDATE Categories SET CategoryName = @CategoryName " & _
           "WHERE CategoryID = @CategoryID", connection)

        adapter.UpdateCommand.Parameters.Add( _
           "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName")

        Dim parameter As SqlParameter = _
           adapter.UpdateCommand.Parameters.Add( _
           "@CategoryID", SqlDbType.Int)
        parameter.SourceColumn = "CategoryID"
        parameter.SourceVersion = DataRowVersion.Original

        Dim categoryTable As New DataTable
        adapter.Fill(categoryTable)

        Dim categoryRow As DataRow = categoryTable.Rows(0)
        categoryRow("CategoryName") = "New Beverages"

        adapter.Update(categoryTable)

        Console.WriteLine("Rows after update.")
        Dim row As DataRow
        For Each row In categoryTable.Rows
            Console.WriteLine("{0}: {1}", row(0), row(1))
        Next
    End Using
End Sub
private static void AdapterUpdate(string connectionString)
{
    using (SqlConnection connection =
               new SqlConnection(connectionString))
    {
        SqlDataAdapter dataAdpater = new SqlDataAdapter(
          "SELECT CategoryID, CategoryName FROM Categories",
          connection);

        dataAdpater.UpdateCommand = new SqlCommand(
           "UPDATE Categories SET CategoryName = @CategoryName " +
           "WHERE CategoryID = @CategoryID", connection);

        dataAdpater.UpdateCommand.Parameters.Add(
           "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName");

        SqlParameter parameter = dataAdpater.UpdateCommand.Parameters.Add(
          "@CategoryID", SqlDbType.Int);
        parameter.SourceColumn = "CategoryID";
        parameter.SourceVersion = DataRowVersion.Original;

        DataTable categoryTable = new DataTable();
        dataAdpater.Fill(categoryTable);

        DataRow categoryRow = categoryTable.Rows[0];
        categoryRow["CategoryName"] = "New Beverages";

        dataAdpater.Update(categoryTable);

        Console.WriteLine("Rows after update.");
        foreach (DataRow row in categoryTable.Rows)
        {
            {
                Console.WriteLine("{0}: {1}", row[0], row[1]);
            }
        }
    }
}

"AutoIncrement"-Spalten

Wenn die Tabellen aus der Datenquelle automatisch inkrementierende Spalten besitzen, können Sie die Spalten im DataSet füllen. Geben Sie dazu die automatisch inkrementierenden Werte als Ausgabeparameter einer gespeicherten Prozedur zurück, und ordnen Sie diesen Parameter einer Spalte in einer Tabelle zu, indem Sie den automatisch inkrementierenden Wert in der ersten Zeile eines von einer gespeicherten Prozedur oder einer SQL-Anweisung zurückgegebenen Resultset zurückgeben oder indem Sie das RowUpdated-Ereignis des DataAdapter verwenden, um eine weitere SELECT-Anweisung auszuführen. Weitere Informationen sowie ein Beispiel finden Sie unter Abrufen von Identitäts- oder AutoWert-Werten (ADO.NET).

Reihenfolge von Einfüge-, Update- und Löschvorgängen

In vielen Fällen ist die Reihenfolge, in der die am DataSet vorgenommenen Änderungen zur Datenquelle gesendet werden, sehr wichtig. Wenn beispielsweise ein Primärschlüsselwert für eine vorhandene Zeile aktualisiert und eine neue Zeile mit dem neuen Primärschlüsselwert als Fremdschlüssel hinzugefügt wurde, muss das Update vor der Einfügung verarbeitet werden.

Mithilfe der Select-Methode der DataTable können Sie ein DataRow-Array zurückgeben, das nur auf Zeilen mit einem bestimmten RowState verweist. Anschließend können Sie das zurückgegebene DataRow-Array an die Update-Methode des DataAdapter übergeben, damit die geänderten Zeilen verarbeitet werden. Wenn Sie eine Teilmenge von Zeilen angeben, die aktualisiert werden sollen, können Sie die Reihenfolge steuern, in der Einfügungen, Updates und Löschvorgänge verarbeitet werden.

Beispiel

Durch den folgenden Code wird beispielsweise sichergestellt, dass die gelöschten Zeilen der Tabelle zuerst verarbeitet werden, anschließend die aktualisierten Zeilen und dann die eingefügten Zeilen.

Dim table As DataTable = dataSet.Tables("Customers")

' First process deletes.
dataSet.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.Deleted))

' Next process updates.
adapter.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.ModifiedCurrent))

' Finally, process inserts.
dataAdpater.Update(table.Select(Nothing, Nothing, _
  DataViewRowState.Added))
DataTable table = dataSet.Tables["Customers"];

// First process deletes.
adapter.Update(table.Select(null, null, DataViewRowState.Deleted));

// Next process updates.
adapter.Update(table.Select(null, null, 
  DataViewRowState.ModifiedCurrent));

// Finally, process inserts.
adapter.Update(table.Select(null, null, DataViewRowState.Added));

Siehe auch

Konzepte

Zeilenstatus und Zeilenversion

'AcceptChanges' und 'RejectChanges'

Zusammenführen von 'DataSet'-Inhalten (ADO.NET)

Abrufen von Identitäts- oder AutoWert-Werten (ADO.NET)

Weitere Ressourcen

DataAdapter und DataReader (ADO.NET)