Aktualisieren von Datenquellen mit "DataAdapters"Updating Data Sources with DataAdapters

Zum Aktualisieren von Datenquellen mit den Änderungen, die an einem Update vorgenommen wurden, wird die DataAdapter-Methode des DataSet aufgerufen.The Update method of the DataAdapter is called to resolve changes from a DataSet back to the data source. Als Argumente akzeptiert die Update-Methode, genau wie die Fill-Methode, eine Instanz eines DataSet sowie ein optionales DataTable-Objekt oder einen DataTable-Namen.The Update method, like the Fill method, takes as arguments an instance of a DataSet, and an optional DataTable object or DataTable name. 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.The DataSet instance is the DataSet that contains the changes that have been made, and the DataTable identifies the table from which to retrieve the changes. Wenn keine DataTable angegeben ist, wird die erste DataTable im DataSet verwendet.If no DataTable is specified, the first DataTable in the DataSet is used.

Wenn die Update-Methode aufgerufen wird, analysiert der DataAdapter die vorgenommenen Änderungen und führt dann den entsprechenden Befehl (INSERT, UPDATE oder DELETE) aus.When you call the Update method, the DataAdapter analyzes the changes that have been made and executes the appropriate command (INSERT, UPDATE, or DELETE). Wenn der DataAdapter eine Änderung an einer DataRow feststellt, verwendet er zum Verarbeiten der Änderung den InsertCommand, den UpdateCommand oder den DeleteCommand.When the DataAdapter encounters a change to a DataRow, it uses the InsertCommand, UpdateCommand, or DeleteCommand to process the change. 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.This allows you to maximize the performance of your ADO.NET application by specifying command syntax at design time and, where possible, through the use of stored procedures. Sie müssen die Befehle vor dem Aufrufen von Update explizit festlegen.You must explicitly set the commands before calling Update. 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.If Update is called and the appropriate command does not exist for a particular update (for example, no DeleteCommand for deleted rows), an exception is thrown.

Hinweis

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.If you are using SQL Server stored procedures to edit or delete data using a DataAdapter, make sure that you do not use SET NOCOUNT ON in the stored procedure definition. Anderenfalls ist die zurückgegebene Anzahl der betroffenen Zeilen gleich Null (0), was der DataAdapter als Parallelitätskonflikt interpretiert.This causes the rows affected count returned to be zero, which the DataAdapter interprets as a concurrency conflict. In diesem Fall wird eine DBConcurrencyException ausgelöst.In this event, a DBConcurrencyException will be thrown.

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.Command parameters can be used to specify input and output values for an SQL statement or stored procedure for each modified row in a DataSet. Weitere Informationen finden Sie unter DataAdapter-Parameter.For more information, see DataAdapter Parameters.

Hinweis

Wichtig ist dabei, zwischen dem Löschen einer Zeile in einer DataTable und dem Entfernen der Zeile zu unterscheiden.It is important to understand the difference between deleting a row in a DataTable and removing the row. Wenn Sie die Remove-Methode oder die RemoveAt-Methode aufrufen, wird die Zeile sofort entfernt.When you call the Remove or RemoveAt method, the row is removed immediately. Wenn Sie anschließend die DataTable oder das DataSet an einen DataAdapter übergeben und Update aufrufen, bleiben die entsprechenden Zeilen in der Datenquelle unangetastet.Any corresponding rows in the back end data source will not be affected if you then pass the DataTable or DataSet to a DataAdapter and call Update. Wenn Sie die Methode Delete verwenden, bleibt die Zeile in der DataTable erhalten, wird aber als zu löschen markiert.When you use the Delete method, the row remains in the DataTable and is marked for deletion. 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.If you then pass the DataTable or DataSet to a DataAdapter and call Update, the corresponding row in the back end data source is deleted.

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.If your DataTable maps to or is generated from a single database table, you can take advantage of the DbCommandBuilder object to automatically generate the DeleteCommand, InsertCommand, and UpdateCommand objects for the DataAdapter. Weitere Informationen finden Sie unter Erstellen von Befehlen mit CommandBuilder.For more information, see Generating Commands with CommandBuilders.

Verwenden von "UpdatedRowSource" zum Zuordnen von Werten zu einem "DataSet"Using UpdatedRowSource to Map Values to a DataSet

