Salvar dados em Datasets
Salvar dados é o processo de persistir dados alterados em um aplicativo de volta para o armazenamento de dados original, geralmente um banco de dados relacional como um SQL Server.
Como um dataset é efetivamente um cache — uma cópia em memória — dos dados, o processo de gravar informações para a fonte de dados original é separado do processo de modificar os dados no dataset.Você pode enviar dados atualizados no datasets de volta para o banco de dados chamando um dos métodos Update de um TableAdapter ou chamando um dos métodos DBDirect do TableAdapter.
Para obter mais informações sobre enviar as alterações em um conjunto de dados de volta ao banco de dados, consulte Como: atualizar dados usando um TableAdapter e Como: salvar alterações do Dataset em um banco de dados.
Visual Studio fornece um componente de TableAdapterManager que auxilia a salvar quando você salva dados em tabelas relacionadas.Esse componente garante que operações de salvar sejam executadas na ordem correta com base nas restrições de chave externa definidas no banco de dados.Para mais informações, consulte Visão geral de atualização hierárquica.
Para obter informações sobre modificação de dados no dataset, consulte Edição de dados em seu aplicativo..
Atualizações de Dois Estágios
Atualizar uma fonte de dados por meio de um dataset é um processo de duas etapas.A primeira etapa é atualizar o dataset com novas informações — novos registros, registros alterados ou registros excluídos.Se seu aplicativo está relacionado somente com o dataset — por exemplo, após atualizar o dataset, você o envia para outro aplicativo que irá executar mais processamento do dataset — então você está terminando a atualização.
Observação |
---|
No Windows Forms, a arquitetura de associação de dados cuida do envio de alterações dos controles associados a dados para o dataset e você não precisa atualizar o dataset com seu próprio código.Para mais informações, consulte Ligação de dados de formulários do Windows. |
Se você estiver atualizando uma fonte de dados (como um banco de dados), a segunda etapa é enviar as alterações do dataset para fonte de dados original.Isto é, o processo de atualização o dataset também não grava as alterações a uma fonte de dados base; você deve executar essa segunda etapa explicitamente.Você normalmente faz isso chamando o método Update do mesmo TableAdapter (ou adaptador de dados) que você usou para preencher o dataset, embora também possa usar adaptadores diferentes, por exemplo, para mover dados de uma fonte de dados para outra ou para atualizar várias fontes de dados.
Processo de atualização de dois estágios e a função do DataRowVersion em uma atualização bem sucedida
Estruturalmente, um dataset disponibiliza dados como conjuntos de coleções.DataSets contêm coleções de tabelas.Tabelas contêm coleções de linhas.Tabelas são expostas como uma coleção do objeto DataSet e registros estão disponíveis na coleção Rows de objetos DataTable.Fazer alterações a dados em um dataset simplesmente manipulando essas coleções usando métodos de coleções de base é possível, mas se você pretende atualizar uma fonte de dados subjacente você deve usar os métodos especificamente criados para modificação de dataset.
Por exemplo, para remover um registro de uma tabela de dados, você poderia chamar o RemoveAt Method da coleção Rows da tabela, que fisicamente exclui o registro do dataset.Se você estiver usando o dataset somente como um armazenamento estruturado para dados e não estiver preocupado em transmitir mudança de informações para um outro aplicativo, manipular coleções dessa maneira é um modo aceitável de atualização um dataset.
Entretanto, se você pretende enviar alterações para uma fonte de dados ou outro aplicativo, você precisará manter informações de alterações (isto é, metadados) sobre cada atualização.Posteriormente, quando você enviar alterações para a fonte de dados ou aplicativo, o processo terá as informações necessárias para localizar e atualizar os registros adequados.Por exemplo, se você excluir um registro no dataset, informações sobre o registro excluído devem ser mantidas no dataset.Dessa forma, quando o DeleteCommand do TableAdapter é chamado, há informações históricas suficientes para localizar o registro original na fonte de dados para que este possa ser excluído.Para obter mais informações, consulte " Mantendo Informações Sobre Alterações " abaixo.
Mesclando DataSets
Você pode atualizar o conteúdo de um dataset mesclando — isto é, copiando o conteúdo de um dataset (chamado de dataset origem) para o dataset chamado (referido como o dataset destino).Quando você mescla datasets, novos registros na fonte do dataset são adicionados para o dataset destino.Além disso, colunas extras do dataset fonte são adicionadas ao dataset destino.Mesclar datasets é particularmente útil quando você tiver um dataset local e obter um segundo dataset de outro aplicativo ou de um componente como um XML Web Services.Também é útil quando você precisa integrar dados de vários datasets.
Ao mesclar conjuntos de dados, você também pode passar um argumento Boolean opcional (preserveChanges) que indica ao método Merge se modificações existentes devem ser retidas no DataSet de destino.Como datasets mantêm várias versões de registros, é importante ter em mente que mais de uma versão dos registros está sendo mesclada.A tabela a seguir ilustra um registro em dois datasets que serão mesclados:
DataRowVersion |
DataSet destino |
DataSet origem |
---|---|---|
Original |
James Wilson |
James C.Wilson |
Current |
Jim Wilson |
James C.Wilson |
Chamar o método Merge na tabela acima com preserveChanges=false targetDataset.Merge(sourceDataset) resulta no seguinte:
DataRowVersion |
DataSet destino |
DataSet origem |
---|---|---|
Original |
James C.Wilson |
James C.Wilson |
Current |
James C.Wilson |
James C.Wilson |
Chamar o método Merge com preserveChanges = true targetDataset.Merge(sourceDataset, true) resulta no seguinte:
DataRowVersion |
DataSet destino |
DataSet origem |
---|---|---|
Original |
James C.Wilson |
James C.Wilson |
Current |
Jim Wilson |
James C.Wilson |
Cuidado |
---|
No cenário preserveChanges = true, se o método RejectChanges for chamado em um registro no DataSet de destino, em seguida, ele reverterá para os dados originais do DataSet source.Isso significa que se você tentar atualizar a fonte de dados original com o dataset destino, ele pode não ser capaz de localizar a linha original para atualizar.Entretanto, você pode impedir uma violação simultânea preenchendo outro dataset com os registros atualizados a partir da fonte de dados e, então, executar uma mesclagem impedindo uma violação simultânea.(Uma violação simultânea ocorre quando outro usuário modifica um registro na fonte de dados após o dataset ter sido preenchido). |
Restrições de Atualização
Para fazer alterações em um linha de dados existente, você adiciona ou atualiza dados nas colunas individuais.Se o dataset contiver restrições (como chaves estrangeiras ou restrições não anuláveis), é possível que você atualize um registro — depois de terminar de atualizar uma coluna, mas antes de obter a próxima — o registro pode temporariamente estar em um estado de erro.
Para evitar violações de restrição você pode temporariamente suspender restrições de atualização.Isso serve para duas finalidades:
Ela impede que um erro seja jogado quando você atualiza uma coluna antes de obter a outra coluna.
Ele suspende determinados eventos de atualização de serem elevados (eventos que são freqüentemente usados para validação).
Após a conclusão de uma atualização, você pode reativar a restrição de verificação, que também reativa eventos de atualização e os aumenta.
Observação |
---|
Em Formulários do Windows, a arquitetura de associação de dados construída dentro do DataGrid suspende a verificação de restrição até que o foco se mova para fora de uma linha, e não é necessário chamar explicitamente os métodos BeginEdit, EndEdit ou CancelEdit. |
As restrições são automaticamente desativadas quando o método Merge é chamado em um DataSet.Quando a mesclagem estiver concluída, se houver quaisquer restrições no conjunto de dados que não possam ser habilitadas, em seguida, uma ConstraintException é gerada.Nesta situação, a propriedade EnforceConstraints é definida como false e todas as violações de restrição devem ser resolvidas antes de redefinir a propriedade EnforceConstraints para true.
Após a conclusão de uma atualização, você pode reativar a restrição de verificação, que também reativa eventos de atualização e os aumenta.
Para obter mais informações sobre eventos de suspensão, consulte Como: desativar restrições ao preencher um Dataset..
Erros de Atualização de DataSet
Quando você atualiza um registro em um dataset, há a possibilidade de um erro.Por exemplo, você pode inadvertidamente gravar dados em uma coluna que é do tipo de dados errado ou muito longo ou que tenha algum outro problema de integridade.Além disso, você pode ter verificações de validação específicas do aplicativo que podem elevar a erros personalizados durante qualquer estágio de um evento de atualização.Para mais informações, consulte Validação de dados em Datasets.
Manter Informações Sobre Alterações
Informações adicionais sobre as alterações em um DataSet são mantidas de duas maneiras: sinalizando a linha que indica se ele foi alterado (RowState), e mantendo várias cópias de um registro (DataRowVersion).Usando essas informações, processos podem determinar o que foi alterado no dataset e podem enviar atualizações apropriadas para a fonte de dados.
Propriedade RowState
A propriedade RowState de um objeto DataRow é um valor que fornece informações sobre o status de uma linha específica de dados.
A tabela a seguir detalha os valores possíveis da enumeração DataRowState:
Valor de DataRowState |
Descrição |
---|---|
A linha foi adicionada como um item para uma DataRowCollection.(Uma linha nesse estado não tem uma versão original correspondente desde que ela não existia no momento em que o último método AcceptChanges foi chamado). |
|
A linha foi criada, mas não é parte de qualquer DataRowCollection.Um objeto DataRow está nesse estado imediatamente após ele ter sido criado antes de ser adicionado a uma coleção, ou se ele tiver sido removido de uma coleção. |
|
Um valor de coluna na linha foi alterado de alguma maneira. |
|
A linha não foi alterada desde que AcceptChanges foi chamado pela última vez. |
Enumeração DataRowVersion
Datasets mantém várias versões de registros.A enumeração DataRowVersion de um objeto DataRow é um valor que pode ser usado para retornar uma versão específica de um objeto DataRow.
A tabela a seguir detalha os valores possíveis da enumeração DataRowVersion:
Valor de DataRowVersion |
Descrição |
---|---|
A versão atual de um registro contém todas as modificações executadas no registro desde a última vez que AcceptChanges foi chamada.Se a linha foi excluída não há versão atual. |
|
O valor padrão de um registro, conforme definido pelo esquema do dataset ou fonte de dados. |
|
A versão original de um registro é uma cópia do registro como ele nas últimas alterações foram confirmadas no dataset.Em termos práticos, isso é normalmente a versão de um registro como lida de uma fonte de dados. |
|
A versão proposta de um registro que está disponível temporariamente, enquanto você está no meio de uma atualização — ou seja, entre o momento que você chamou o método BeginEdit e o método EndEdit.Você normalmente acessa a versão proposta de um registro em um manipulador para um evento como RowChanging.Chamar o método CancelEdit reverte as alterações e exclui a versão proposta da linha de dados. |
As versões originais e atuais são úteis quando informações de atualização são transmitidas para uma fonte de dados.Normalmente, quando uma atualização é enviada para a fonte de dados, as novas informações para o banco de dados estão na versão atual de um registro.Informações da versão original são usadas para localizar o registro para atualizar.Por exemplo, no caso onde a chave primária de um registro for alterada, você deve ter uma maneira de localizar o registro adequado em uma fonte de dados, para atualizar as alterações.Se nenhuma versão original existisse, o registro provavelmente seria anexado à fonte de dados, resultando não apenas em um registro extra indesejado, mas em um registro que está impreciso e desatualizado.As duas versões também são usados no controle de simultaneidade; você pode comparar a versão original contra um registro na fonte de dados para determinar se o registro foi alterado desde que foi carregado no dataset.
A versão proposta é útil quando você precisa realizar validação antes de realmente confirmar as alterações para o dataset.
Mesmo se registros tiverem sido alterados, não há sempre versões originais ou atuais de linha.Quando você insere uma nova linha na tabela, não há nenhuma versão original, somente a versão atual.Da mesma forma, se você excluir uma linha, chamando o método Delete da tabela, há uma versão original, mas nenhuma versão atual.
Você pode testar para ver se uma versão específica de um registro existe consultando o método de HasVersion de uma linha de dados.Você pode acessar tanto a versão de um registro, passando um valor de enumeração DataRowVersion como um argumento opcional quando você solicita o valor de uma coluna.
Obter Registros Alterados
É comum que você não atualize cada registro em um dataset.Por exemplo, um usuário pode estar trabalhando com um controle DataGridView de Formulários do Windows que exibe vários registros.Entretanto, o usuário pode atualizar apenas alguns registros, excluir um, e inserir um novo nome.Datasets e tabelas de dados fornecem um método (GetChanges) para retornar somente as linhas que foram modificadas.
Você pode criar subconjuntos dos registros alterados usando o método GetChanges de uma tabela de dados (GetChanges) ou do próprio conjunto de dados (GetChanges).Se você chamar o método para a tabela de dados, ela retornará uma cópia da tabela com apenas os registros alterados.De a mesma forma, se você chamar o método no dataset, você obtém um novo conjunto de dados com apenas os registros alterados em ele.GetChanges por si só retornará todos os registros alterados.Em contraste, passando o DataRowState desejado como um parâmetro para o método GetChanges, você pode especificar o subconjunto de registros alterados que você deseja: registros recém-adicionados, registros marcados para exclusão, registros separados, ou registros modificados.
Obter um subconjunto de registros alterados é especialmente útil quando você deseja enviar registros para outro componente para processamento.Em vez de enviar o dataset inteiro, você pode reduzir a sobrecarga de se comunicar com o outro componente por meio somente os registros que o componente precisa.Para mais informações, consulte Como: recuperar linhas alteradas.
Confirmar Alterações no DataSet
À medida que as alterações são feitas no dataset, a propriedade RowState das linhas alteradas é definida.As versões original e atuais do registros são estabelecidas e mantidas e disponibilizadas para você pela propriedade RowVersion.Os metadados armazenados nessas propriedades que representam as alterações são necessários para enviar as atualizações adequadas para a fonte de dados.
Se as alterações refletem o estado atual da fonte de dados, você não mais precisa manter essas informações.Normalmente, existem duas vezes quando o dataset e sua fonte estão em sincronização:
Imediatamente após você ter carregado informações para o dataset, como quando você lê dados da fonte.
Após enviar alterações do dataset para a fonte de dados (mas não antes, porque você pode perder as informações necessárias para enviar alterações para o banco de dados).
Você pode confirmar as alterações pendentes para o conjunto de dados chamando o método AcceptChanges.Normalmente, AcceptChanges seria chamado nos seguintes momentos em seu aplicativo.
Depois que você carregou o dataset.Se você carregar um dataset chamando o métodoFill de um TableAdapter, então o adaptador confirma automaticamente as alterações para você.Entretanto, se você carregar um dataset, mesclando outro dataset para ele, então você terá que confirmar as alterações manualmente.
Observação Você pode impedir que o adaptador confirme automaticamente as alterações ao chamar o método Fill, definindo a propriedade AcceptChangesDuringFill do adaptador para false.Se ela estiver definida como false, então o RowState de cada linha inserida durante o preenchimento é definido como Added.
Após você ter enviado alterações do dataset para outro processo, como um XML Web Service.
Cuidado Confirmar a alteração dessa maneira apaga qualquer mudança da informação.Não confirmar alterações até depois que você tiver efetuado quaisquer operações no qual seu aplicativo depende em saber quais alterações foram feitas no dataset.
Esse método realiza o seguinte:
Grava a versão Current de um registro na sua versão Original, substituindo a versão original.
Remove qualquer linha cuja propriedade RowState é definida como Deleted.
Define a propriedade RowState de um registro para Unchanged.
O método AcceptChanges está disponível em três níveis.Você pode chamá-lo em um objeto DataRow, que confirma as alterações apenas naquela linha.Você também pode chamá-lo em um objeto DataTable para confirmar todas as linhas em uma tabela, ou o objeto DataSet para confirmar todas as alterações pendentes em todos os registros de todas as tabelas do DataSet.
A tabela a seguir descreve quais alterações são confirmadas com base em qual objeto o método é chamado.
Método |
Resultado |
---|---|
Alterações são confirmadas somente sobre a linha específica |
|
Alterações são confirmadas em todas as linhas na tabela específica |
|
Alterações são confirmadas em todas as linhas em todas as tabelas do dataset |
Observação |
---|
Se você carregar um dataset chamando o método Fill de um TableAdapter, você não tem que explicitamente aceitar alterações; por padrão o método Fill chama o método AcceptChanges quando ele tiver terminado de preencher a tabela de dados. |
Um método relacionado, RejectChanges, desfaz o efeito das alterações copiando a versão Original de volta para a versão Current de registros e definindo o RowState de cada registro de volta para Unchanged.
Validação de Dados
A fim de verificar que os dados em seu aplicativo atendem aos requisitos dos processos que é passado, você freqüentemente precisa adicionar validação.Isso pode envolver verificação que uma entrada do usuário em um formulário está correta, validação de dados enviados para seu aplicativo por outro aplicativo ou mesmo verificar que informações calculadas no seu componente se enquadra nas restrições de sua fonte de dados e aplicativos requeridos.
Você pode validar dados de várias maneiras:
Na camada comercial, adicionando o código a seu aplicativo para validar dados.O dataset é um local que você pode fazer isso.O dataset fornece algumas das vantagens de validação back-end — como a capacidade para validar alterações como valores de coluna e linha alteradas.Para mais informações, consulte Validação de dados em Datasets.
Na camada de apresentação, adicionando validação a formulários.Para mais informações, consulte User Input Validation in Windows Forms.
No back-end de dados, enviando dados para a fonte de dados — por exemplo, o banco de dados — e permitindo que ele aceite ou rejeite os dados.Se você estiver trabalhando com um banco de dados que tem recursos sofisticados para validação de dados e fornecimento de informações de erro, isso pode ser uma abordagem prática porque você pode validar os dados não importando de onde ele vem.Entretanto, ele pode não acomodar requisitos específicos de aplicativo de validação.Além disso, tendo a fonte de dados validada, dados podem resultar em várias viagens à fonte de dados, dependendo de como seu aplicativo facilita em resolver erros de validação elevados pelo back-end.
Observação de segurança Ao usar comandos de dados com uma propriedade CommandType definida como Text, verifique cuidadosamente as informações enviadas a partir de um cliente antes de transmití-las ao seu banco de dados.Usuários mal intencionados podem tentar para enviar (inserir) instruções SQL modificadas ou adicionais em um esforço para obter acesso não autorizado ou danificar o banco de dados.Antes de você transferir a entrada do usuário a um banco de dados, você deve verificar se as informações são válidas; é a melhor prática para sempre usar consultas parametrizadas ou procedimentos armazenados quando possível.Para mais informações, consulte Script Exploits Overview.
Após terem sido feitas alterações em um dataset, você pode transmitir as alterações em uma fonte de dados.Mais comumente, você faz isso chamando o método Update de um TableAdapter (ou adaptador de dados).O método loops a cada registro em uma tabela de dados, determina que tipo de atualização é necessária (atualizar, inserir ou excluir), se houver, e, então, executa o comando apropriado.
Como Uma Atualização é Transmitida à Fonte de Dados
Como uma ilustração da como atualizações são feitas, suponha que o seu aplicativo utilize um dataset contendo uma única tabela de dados.O aplicativo busca duas linhas do banco de dados.Após a recuperação, a tabela de dados na memória tem esta aparência:
(RowState) CustomerID Name Status
(Unchanged) c200 Robert Lyon Good
(Unchanged) c400 Nancy Buchanan Pending
Seu aplicativo altera o status de Nancy Buchanan para " Preferred ". Como resultado dessa alteração, o valor da propriedade RowState daquela linha muda de Unchanged para Modified.O valor da propriedade RowState para a primeira linha permanece Unchanged.A tabela de dados agora tem esta aparência:
(RowState) CustomerID Name Status
(Unchanged) c200 Robert Lyon Good
(Modified) c400 Nancy Buchanan Preferred
Seu aplicativo agora chama o método Update para transmitir o dataset para o banco de dados.O método inspeciona cada linha por vez.Para a primeira linha, o método não transmite Instrução SQL para o banco de dados, porque essa linha não foi alterada desde que foi originalmente procurada no banco de dados.
Para a segunda linha, no entanto, o método Update automaticamente chama o comando de dados adequado e o transmite para o banco de dados.A sintaxe específica da instrução SQL depende do dialeto do SQL suportado para o armazenamento de dados subjacente.Mas os seguintes traços gerais de instrução do SQL transmitidos são os que valem a pena observar:
A instrução SQL transmitida é uma declaração UPDATE.O adaptador sabe usar uma instrução UPDATE porque o valor da propriedade RowState é Modified.
A instrução SQL transmitida inclui uma cláusula WHERE indicando que o destino da declaração UPDATE é a linha cujo CustomerID = 'c400'.Esta parte da declaração SELECT distingue a linha de destino de todas as outras porque o CustomerID é a chave primária da tabela de destino.As informações para a cláusula WHERE são derivadas da versão original do registro (DataRowVersion.Original), no caso de os valores necessários para identificar a linha terem sido alterados.
A instrução SQL transmitida inclui a cláusula SET, para definir os novos valores das colunas modificadas.
Observação Se a propriedade UpdateCommand do TableAdapter tiver sido definida com o nome de um procedimento armazenado, o adaptador não constrói uma instrução SQL.Em vez disso, ele chama o procedimento armazenado com os parâmetros apropriados passados.
Passando Parâmetros
Valores de registros a serem atualizados no banco de dados são passados usando parâmetros.Quando o método Update do TableAdapter executa uma declaração UPDATE, ele precisa preencher os valores de parâmetro.Ele obtém esses valores da coleção Parameters para o comando de dados apropriado — neste caso, o objeto UpdateCommand no TableAdapter.
Se você tiver usado as ferramentas do Visual Studio para gerar um adaptador de dados, o objeto UpdateCommand conterá uma coleção de parâmetros que corresponde a cada espaço reservado de parâmetro na declaração.
A propriedade SqlParameter.SourceColumn de cada parâmetro aponta para uma coluna na tabela de dados.Por exemplo, a propriedade de SourceColumn para au_id e parâmetros de Original_au_id é definida para o qual coluna na tabela de dados que contém a identificação do autorQuando o método de Update do adaptador executa, leia a coluna de identificação de autor do registro sendo atualizado e preenche os valores na instrução.
Em uma instrução UPDATE, você precisa especificar novos valores (aqueles que serão gravados no Registro) bem como os antigos (de modo que o registro a ser atualizado possa ser localizado no banco de dados).Portanto, há dois parâmetros para cada valor: um para a cláusula set e um diferente para a cláusula WHERE.Ambos os parâmetros lêem dados do registro que está sendo atualizado, mas eles obtêm versões diferentes do valor da coluna baseado na SqlParameter.SourceVersion Property do parâmetro.O parâmetro para a cláusula SET obtém a versão atual, e o parâmetro para a cláusula WHERE obtém a versão original.
Observação |
---|
Você mesmo também pode definir valores na coleção Parameters no código, o que normalmente você faria em um manipulador de eventos para o evento RowChanging do adaptador de dados. |
Atualizando Tabelas Relacionadas
Se o dataset contiver várias tabelas, você precisa atualizá-las individualmente chamando o método Update de cada adaptador de dados separadamente.Se as tabelas têm uma relação pai-filho, é provável que você terá que enviar atualizações para o banco de dados em uma ordem específica.Um cenário comum é que você adicionou pai e o filho relacionado gravados para um dataset — por exemplo, um novo registro do cliente e um ou mais registros relacionados.Se o próprio banco de dados está impondo regras de integridade relacional, ele aumentará erros se você enviar o novo registro filho para o banco de dados antes que o registro pai tiver sido criado.
Inversamente, se você excluir registros relacionados no dataset, geralmente você terá para que atualizações na ordem inversa: tabela filho primeiro, depois tabela pai.Caso contrário, é provável que o banco de dados que gere um erro porque as regras de integridade referencial impedirão você de excluir um registro pai enquanto ainda existem registros filho relacionados.
Uma regra geral para enviar atualizações para tabelas relacionadas é a seguir nesta ordem:
Tabela filho: excluir registros.
Tabela pai: inserir, atualizar e excluir registros.
Tabela filho: inserir e atualizar registros.
Para mais informações, consulte Passo a passo: Salvando dados em um banco de dados (várias tabelas).
Controle de Concorrência
Como datasets são desconectados da fonte de dados, não mantenha bloqueios em registros na fonte de dados.Portanto, se você deseja atualizar o banco de dados, e se ele for importante para seu aplicativo para manter controle de simultaneidade, você deve reconciliar registros no dataset com aqueles no banco de dados.Por exemplo, você pode localizar registros no banco de dados que foram alterados desde o último preenchimento do dataset.Nesse caso, você deve executar aplicação-apropriada lógica para especificar o que acontece com o registro de banco de dados ou com o registro alterado que você tem em sua dataset.
Consulte também
Tarefas
Como: atualizar dados usando um TableAdapter
Conceitos
Preparando seu aplicativo para receber dados
Buscando dados em seu aplicativo.
Controles de vinculação de dados de Visual Studio
Edição de dados em seu aplicativo.