Gerando comandos com CommandBuilders
Quando a SelectCommand
propriedade é especificada dinamicamente em tempo de execução, como por meio de uma ferramenta de consulta que recebe um comando textual do usuário, talvez não seja possível especificar o , InsertCommand
UpdateCommand
apropriado , ou DeleteCommand
em tempo de design. Se seus DataTable mapas para ou são gerados a partir de uma única tabela de banco de dados, você pode aproveitar o DbCommandBuilder objeto para gerar automaticamente o DeleteCommand
, InsertCommand
e UpdateCommand
do DbDataAdapter.
Como requisito mínimo, você deve definir a propriedade para que a SelectCommand
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 InsertCommand
UpdateCommand
, 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 para um DataSet
retorno à fonte de dados, consulte Atualizando fontes de dados com DataAdapters.
Talvez você queira mapear os parâmetros de saída de volta para a linha atualizada de um DataSet
arquivo . Uma tarefa comum seria recuperar o valor de um campo de identidade gerado automaticamente ou carimbo de data/hora 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 colunas como identidades, expressões ou carimbos de data/hora). |
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 na fonte de dados de 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 simultaneidade 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 substituiçã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 desejar que UPDATE ou DELETE seja concluído, independentemente dos valores originais, você deve definir explicitamente o UpdateCommand
para e DataAdapter
não confiar na 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 você modificar o CommandText
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 SelectCommand
pelo , e uma exceção será lançada.
Você pode atualizar as informações de esquema usadas pelo para gerar comandos automaticamente CommandBuilder
chamando o RefreshSchema
método do CommandBuilder
.
Se quiser saber qual comando foi gerado automaticamente, você pode obter uma referência aos comandos gerados automaticamente usando os GetInsertCommand
métodos , GetUpdateCommand
e 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 método RefreshSchema é chamado para atualizar os comandos gerados automaticamente com essas novas informações 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");