Mit der DataTable-Eigenschaft eines DataAdapter-Objekts können Sie steuern, wie die von der Datenquelle zurückgegebenen Werte nach einem Aufruf der UpdateUpdatedRowSource-Methode eines DbCommand der erneut zugeordnet werden.You can control how the values returned from the data source are mapped back to the DataTable following a call to the Update method of a DataAdapter, by using the UpdatedRowSource property of a DbCommand object. Durch Festlegen eines der UpdatedRowSource-Enumerationswerte für die UpdateRowSource-Eigenschaft kann gesteuert werden, ob die von den DataAdapter-Befehlen zurückgegebenen Ausgabeparameter ignoriert oder auf die geänderte Zeile im DataSet angewendet werden.By setting the UpdatedRowSource property to one of the UpdateRowSource enumeration values, you can control whether output parameters returned by the DataAdapter commands are ignored or applied to the changed row in the DataSet. Es kann auch festgelegt werden, ob die erste zurückgegebene Zeile (wenn vorhanden) auf die geänderte Zeile in der DataTable angewendet wird.You can also specify whether the first returned row (if it exists) is applied to the changed row in the DataTable.

In der folgenden Tabelle werden die verschiedenen Werte der UpdateRowSource-Enumeration und deren Auswirkungen auf das Verhalten eines mit einem DataAdapter verwendeten Befehls beschrieben.The following table describes the different values of the UpdateRowSource enumeration and how they affect the behavior of a command used with a DataAdapter.

"UpdatedRowSource"-EnumerationUpdatedRowSource Enumeration BeschreibungDescription
Both Sowohl die Ausgabeparameter als auch die erste Zeile eines zurückgegebenen Resultset können der geänderten Zeile im DataSet zugeordnet werden.Both the output parameters and the first row of a returned result set may be mapped to the changed row in the DataSet.
FirstReturnedRecord Nur die Daten in der ersten Zeile eines zurückgegebenen Resultset können der geänderten Zeile im DataSet zugeordnet werden.Only the data in the first row of a returned result set may be mapped to the changed row in the DataSet.
None Alle Ausgabeparameter oder Zeilen eines zurückgegebenen Resultset werden ignoriert.Any output parameters or rows of a returned result set are ignored.
OutputParameters Der geänderten Zeile im DataSet können nur Ausgabeparameter zugeordnet werden.Only output parameters may be mapped to the changed row in the DataSet.

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.The Update method resolves your changes back to the data source; however other clients may have modified data at the data source since the last time you filled the DataSet. Wenn Sie das DataSet mit den aktuellen Daten aktualisieren möchten, verwenden Sie den DataAdapter und die Fill-Methode.To refresh your DataSet with current data, use the DataAdapter and Fill method. Der Tabelle werden neue Zeilen hinzugefügt, und aktualisierte Informationen werden in die vorhandenen Zeilen eingefügt.New rows will be added to the table, and updated information will be incorporated into existing rows. 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.The Fill method determines whether a new row will be added or an existing row will be updated by examining the primary key values of the rows in the DataSet and the rows returned by the SelectCommand. 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.If the Fill method encounters a primary key value for a row in the DataSet that matches a primary key value from a row in the results returned by the SelectCommand, it updates the existing row with the information from the row returned by the SelectCommand and sets the RowState of the existing row to Unchanged. 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.If a row returned by the SelectCommand has a primary key value that does not match any of the primary key values of the rows in the DataSet, the Fill method adds a new row with a RowState of Unchanged.

Hinweis

Wenn der SelectCommand die Ergebnisse eines OUTER JOIN zurückgibt, legt der DataAdapter keinen PrimaryKey-Wert für die resultierende DataTable fest.If the SelectCommand returns the results of an OUTER JOIN, the DataAdapter will not set a PrimaryKey value for the resulting DataTable. Sie müssen den PrimaryKey selbst definieren, um sicherzustellen, dass doppelte Zeilen ordnungsgemäß aufgelöst werden.You must define the PrimaryKey yourself to ensure that duplicate rows are resolved correctly. Weitere Informationen finden Sie unter Definieren von primär Schlüsseln.For more information, see Defining Primary Keys.

