Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Dotyczy: .NET Framework
.NET
Standard
Metoda Update metody jest wywoływana DataAdapter w celu rozwiązania zmian z DataSet powrotem do źródła danych. Metoda Update , podobnie jak Fill metoda, przyjmuje jako argumenty wystąpienie DataSetobiektu i opcjonalną DataTable nazwę lub DataTable obiekt. Wystąpienie DataSet to DataSet , które zawiera wprowadzone zmiany, oraz DataTable identyfikuje tabelę, z której mają zostać pobrane zmiany. Jeśli nie DataTable zostanie określony, zostanie użyty pierwszy DataTable w elemecie DataSet .
Podczas wywoływania Update metody DataAdapter funkcja analizuje wprowadzone zmiany i wykonuje odpowiednie polecenie (INSERT, UPDATE lub DELETE). W przypadku DataAdapter napotkania zmiany na DataRow, używa InsertCommandmetody , UpdateCommandlub DeleteCommand do przetworzenia zmiany.
Te właściwości umożliwiają zmaksymalizowanie wydajności aplikacji ADO.NET przez określenie składni poleceń w czasie projektowania i, tam, gdzie to możliwe, za pomocą procedur składowanych. Przed wywołaniem Updatepolecenia należy jawnie ustawić polecenie . Jeśli Update jest wywoływana i odpowiednie polecenie nie istnieje dla określonej aktualizacji (na przykład nie DeleteCommand dla usuniętych wierszy), zgłaszany jest wyjątek.
Ważne
Jeśli używasz procedur składowanych programu SQL Server do edytowania lub usuwania danych przy użyciu elementu DataAdapter, upewnij się, że nie używasz SET NOCOUNT ON w definicji procedury składowanej. Powoduje to, że liczba wierszy, których dotyczy problem, zwraca wartość zero, co DataAdapter interpretuje jako konflikt współbieżności. W tym przypadku zostanie zgłoszony wyjątek DBConcurrencyException.
Parametry polecenia mogą służyć do określania wartości wejściowych i wyjściowych instrukcji SQL lub procedury składowanej dla każdego zmodyfikowanego wiersza w obiekcie DataSet. Aby uzyskać więcej informacji, zobacz Parametry elementu DataAdapter.
Uwaga / Notatka
Ważne jest, aby zrozumieć różnicę między usunięciem wiersza w obiekcie DataTable a usunięciem wiersza. Po wywołaniu Remove metody or RemoveAt wiersz zostanie natychmiast usunięty. Jeśli następnie przekażesz DataTable element lub do metody DataAdapter i DataSetUpdate, wszystkie odpowiednie wiersze w źródle danych zaplecza nie będą miały wpływu. W przypadku użycia metody wiersz pozostaje w elemecie DeleteDataTable i jest oznaczony do usunięcia. Jeśli następnie przekażesz metodę DataTableDataAdapter lub DataSet do metody i Update, odpowiedni wiersz w źródle danych zaplecza zostanie usunięty.
DataTable Jeśli mapy do lub są generowane na podstawie pojedynczej tabeli bazy danych, możesz skorzystać z DbCommandBuilder obiektu , aby automatycznie wygenerować DeleteCommandobiekty , InsertCommandi UpdateCommand dla obiektu DataAdapter. Aby uzyskać więcej informacji, zobacz Generowanie poleceń za pomocą poleceń CommandBuilders.
Używanie elementu UpdatedRowSource do mapowania wartości na zestaw danych
Możesz kontrolować, jak wartości zwracane ze źródła danych są mapowane z powrotem do DataTable następującego wywołania Update metody DataAdapter, przy użyciu UpdatedRowSource właściwości SqlCommand obiektu. Ustawiając UpdatedRowSource właściwość na jedną z UpdateRowSource wartości wyliczenia, możesz kontrolować, czy parametry wyjściowe zwracane przez DataAdapter polecenia są ignorowane, czy stosowane do zmienionego wiersza w obiekcie DataSet. Można również określić, czy pierwszy zwrócony wiersz (jeśli istnieje) jest stosowany do zmienionego wiersza w pliku DataTable.
W poniższej tabeli opisano różne wartości UpdateRowSource wyliczenia i sposób ich wpływu na zachowanie polecenia używanego z elementem DataAdapter.
| UpdatedRowSource— Wyliczenie | Description |
|---|---|
| Both | Parametry wyjściowe i pierwszy wiersz zwróconego zestawu wyników mogą być mapowane na zmieniony wiersz w pliku DataSet. |
| FirstReturnedRecord | Tylko dane w pierwszym wierszu zwróconego zestawu wyników mogą być mapowane na zmieniony wiersz w pliku DataSet. |
| None | Wszystkie parametry wyjściowe lub wiersze zwróconego zestawu wyników są ignorowane. |
| OutputParameters | Tylko parametry wyjściowe mogą być mapowane na zmieniony wiersz w pliku DataSet. |
Metoda Update usuwa zmiany ze źródłem danych, jednak inni klienci mogli zmodyfikować dane w źródle danych od czasu ostatniego wypełnienia elementu DataSet. Aby odświeżyć dane DataSet przy użyciu bieżących danych, użyj DataAdapter metody i Fill . Nowe wiersze zostaną dodane do tabeli, a zaktualizowane informacje zostaną włączone do istniejących wierszy.
Metoda Fill określa, czy nowy wiersz zostanie dodany, czy istniejący wiersz zostanie zaktualizowany, sprawdzając wartości klucza podstawowego wierszy w DataSet tabeli i wiersze zwrócone przez SelectCommandelement .
Fill Jeśli metoda napotka wartość klucza podstawowego dla wiersza wDataSet, który pasuje do wartości klucza podstawowego z wiersza w wynikach zwróconych przez SelectCommand, aktualizuje istniejący wiersz z informacjami z wiersza zwróconego przez SelectCommand i ustawia RowState istniejący wiersz na Unchangedwartość . Jeśli wiersz zwracany przez SelectCommand element ma wartość klucza podstawowego, która nie jest zgodna z żadnymi wartościami klucza podstawowego wierszy w DataSettabeli , Fill metoda dodaje nowy wiersz z wartością UnchangedRowState .
Uwaga / Notatka
SelectCommand Jeśli funkcja zwraca wyniki sprzężenia ZEWNĘTRZNEgo, DataAdapter parametr nie ustawi PrimaryKey wartości wynikowej DataTable. Należy zdefiniować PrimaryKey samodzielnie, aby upewnić się, że zduplikowane wiersze są prawidłowo rozpoznawane.
Aby obsłużyć wyjątki, które mogą wystąpić podczas wywoływania metody, możesz użyć RowUpdated zdarzenia do reagowania na błędy aktualizacji wierszy w miarę ich występowania (zobacz Handle DataAdapter events) lub można ustawić wartość ContinueUpdateOnError na true przed wywołaniem UpdateUpdatemetody i odpowiedzieć na informacje o błędzie przechowywane we RowError właściwości określonego wiersza po zakończeniu aktualizacji.
Uwaga / Notatka
Wywołanie AcceptChanges metody , DataTableDataSetlub DataRow spowoduje zastąpienie wszystkich Original wartości obiektu DataRow wartościami Current dla elementu DataRow. Jeśli wartości pól identyfikujące wiersz jako unikatowy zostały zmodyfikowane, po wywołaniu AcceptChangesOriginal wartości nie będą już zgodne z wartościami w źródle danych.
AcceptChanges metoda jest wywoływana automatycznie dla każdego wiersza podczas wywołania Update metody DataAdapter. Oryginalne wartości można zachować podczas wywołania metody Update, ustawiając AcceptChangesDuringUpdate najpierw właściwość DataAdapter właściwości na false lub tworząc program obsługi zdarzeń dla RowUpdated zdarzenia i ustawiając Status wartość SkipCurrentRow. Aby uzyskać więcej informacji, zobacz Handle DataAdapter Events (Obsługa zdarzeń dataadapter).
W poniższych przykładach pokazano, jak wykonać aktualizacje zmodyfikowanych wierszy, jawnie ustawiając UpdateCommandDataAdapter metodę i wywołując metodę Update .
Uwaga / Notatka
Parametr określony w obiekcie WHERE clauseUPDATE statement jest ustawiony na użycie Original wartości SourceColumn. Jest to ważne, ponieważ Current wartość mogła zostać zmodyfikowana i może być niezgodna z wartością w źródle danych. Wartość Original to wartość, która została użyta do wypełnienia DataTable elementu ze źródła danych.
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]);
}
}
}
}
Kolumny autoinkrementacji
Jeśli tabele ze źródła danych mają kolumny automatycznego zwiększania, możesz wypełnić kolumny w DataSet elemecie , zwracając wartość automatycznego przyrostu jako parametr wyjściowy procedury składowanej i mapując ją na kolumnę w tabeli, zwracając wartość auto-inkrementacji w pierwszym wierszu zestawu wyników zwróconego przez procedurę składowaną lub instrukcję SQL. lub za pomocą RowUpdated zdarzenia DataAdapter , aby wykonać dodatkową instrukcję SELECT. Aby uzyskać więcej informacji i przykład, zobacz Pobieranie tożsamości lub wartości autonumeruj.
Kolejność wstawiania, aktualizacji i usuwania
W wielu okolicznościach ważna jest kolejność wysyłania zmian wprowadzonych za pośrednictwem DataSet elementu do źródła danych. Jeśli na przykład wartość klucza podstawowego dla istniejącego wiersza zostanie zaktualizowana, a nowy wiersz został dodany przy użyciu nowej wartości klucza podstawowego jako klucza obcego, ważne jest, aby przetworzyć aktualizację przed wstawieniem.
Możesz użyć Select metody , DataTable aby zwrócić tablicę DataRow , która odwołuje się tylko do wierszy z określonym RowStateelementem . Następnie można przekazać zwróconą DataRow tablicę do Update metody DataAdapter , aby przetworzyć zmodyfikowane wiersze. Określając podzestaw wierszy do zaktualizowania, można kontrolować kolejność przetwarzania wstawiania, aktualizacji i usuwania.
Example
Na przykład poniższy kod gwarantuje, że usunięte wiersze tabeli są najpierw przetwarzane, a następnie zaktualizowane wiersze, a następnie wstawione wiersze.
// Assumes that dataSet and adapter are valid objects.
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));
Pobieranie i aktualizowanie danych za pomocą elementu DataAdapter
Aby pobrać i zaktualizować dane, możesz użyć elementu DataAdapter.
W przykładzie użyto
DataAdapter.AcceptChangesDuringFillmetody klonowania danych w bazie danych. Jeśli właściwość jest ustawiona jako false, funkcja AcceptChanges nie jest wywoływana podczas wypełniania tabeli, a nowo dodane wiersze są traktowane jako wstawione wiersze. W tym przykładzie użyto tych wierszy do wstawienia nowych wierszy do bazy danych.Przykłady służą
DataAdapter.TableMappingsdo definiowania mapowania między tabelą źródłową a tabelą DataTable.W przykładzie użyto
DataAdapter.FillLoadOptionmetody określania, w jaki sposób karta wypełnia tabelę DataTable z elementu DbDataReader. Podczas tworzenia tabeli DataTable można zapisywać dane tylko z bazy danych do bieżącej wersji lub oryginalnej wersji, ustawiając właściwość jako LoadOption.Upsert lub LoadOption.PreserveChanges.Przykład zaktualizuje również tabelę przy użyciu polecenia
DbDataAdapter.UpdateBatchSize, aby wykonać operacje wsadowe.
Przed skompilowanie i uruchomieniem przykładowej bazy danych należy utworzyć przykładową bazę danych:
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
using System;
using System.Data;
using System.Data.Common;
using Microsoft.Data.SqlClient;
using System.Linq;
using CSDataAdapterOperations.Properties;
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);
}
}
}
namespace CSDataAdapterOperations.Properties
{
internal sealed partial class Settings : System.Configuration.ApplicationSettingsBase
{
private static readonly Settings defaultInstance =
((Settings)(System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default => defaultInstance;
[System.Configuration.ApplicationScopedSetting()]
[System.Configuration.DefaultSettingValue("Data Source=(local);Initial Catalog=MySchool;Integrated Security=True")]
public string MySchoolConnectionString => ((string)(this["MySchoolConnectionString"]));
}
}
Zobacz także
- Adaptery danych i Czytniki danych
- Pobieranie wartości tożsamości lub autonumeruj
- Microsoft ADO.NET dla programu SQL Server