Partilhar via


Gerando comandos com CommandBuilders

Quando a SelectCommand propriedade é especificada dinamicamente em tempo de execução, como através de uma ferramenta de consulta que aceita um comando textual do utilizador, pode não ser possível especificar InsertCommand, UpdateCommand, ou DeleteCommand na fase de concepção. Se o seu DataTable mapeia para ou é gerado a partir de uma única tabela de base de dados, pode tirar partido do objeto DbCommandBuilder para gerar de forma automática o DeleteCommand, InsertCommand e UpdateCommand do DbDataAdapter.

Como requisito mínimo, deve definir a propriedade SelectCommand para que a geração automática de comandos funcione. O esquema de tabela recuperado SelectCommand pela propriedade determina a sintaxe das instruções INSERT, UPDATE e DELETE geradas automaticamente.

O DbCommandBuilder deve executar o SelectCommand para retornar os metadados necessários para construir os comandos INSERT, UPDATE e DELETE SQL. Como resultado, uma viagem extra para a fonte de dados é necessária, e isso pode prejudicar o desempenho. Para obter o desempenho ideal, especifique seus comandos explicitamente em vez de usar o DbCommandBuilder.

O SelectCommand também deve retornar pelo menos uma chave primária ou coluna exclusiva. Se nenhum estiver presente, uma InvalidOperation exceção será gerada e os comandos não serão gerados.

Quando associado a um DataAdapter, o DbCommandBuilder gera automaticamente as InsertCommandUpdateCommand, e DeleteCommand propriedades do DataAdapter se são referências nulas. Se um Command já existe para uma propriedade, o existente Command é usado.

As exibições de banco de dados criadas pela junção de duas ou mais tabelas não são consideradas uma única tabela de banco de dados. Neste caso, você não pode usar o DbCommandBuilder para gerar comandos automaticamente, você deve especificar seus comandos explicitamente. Para obter informações sobre como definir explicitamente comandos para resolver atualizações de DataSet de volta à fonte de dados, consulte Atualização de fontes de dados com DataAdapters.

Talvez queiras mapear os parâmetros de saída de volta para a linha atualizada de um arquivo DataSet. Uma tarefa comum seria recuperar o valor de um campo de identidade gerado automaticamente ou de um timestamp da fonte de dados. O DbCommandBuilder não mapeará parâmetros de saída para colunas em uma linha atualizada por padrão. Neste caso, você deve especificar seu comando explicitamente. Para obter um exemplo de mapeamento de um campo de identidade gerado automaticamente de volta para uma coluna de uma linha inserida, consulte Recuperando valores de identidade ou numeração automática.

Regras para comandos gerados automaticamente

A tabela a seguir mostra as regras de como os comandos gerados automaticamente são gerados.

Comando Regra
InsertCommand Insere uma linha na fonte de dados para todas as linhas da tabela com um RowState de Added. Insere valores para todas as colunas atualizáveis (mas não para colunas como identidades, expressões ou marcas temporais).
UpdateCommand Atualiza linhas na fonte de dados para todas as linhas da tabela com um RowState de Modified. Atualiza os valores de todas as colunas, exceto as colunas que não são atualizáveis, como identidades ou expressões. Atualiza todas as linhas em que 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", mais adiante neste tópico.
DeleteCommand Exclui linhas da fonte de dados para todas as linhas da tabela com um RowState de Deleted. Exclui todas as linhas em que os valores de coluna correspondem aos valores de coluna de chave primária da linha e em que 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", mais adiante neste tópico.

Modelo de concorrência otimista para atualizações e exclusões

A lógica para gerar comandos automaticamente para instruções UPDATE e DELETE é baseada em simultaneidade otimista - ou seja, os registros não são bloqueados para edição e podem ser modificados por outros usuários ou processos a qualquer momento. Como um registro poderia ter sido modificado depois de ter sido retornado da instrução SELECT, mas antes da 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 só será atualizada se contiver todos os valores originais e não tiver sido excluída da fonte de dados. Isso é feito para evitar a sobrescrição de novos dados. Quando uma atualização gerada automaticamente tenta atualizar uma linha que foi excluída ou que não contém os valores originais encontrados no DataSet, o comando não afeta nenhum registro e um DBConcurrencyException é lançado.