Um Ausnahmen zu behandeln, die beim Aufrufen der Update -Methode auftreten können, können RowUpdated Sie das-Ereignis verwenden, um auf Fehler beim Aktualisieren von Zeilen zu reagieren (siehe Verarbeiten von DataAdapter- DataAdapter.ContinueUpdateOnError Ereignissen), oder Sie können auf true festlegen. Aufrufen Updatevon und reagieren auf die Fehlerinformationen, die in RowError der-Eigenschaft einer bestimmten Zeile gespeichert sind, wenn das Update beendet ist (siehe Zeilen Fehlerinformationen).To handle exceptions that may occur when calling the Update method, you can use the RowUpdated event to respond to row update errors as they occur (see Handling DataAdapter Events), or you can set DataAdapter.ContinueUpdateOnError to true before calling Update, and respond to the error information stored in the RowError property of a particular row when the update is complete (see Row Error Information).

Hinweis

AcceptChanges DataTable Current DataRowWenn Sie DataRow für ,oderDataRow aufrufen, werden alle Original Werte für ein mit den Werten für die überschrieben. DataSetCalling AcceptChanges on the DataSet, DataTable, or DataRow will cause all Original values for a DataRow to be overwritten with the Current values for the DataRow. Wenn die Feldwerte, mit denen die Zeile als eindeutig identifiziert wird, geändert wurden, stimmen die AcceptChanges-Werte nicht mehr mit den Werten in der Datenquelle überein, nachdem Original aufgerufen wurde.If the field values that identify the row as unique have been modified, after calling AcceptChanges the Original values will no longer match the values in the data source. AcceptChanges wird während eines Aufrufs der Update-Methode eines DataAdapter automatisch für jede Zeile aufgerufen.AcceptChanges is called automatically for each row during a call to the Update method of a DataAdapter. Sie können die Originalwerte während eines Aufrufs der UpdateAcceptChangesDuringUpdate-Methode beibehalten, indem Sie zuerst die DataAdapter-Eigenschaft des RowUpdated auf falseStatus setzen oder indem Sie einen Ereignishandler für das SkipCurrentRow-Ereignis erstellen und den auf festlegen.You can preserve the original values during a call to the Update method by first setting the AcceptChangesDuringUpdate property of the DataAdapter to false, or by creating an event handler for the RowUpdated event and setting the Status to SkipCurrentRow. Weitere Informationen finden Sie unter Zusammenführen von DataSet-Inhalten und Verarbeiten von DataAdapter-Ereignissen.For more information, see Merging DataSet Contents and Handling DataAdapter Events.

BeispielExample

In den folgenden Beispielen wird veranschaulicht, wie Updates für geänderte Zeilen durch explizites Festlegen DataAdapter des von und Update durch Aufrufen der UpdateCommand -Methode durchgeführt werden.The following examples demonstrate how to perform updates to modified rows by explicitly setting the UpdateCommand of a DataAdapter and calling its Update method. Beachten Sie, dass der in der WHERE-Klausel der UPDATE-Anweisung festgelegte Parameterwert angibt, dass der Original-Wert der SourceColumn verwendet wird.Notice that the parameter specified in the WHERE clause of the UPDATE statement is set to use the Original value of the SourceColumn. Dies ist wichtig, weil der Current-Wert möglicherweise geändert wurde und u. U. nicht mehr mit dem Wert in der Datenquelle übereinstimmt.This is important, because the Current value may have been modified and may not match the value in the data source. Beim Original-Wert handelt es sich um den Wert, mit dem die DataTable aus der Datenquelle aufgefüllt wurde.The Original value is the value that was used to populate the DataTable from the data source.

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]);
            }
        }
    }
}
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

"AutoIncrement"-SpaltenAutoIncrement Columns

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.If the tables from your data source have auto-incrementing columns, you can fill the columns in your DataSet either by returning the auto-increment value as an output parameter of a stored procedure and mapping that to a column in a table, by returning the auto-increment value in the first row of a result set returned by a stored procedure or SQL statement, or by using the RowUpdated event of the DataAdapter to execute an additional SELECT statement. Weitere Informationen und ein Beispiel finden Sie unter Abrufen von Identitäts-oderAuto Sequenz Werten.For more information and an example, see Retrieving Identity or Autonumber Values.

Reihenfolge von Einfüge-, Update- und LöschvorgängenOrdering of Inserts, Updates, and Deletes

In vielen Fällen ist die Reihenfolge, in der die am DataSet vorgenommenen Änderungen zur Datenquelle gesendet werden, sehr wichtig.In many circumstances, the order in which changes made through the DataSet are sent to the data source is important. 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.For example, if a primary key value for an existing row is updated, and a new row has been added with the new primary key value as a foreign key, it is important to process the update before the insert.

