Gerar comandos com CommandBuilders
Aplicável a: .NET Framework .NET .NET Standard
Quando a propriedade SelectCommand
do objeto DbDataAdapter é especificada dinamicamente em tempo de execução, como por meio de uma ferramenta de consulta que recebe um comando textual do usuário, pode não ser possível especificar o InsertCommand
, UpdateCommand
ou DeleteCommand
apropriado no tempo de design. Se seu DataTable mapear para ou for gerado a partir de uma única tabela do banco de dados, você poderá aproveitar o objeto DbCommandBuilder para gerar automaticamente o DeleteCommand
, InsertCommand
e UpdateCommand
do DbDataAdapter.
Observação
No Provedor de Dados do Microsoft SqlClient para SQL Server, a classe SqlDataAdapter é derivada da classe DbDataAdapter, e a classe SqlCommandBuilder é derivada da DbCommandBuilder.
Como um requisito mínimo, você deverá definir a propriedade SelectCommand
para que a geração automática de comando funcione. O esquema da tabela recuperado pela propriedade SelectCommand
determina a sintaxe das instruções INSERT, UPDATE e DELETE geradas automaticamente.
O DbCommandBuilder deve executar o SelectCommand
na ordem para retornar os metadados necessários para construir os comandos SQL INSERT, UPDATE e DELETE. Como resultado, uma viagem extra à fonte de dados é necessária e isso pode comprometer o desempenho. Para obter o desempenho ideal, especifique seus comandos explicitamente em vez de usar o DbCommandBuilder.
Observação
O SelectCommand
também deve retornar pelo menos uma chave primária ou coluna exclusivo. Se nenhuma delas estiver presente, uma exceção InvalidOperation
será gerada, e os comandos não serão gerados.
Quando estiver associado com um DataAdapter
, o DbCommandBuilder gera automaticamente as propriedades InsertCommand
, UpdateCommand
e DeleteCommand
do DataAdapter
se forem referências nulas. Se um Command
já existir para uma propriedade, o Command
existente será usado.
As exibições de banco de dados que são criadas juntando duas ou mais tabelas não são consideradas uma única tabela de banco de dados. Nessa instância, não é possível usar o DbCommandBuilder para gerar comandos automaticamente. Você deve especificar os comandos de forma explícita. Para obter informações sobre como definir comandos explicitamente para resolver atualizações para um DataSet
de volta para a fonte de dados, confira Atualizar fontes de dados com DataAdapters.
Você pode desejar mapear parâmetros de saída de volta para a linha atualizada de um DataSet
. Uma tarefa comum é recuperar o valor de um campo de identidade ou um carimbo de data/hora gerado automaticamente da fonte de dados. O DbCommandBuilder não mapeará parâmetros de saída para colunas em uma linha atualizada por padrão. Nessa instância, você deve especificar o comando explicitamente. Para obter um exemplo de como mapear um campo de identidade gerado automaticamente de volta para uma coluna de uma linha inserida, confira Recuperar valores de identidade ou numeração automática.
Regras para comandos gerados automaticamente
A tabela a seguir mostra as regras para como os comandos gerados automaticamente são gerados.
Comando | Regra |
---|---|
InsertCommand |
Insere uma linha na fonte de dados para todas as linhas na tabela com um RowState de Added. Insere valores para todas as colunas que são atualizáveis (mas não colunas como identidades, expressões ou carimbos de data/hora). |
UpdateCommand |
Atualiza linhas na fonte de dados para todas as linhas na tabela com um RowState de Modified. Atualiza os valores de todas as colunas exceto as que não são atualizáveis, como identidades ou expressões. Atualiza todas as linhas onde os valores de coluna na fonte de dados correspondem aos valores de coluna de chave primária da linha, e onde as colunas restantes na fonte de dados correspondem aos valores originais da linha. Para obter mais informações, consulte “Modelo de simultaneidade otimista para atualizações e exclusões”, posteriormente neste tópico. |
DeleteCommand |
Exclui linhas na fonte de dados para todas as linhas na tabela com um RowState de Deleted. Exclui todas as linhas onde os valores de coluna correspondem aos valores de coluna de chave primária da linha, e onde as colunas restantes na fonte de dados correspondem aos valores originais da linha. Para obter mais informações, confira o Modelo de simultaneidade otimista para atualizações e exclusões, mais adiante neste tópico. |
Modelo de simultaneidade otimista para atualizações e exclusões
A lógica para gerar automaticamente comandos para instruções UPDATE e DELETE é baseada na simultaneidade otimista, isto é, os registros não são bloqueados para edição e podem ser alterados por outros usuários ou processos a qualquer momento. Como um registro pode ter sido modificado após ter sido retornado da instrução SELECT, mas antes de a instrução UPDATE ou DELETE ser emitida, a instrução UPDATE ou DELETE gerada automaticamente contém uma cláusula WHERE, especificando que uma linha estará atualizada apenas se contiver todos os valores originais e não tiver sido excluída da fonte de dados. Isso é feito para evitar sobrescrever novos dados.
Observação
Onde uma atualização gerada automaticamente tentar atualizar uma linha que foi excluída ou que não contém os valores originais localizados no DataSet, o comando não afetará nenhum registro e uma DBConcurrencyException será gerada.
Se você desejar que a instrução UPDATE ou DELETE seja concluída independentemente dos valores originais, você deverá definir explicitamente o UpdateCommand
para o DataAdapter
e não depender da geração de comando automática.
Limitações da lógica de geração automática de comando
As seguintes limitações aplicam-se à geração automática de comando.
Somente tabelas não relacionadas
A lógica de geração automática de comando gera instruções INSERT, UPDATE ou DELETE para tabelas autônomas sem levar em consideração as relações com outras tabelas em uma fonte de dados. Como resultado, você pode encontrar uma falha ao chamar Update
para enviar alterações para uma coluna que participa em uma restrição de chave estrangeira no banco de dados. Para evitar essa exceção, não use o DbCommandBuilder para atualizar as colunas envolvidas em uma restrição de chave estrangeira; em vez disso, especifique explicitamente as instruções usadas para executar a operação.
Nomes de coluna e tabela
A lógica da geração automática de comando poderá falhar se os nomes de colunas ou tabelas contiverem algum caractere especial, como espaços, pontos, aspas ou outros caracteres não alfanuméricos, mesmo se estiver limitado por colchetes. Dependendo do provedor, definir os parâmetros QuotePrefix e QuoteSuffix pode permitir que a lógica de geração processe os espaços, mas não será possível substituir caracteres especiais. Os nomes de tabela totalmente qualificados na forma de catalog.schema.table têm suporte.
Usar o CommandBuilder para gerar automaticamente uma instrução SQL
Para gerar automaticamente as instruções SQL para um DataAdapter
, primeiro defina a propriedade SelectCommand
de DataAdapter
, em seguida, crie um objeto CommandBuilder
e especifique como argumento o DataAdapter
para o qual o CommandBuilder
gerará instruções SQL automaticamente.
// Assumes that connection is a valid SqlConnection object
// inside of a using block.
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = new SqlCommand(queryString, connection);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
builder.QuotePrefix = "[";
builder.QuoteSuffix = "]";
Modificar o SelectCommand
Se você alterar o CommandText
do SelectCommand
após os comandos INSERT, UPDATE ou DELETE terem sido gerados automaticamente, uma exceção poderá ocorrer. Se o SelectCommand.CommandText
modificado contiver informações de esquema que forem inconsistentes com o SelectCommand.CommandText
usado quando os comandos de inserção, atualização ou exclusão foram gerados automaticamente, as chamadas futuras para o método DataAdapter.Update
poderão tentar acessar as colunas que não existem mais na tabela atual referenciada pelo SelectCommand
e uma exceção será gerada.
Você pode atualizar as informações de esquema usadas pelo CommandBuilder
para gerar automaticamente comandos chamando o método RefreshSchema
do CommandBuilder
.
Se você quiser saber qual comando foi gerado automaticamente, poderá obter uma referência para comandos gerados automaticamente usando os métodos GetInsertCommand
, GetUpdateCommand
e GetDeleteCommand
do objeto CommandBuilder
e verificando a propriedade CommandText
do comando associado.
O exemplo de código a seguir grava no console o comando de atualização que foi gerado automaticamente.
// Generate the update command automatically by SqlCommandBuilder
Console.WriteLine(builder.GetUpdateCommand().CommandText);
O exemplo a seguir recria a tabela no conjunto de dados do . O método RefreshSchema é chamado para atualizar os comandos gerados automaticamente com as informações dessa nova coluna.
// Assumes an open SqlConnection and SqlDataAdapter inside of a using block.
adapter.SelectCommand.CommandText = newQueryString;
builder.RefreshSchema();
dataSet.Tables.Remove(dataSet.Tables[tableName]);
adapter.Fill(dataSet, tableName);