Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Aplica-se a: .NET Framework
.NET
.NET Standard
O método do Update do DataAdapter é chamado para resolver alterações do DataSet de volta para a fonte de dados. O método Update, tal como o método Fill, toma como argumentos uma instância de DataSet, e um objeto DataTable opcional ou nome DataTable. A DataSet instância é a DataSet que contém as alterações feitas, e o DataTable identifica a tabela de onde recuperar as alterações. Se não for especificado DataTable, o primeiro DataTable em DataSet é usado.
Quando chama o Update método, analisa DataAdapter as alterações feitas e executa o comando apropriado (INSERT, UPDATE ou DELETE). Quando o DataAdapter encontra uma alteração num DataRow, usa o InsertCommand, UpdateCommand, ou DeleteCommand para processar a mudança.
Estas propriedades permitem-lhe maximizar o desempenho da sua aplicação ADO.NET especificando a sintaxe dos comandos no momento do design e, sempre que possível, através do uso de procedimentos armazenados. Deve definir explicitamente os comandos antes de chamar Update. Se Update é chamado e o comando apropriado não existir em uma atualização específica (por exemplo, não existe DeleteCommand para linhas eliminadas), é lançada uma exceção.
Importante
Se estiver a usar procedimentos armazenados no SQL Server para editar ou eliminar dados usando um DataAdapter, certifique-se de que não utiliza SET NOCOUNT ON na definição do procedimento armazenado. Isso faz com que a contagem de linhas afetadas retornada seja zero, o que o DataAdapter interpreta como um conflito de simultaneidade. Neste caso, um DBConcurrencyException será lançado.
Parâmetros de comando podem ser usados para especificar valores de entrada e saída para uma instrução SQL ou procedimento armazenado para cada linha modificada num DataSet. Para mais informações, consulte parâmetros DataAdapter.
Observação
É importante perceber a diferença entre apagar uma linha em a DataTable e removê-la. Quando chama o Remove método ou RemoveAt , a linha é removida imediatamente. Quaisquer linhas correspondentes na fonte de dados do back-end não serão afetadas se depois passar o DataTable ou DataSet para um DataAdapter e chamar Update. Quando usa o Delete método, a linha permanece no DataTable e é marcada para eliminação. Se depois passar o DataTable ou DataSet para um DataAdapter e chamar Update, a linha correspondente na fonte de dados do back end é eliminada.
Se o seu DataTable se mapear para ou for gerado a partir de uma única tabela de base de dados, pode tirar partido do objeto DbCommandBuilder para gerar automaticamente o DeleteCommand, InsertCommand e UpdateCommand objetos para o DataAdapter. Para mais informações, consulte Geração de comandos com CommandBuilders.
Utilize o UpdatedRowSource para mapear valores para um DataSet
Pode controlar como os valores devolvidos pela fonte de dados são mapeados de volta para o DataTable após uma chamada ao método Update de um DataAdapter, utilizando a propriedade UpdatedRowSource de um objeto SqlCommand. Ao definir a UpdatedRowSource propriedade para um dos UpdateRowSource valores de enumeração, pode controlar se os parâmetros de saída devolvidos pelos DataAdapter comandos são ignorados ou aplicados à linha alterada no DataSet. Também pode especificar se a primeira linha devolvida (se existir) é aplicada à linha alterada no DataTable.
A tabela seguinte descreve os diferentes valores da UpdateRowSource enumeração e como estes afetam o comportamento de um comando usado com um DataAdapter.
| Enumeração UpdatedRowSource | Description |
|---|---|
| Both | Tanto os parâmetros de saída como a primeira linha de um conjunto de resultados devolvidos podem ser mapeados para a linha alterada no DataSet. |
| FirstReturnedRecord | Apenas os dados da primeira linha de um conjunto de resultados devolvidos podem ser mapeados para a linha alterada no DataSet. |
| None | Quaisquer parâmetros de saída ou linhas de um conjunto de resultados devolvidos são ignorados. |
| OutputParameters | Apenas os parâmetros de saída podem ser mapeados para a linha alterada no DataSet. |
O Update método resolve as suas alterações de volta à fonte de dados; no entanto, outros clientes podem ter modificado os dados na fonte desde a última vez que preencheu o DataSet. Para atualizar o seu DataSet com dados atuais, utilize o método DataAdapterFill. Novas linhas serão adicionadas à tabela e informações atualizadas serão incorporadas nas linhas existentes.
O método Fill determina se uma nova linha será adicionada ou se uma linha existente será atualizada, examinando os valores da chave primária das linhas em DataSet e nas linhas devolvidas pelo SelectCommand. Se o Fill método encontrar um valor de chave primária para uma linha em que DataSet corresponde a um valor de chave primária de uma linha nos resultados devolvidos pelo SelectCommand, atualiza a linha existente com a informação da linha devolvida por o SelectCommand e define o RowState da linha existente para Unchanged. Se uma linha devolvida pelo SelectCommand tiver um valor de chave primária que não corresponda a nenhum dos valores de chave primária das linhas do DataSet, o método Fill adiciona uma nova linha com um RowState de Unchanged.
Observação
Se o SelectCommand devolver os resultados de um OUTER JOIN, o DataAdapter não definirá PrimaryKey valor para o DataTable resultante. Deve definir o PrimaryKey você mesmo para garantir que as linhas duplicadas sejam resolvidas corretamente.
Para lidar com exceções que possam ocorrer ao chamar o Update método, pode usar o RowUpdated evento para responder a erros de atualização de linha à medida que ocorrem (ver Lidar com eventos DataAdaptador), ou pode definir ContinueUpdateOnError para true antes de chamar Update, e responder à informação de erro armazenada na RowError propriedade de uma determinada linha quando a atualização estiver concluída.
Observação
Chamar AcceptChanges no DataSet, DataTable, ou DataRow fará com que todos os valores de Original para um DataRow sejam sobrescritos pelos valores de Current para o DataRow. Se os valores do campo que identificam a linha como única forem modificados, após chamar AcceptChanges os Original valores deixarão de corresponder aos valores na fonte de dados.
AcceptChanges é chamado automaticamente para cada linha durante uma chamada ao método Update de um DataAdapter. Pode preservar os valores originais durante uma chamada ao método Update definindo primeiro a propriedade AcceptChangesDuringUpdate do DataAdapter para false, ou criando um evento para o gestor de eventos RowUpdated e definindo o Status para SkipCurrentRow. Para mais informações, consulte Eventos do DataAdapter.
Os exemplos seguintes demonstram como realizar atualizações a linhas modificadas definindo explicitamente o UpdateCommand de a DataAdapter e chamando o seu Update método.
Observação
O parâmetro especificado no WHERE clause do UPDATE statement está definido para usar o valor Original do SourceColumn. Isto é importante, porque o Current valor pode ter sido modificado e pode não corresponder ao valor na fonte de dados. O Original valor é o valor que foi usado para preencher o DataTable a partir da fonte de dados.
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]);
}
}
}
}
Colunas AutoIncrement
Se as tabelas da sua fonte de dados tiverem colunas com auto-incremento, pode preencher as colunas do seu DataSet de várias formas: retornando o valor de auto-incremento como parâmetro de saída de um procedimento armazenado e mapeando-o para uma coluna numa tabela, retornando o valor de auto-incremento na primeira linha de um conjunto de resultados devolvido por um procedimento armazenado ou uma instrução SQL, ou usando o evento RowUpdated de DataAdapter para executar uma instrução SELECT adicional. Para mais informações e um exemplo, consulte Recuperar valores de identidade ou autonumeração.
Ordenação das inserções, atualizações e eliminação
Em muitas circunstâncias, a ordem em que as alterações feitas através do DataSet são enviadas para a fonte de dados é importante. Por exemplo, se um valor de chave primária para uma linha existente for atualizado e uma nova linha foi adicionada com o novo valor da chave primária como chave estrangeira, é importante processar a atualização antes da inserção.
Pode usar o método do DataTableSelect para devolver uma matriz DataRow que apenas faz referência a linhas com um determinado RowState. Pode então passar o array devolvido DataRow para o método Update de DataAdapter processar as linhas modificadas. Ao especificar um subconjunto de linhas a atualizar, pode controlar a ordem em que as inserções, atualizações e eliminações são processadas.
Example
Por exemplo, o código seguinte garante que as linhas eliminadas da tabela são processadas primeiro, depois as linhas atualizadas e, por fim, as linhas inseridas.
// 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));
Use um DataAdapter para recuperar e atualizar dados
Podes usar um DataAdapter para recuperar e atualizar os dados.
A amostra usa
DataAdapter.AcceptChangesDuringFillpara clonar os dados na base de dados. Se a propriedade for definida como falsa, AcceptChanges não é chamado ao preencher a tabela, e as linhas recém-adicionadas são tratadas como linhas inseridas. Assim, a amostra usa estas linhas para inserir as novas linhas na base de dados.As amostras usam o
DataAdapter.TableMappingspara definir o mapeamento entre a tabela de origem e o DataTable.O exemplo serve
DataAdapter.FillLoadOptionpara determinar como o adaptador preenche a DataTable a partir do DbDataReader. Quando crias uma DataTable, só podes escrever os dados da base de dados para a versão atual ou original, definindo a propriedade como LoadOption.Upsert ou LoadOption.PreserveChanges.O exemplo também irá atualizar a tabela usando
DbDataAdapter.UpdateBatchSizepara realizar operações em lote.
Antes de compilar e executar a amostra, precisa de criar a base de dados de exemplo:
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"]));
}
}