Mithilfe der Select-Methode der DataTable können Sie ein DataRow-Array zurückgeben, das nur auf Zeilen mit einem bestimmten RowState verweist.You can use the Select method of the DataTable to return a DataRow array that only references rows with a particular RowState. Anschließend können Sie das zurückgegebene DataRow-Array an die Update-Methode des DataAdapter übergeben, damit die geänderten Zeilen verarbeitet werden.You can then pass the returned DataRow array to the Update method of the DataAdapter to process the modified rows. 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.By specifying a subset of rows to be updated, you can control the order in which inserts, updates, and deletes are processed.

BeispielExample

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.For example, the following code ensures that the deleted rows of the table are processed first, then the updated rows, and then the inserted rows.

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.
adapter.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));

Verwenden von "DataAdapter" zum Abrufen und Aktualisieren von DatenUse a DataAdapter to Retrieve and Update Data

Sie können DataAdapter verwenden, um die Daten abzurufen und zu aktualisieren.You can use a DataAdapter to retrieve and update the data.

  • Im Beispiel wird DataAdapter.AcceptChangesDuringFill verwendet, um die Daten in der Datenbank zu klonen.The sample uses DataAdapter.AcceptChangesDuringFill to clone the data in the database. Wenn die Eigenschaft auf False festgelegt ist, wird AcceptChanges beim Auffüllen der Datenbank nicht aufgerufen, und die neu hinzugefügten Zeilen werden als eingefügte Zeilen behandelt.If the property is set as false, AcceptChanges is not called when filling the table, and the newly added rows are treated as inserted rows. Daher werden im Beispiel diese Zeilen zum Einfügen der neuen Zeilen in die Datenbank verwendet.So, the sample uses these rows to insert the new rows into the database.

  • In den Beispielen wird DataAdapter.TableMappings verwendet, um die Zuordnung zwischen der Quelltabelle und der DataTable zu definieren.The samples uses DataAdapter.TableMappings to define the mapping between the source table and DataTable.

  • Im Beispiel wird DataAdapter.FillLoadOption verwendet, um zu bestimmen, wie die DataTable aus DbDataReader vom Adapter aufgefüllt wird.The sample uses DataAdapter.FillLoadOption to determine how the adapter fills the DataTable from the DbDataReader. Beim Erstellen einer DataTable können die Daten aus der Datenbank nur in die aktuelle oder ursprüngliche Version geschrieben werden, wenn die Eigenschaft auf LoadOption.Upsert oder LoadOption.PreserveChanges festgelegt wird.When you create a DataTable, you can only write the data from database to the current version or the original version by setting the property as the LoadOption.Upsert or the LoadOption.PreserveChanges.

  • Im Beispiel wird die Tabelle auch mithilfe von DbDataAdapter.UpdateBatchSize zum Ausführen von Batchvorgängen aktualisiert.The sample will also update the table by using DbDataAdapter.UpdateBatchSize to perform batch operations.

Bevor Sie dieses Beispiel kompilieren und ausführen, müssen Sie die Beispieldatenbank erstellen:Before you compile and run the sample, you need to create the sample database:

USE [master]
GO

CREATE DATABASE [MySchool]

GO

USE [MySchool]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Course]([CourseID] [nvarchar](10) NOT NULL,
[Year] [smallint] NOT NULL,
[Title] [nvarchar](100) NOT NULL,
[Credits] [int] NOT NULL,
[DepartmentID] [int] NOT NULL,
 CONSTRAINT [PK_Course] PRIMARY KEY CLUSTERED
(
[CourseID] ASC,
[Year] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]

GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Department]([DepartmentID] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](50) NOT NULL,
[Budget] [money] NOT NULL,
[StartDate] [datetime] NOT NULL,
[Administrator] [int] NULL,
 CONSTRAINT [PK_Department] PRIMARY KEY CLUSTERED