Se quiser que UPDATE ou DELETE seja concluído, independentemente dos valores originais, deve definir explicitamente o UpdateCommand para o DataAdapter e não depender da geração automática de comandos.

Limitações da lógica de geração automática de comandos

As limitações a seguir se aplicam à geração automática de comandos.

Somente tabelas não relacionadas

A lógica de geração automática de comandos gera instruções INSERT, UPDATE ou DELETE para tabelas autônomas sem levar em conta quaisquer relações com outras tabelas na fonte de dados. Como resultado, você pode encontrar uma falha ao chamar Update para enviar alterações para uma coluna que participa de uma restrição de chave estrangeira no banco de dados. Para evitar essa exceção, não use o DbCommandBuilder para atualizar 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 tabelas e colunas

A lógica de geração automática de comandos pode falhar se os nomes das colunas ou das tabelas contiverem caracteres especiais, como espaços, pontos, aspas ou outros caracteres não alfanuméricos, mesmo que delimitados por colchetes. Dependendo do provedor, definir os parâmetros QuotePrefix e QuoteSuffix pode permitir que a lógica de geração processe espaços, mas não pode escapar de caracteres especiais. Há suporte para nomes de tabelas totalmente qualificados na forma de catalog.schema.table .

Usando o CommandBuilder para gerar automaticamente uma instrução SQL

Para gerar automaticamente instruções SQL para um DataAdapter, primeiro defina a SelectCommand propriedade do DataAdapter, em seguida, crie um CommandBuilder objeto e especifique como um argumento para o DataAdapter qual o CommandBuilder irá gerar automaticamente instruções SQL.

' Assumes that connection is a valid SqlConnection object
' inside of a Using block.
Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
  "SELECT * FROM dbo.Customers", connection)
Dim builder As SqlCommandBuilder = New SqlCommandBuilder(adapter)
builder.QuotePrefix = "["
builder.QuoteSuffix = "]"
// Assumes that connection is a valid SqlConnection object
// inside of a using block.
SqlDataAdapter adapter = new SqlDataAdapter(
  "SELECT * FROM dbo.Customers", connection);
SqlCommandBuilder builder = new SqlCommandBuilder(adapter);
builder.QuotePrefix = "[";
builder.QuoteSuffix = "]";

Modificando o SelectCommand

Se modificar o CommandText do SelectCommand após os comandos INSERT, UPDATE ou DELETE terem sido gerados automaticamente, poderá ocorrer uma exceção. Se o modificado SelectCommand.CommandText contiver informações de esquema inconsistentes com o SelectCommand.CommandText usado quando os comandos inserir, atualizar ou excluir foram gerados automaticamente, chamadas futuras para o DataAdapter.Update método poderão tentar acessar colunas que não existem mais na tabela atual referenciada SelectCommandpelo , e uma exceção será lançada.

Você pode atualizar as informações de esquema usadas pelo CommandBuilder para gerar comandos automaticamente, chamando o método RefreshSchema do CommandBuilder.

Se quiser saber qual comando foi gerado automaticamente, você pode obter uma referência aos comandos gerados automaticamente usando os GetInsertCommandmétodos , GetUpdateCommande GetDeleteCommand do CommandBuilder objeto e verificando a CommandText propriedade do comando associado.

O exemplo de código a seguir grava no console o comando update que foi gerado automaticamente.

Console.WriteLine(builder.GetUpdateCommand().CommandText)
Console.WriteLine(builder.GetUpdateCommand().CommandText);

O exemplo a seguir recria a Customers tabela no conjunto de custDS dados. O RefreshSchema método é chamado para atualizar os comandos gerados automaticamente com esta nova informação de coluna.

' Assumes an open SqlConnection and SqlDataAdapter inside of a Using block.
adapter.SelectCommand.CommandText = _
  "SELECT CustomerID, ContactName FROM dbo.Customers"
builder.RefreshSchema()

custDS.Tables.Remove(custDS.Tables("Customers"))
adapter.Fill(custDS, "Customers")
// Assumes an open SqlConnection and SqlDataAdapter inside of a using block.
adapter.SelectCommand.CommandText =
  "SELECT CustomerID, ContactName FROM dbo.Customers";
builder.RefreshSchema();

custDS.Tables.Remove(custDS.Tables["Customers"]);
adapter.Fill(custDS, "Customers");

Ver também