(
[DepartmentID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]

GO

INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C1045', 2012, N'Calculus', 4, 7)
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C1061', 2012, N'Physics', 4, 1)
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C2021', 2012, N'Composition', 3, 2)
INSERT [dbo].[Course] ([CourseID], [Year], [Title], [Credits], [DepartmentID]) VALUES (N'C2042', 2012, N'Literature', 4, 2)

SET IDENTITY_INSERT [dbo].[Department] ON

INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (1, N'Engineering', 350000.0000, CAST(0x0000999C00000000 AS DateTime), 2)
INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (2, N'English', 120000.0000, CAST(0x0000999C00000000 AS DateTime), 6)
INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (4, N'Economics', 200000.0000, CAST(0x0000999C00000000 AS DateTime), 4)
INSERT [dbo].[Department] ([DepartmentID], [Name], [Budget], [StartDate], [Administrator]) VALUES (7, N'Mathematics', 250024.0000, CAST(0x0000999C00000000 AS DateTime), 3)
SET IDENTITY_INSERT [dbo].[Department] OFF

ALTER TABLE [dbo].[Course]  WITH CHECK ADD  CONSTRAINT [FK_Course_Department] FOREIGN KEY([DepartmentID])
REFERENCES [dbo].[Department] ([DepartmentID])
GO
ALTER TABLE [dbo].[Course] CHECK CONSTRAINT [FK_Course_Department]
GO

C#und Visual Basic Projekte mit diesem Codebeispiel finden Sie unter Codebeispiele für Entwickler.C# and Visual Basic projects with this code sample can be found on Developer Code Samples.

using System;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Linq;
using CSDataAdapterOperations.Properties;

namespace CSDataAdapterOperations.Properties {
   internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {

      private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));

      public static Settings Default {
         get {
            return defaultInstance;
         }
      }

      [global::System.Configuration.ApplicationScopedSettingAttribute()]
      [global::System.Configuration.DefaultSettingValueAttribute("Data Source=(local);Initial Catalog=MySchool;Integrated Security=True")]
      public string MySchoolConnectionString {
         get {
            return ((string)(this["MySchoolConnectionString"]));
         }
      }
   }
}

class Program {
   static void Main(string[] args) {
      Settings settings = new Settings();

      // Copy the data from the database.  Get the table Department and Course from the database.
      String selectString = @"SELECT [DepartmentID],[Name],[Budget],[StartDate],[Administrator]
                                     FROM [MySchool].[dbo].[Department];

                                   SELECT [CourseID],@Year as [Year],Max([Title]) as [Title],
                                   Max([Credits]) as [Credits],Max([DepartmentID]) as [DepartmentID]
                                   FROM [MySchool].[dbo].[Course]
                                   Group by [CourseID]";

      DataSet mySchool = new DataSet();

      SqlCommand selectCommand = new SqlCommand(selectString);
      SqlParameter parameter = selectCommand.Parameters.Add("@Year", SqlDbType.SmallInt, 2);
      parameter.Value = new Random(DateTime.Now.Millisecond).Next(9999);

      // Use DataTableMapping to map the source tables and the destination tables.
      DataTableMapping[] tableMappings = {new DataTableMapping("Table", "Department"), new DataTableMapping("Table1", "Course")};
      CopyData(mySchool, settings.MySchoolConnectionString, selectCommand, tableMappings);

      Console.WriteLine("The following tables are from the database.");
      foreach (DataTable table in mySchool.Tables) {
         Console.WriteLine(table.TableName);
         ShowDataTable(table);
      }

      // Roll back the changes
      DataTable department = mySchool.Tables["Department"];
      DataTable course = mySchool.Tables["Course"];

      department.Rows[0]["Name"] = "New" + department.Rows[0][1];
      course.Rows[0]["Title"] = "New" + course.Rows[0]["Title"];
      course.Rows[0]["Credits"] = 10;

      Console.WriteLine("After we changed the tables:");
      foreach (DataTable table in mySchool.Tables) {
         Console.WriteLine(table.TableName);
         ShowDataTable(table);
      }

      department.RejectChanges();
      Console.WriteLine("After use the RejectChanges method in Department table to roll back the changes:");
      ShowDataTable(department);

      DataColumn[] primaryColumns = { course.Columns["CourseID"] };
      DataColumn[] resetColumns = { course.Columns["Title"] };
      ResetCourse(course, settings.MySchoolConnectionString, primaryColumns, resetColumns);
      Console.WriteLine("After use the ResetCourse method in Course table to roll back the changes:");
      ShowDataTable(course);

      // Batch update the table.
      String insertString = @"Insert into [MySchool].[dbo].[Course]([CourseID],[Year],[Title],
                                   [Credits],[DepartmentID])
             values (@CourseID,@Year,@Title,@Credits,@DepartmentID)";
      SqlCommand insertCommand = new SqlCommand(insertString);
      insertCommand.Parameters.Add("@CourseID", SqlDbType.NVarChar, 10, "CourseID");
      insertCommand.Parameters.Add("@Year", SqlDbType.SmallInt, 2, "Year");
      insertCommand.Parameters.Add("@Title", SqlDbType.NVarChar, 100, "Title");
      insertCommand.Parameters.Add("@Credits", SqlDbType.Int, 4, "Credits");
      insertCommand.Parameters.Add("@DepartmentID", SqlDbType.Int, 4, "DepartmentID");

      const Int32 batchSize = 10;
      BatchInsertUpdate(course, settings.MySchoolConnectionString, insertCommand, batchSize);
   }

   private static void CopyData(DataSet dataSet, String connectionString, SqlCommand selectCommand, DataTableMapping[] tableMappings) {
      using (SqlConnection connection = new SqlConnection(connectionString)) {
         selectCommand.Connection = connection;

         connection.Open();

         using (SqlDataAdapter adapter = new SqlDataAdapter(selectCommand)) {adapter.TableMappings.AddRange(tableMappings);
            // If set the AcceptChangesDuringFill as the false, AcceptChanges will not be called on a
            // DataRow after it is added to the DataTable during any of the Fill operations.
            adapter.AcceptChangesDuringFill = false;

            adapter.Fill(dataSet);
         }
      }
   }

   // Roll back only one column or several columns data of the Course table by call ResetDataTable method.
   private static void ResetCourse(DataTable table, String connectionString,
       DataColumn[] primaryColumns, DataColumn[] resetColumns) {
      table.PrimaryKey = primaryColumns;

      // Build the query string
      String primaryCols = String.Join(",", primaryColumns.Select(col => col.ColumnName));
      String resetCols = String.Join(",", resetColumns.Select(col => $"Max({col.ColumnName}) as {col.ColumnName}"));

      String selectString = $"Select {primaryCols},{resetCols} from Course Group by {primaryCols}");

      SqlCommand selectCommand = new SqlCommand(selectString);

      ResetDataTable(table, connectionString, selectCommand);
   }

   // RejectChanges will roll back all changes made to the table since it was loaded, or the last time AcceptChanges
   // was called. When you copy from the database, you can lose all the data after calling RejectChanges
   // The ResetDataTable method rolls back one or more columns of data.
   private static void ResetDataTable(DataTable table, String connectionString,
       SqlCommand selectCommand) {
      using (SqlConnection connection = new SqlConnection(connectionString)) {
         selectCommand.Connection = connection;

         connection.Open();

         using (SqlDataAdapter adapter = new SqlDataAdapter(selectCommand)) {
            // The incoming values for this row will be written to the current version of each
            // column. The original version of each column's data will not be changed.
            adapter.FillLoadOption = LoadOption.Upsert;

            adapter.Fill(table);
         }
      }
   }

   private static void BatchInsertUpdate(DataTable table, String connectionString,
       SqlCommand insertCommand, Int32 batchSize) {
      using (SqlConnection connection = new SqlConnection(connectionString)) {
         insertCommand.Connection = connection;
         // When setting UpdateBatchSize to a value other than 1, all the commands
         // associated with the SqlDataAdapter have to have their UpdatedRowSource
         // property set to None or OutputParameters. An exception is thrown otherwise.
         insertCommand.UpdatedRowSource = UpdateRowSource.None;

         connection.Open();

         using (SqlDataAdapter adapter = new SqlDataAdapter()) {
            adapter.InsertCommand = insertCommand;
            // Gets or sets the number of rows that are processed in each round-trip to the server.
            // Setting it to 1 disables batch updates, as rows are sent one at a time.
            adapter.UpdateBatchSize = batchSize;

            adapter.Update(table);

            Console.WriteLine("Successfully to update the table.");
         }
      }
   }

   private static void ShowDataTable(DataTable table) {
      foreach (DataColumn col in table.Columns) {
         Console.Write("{0,-14}", col.ColumnName);
      }
      Console.WriteLine("{0,-14}", "RowState");

      foreach (DataRow row in table.Rows) {
         foreach (DataColumn col in table.Columns) {
            if (col.DataType.Equals(typeof(DateTime)))
               Console.Write("{0,-14:d}", row[col]);
            else if (col.DataType.Equals(typeof(Decimal)))
               Console.Write("{0,-14:C}", row[col]);
            else
               Console.Write("{0,-14}", row[col]);
         }
         Console.WriteLine("{0,-14}", row.RowState);
      }
   }
}

Siehe auchSee also