Partilhar via


Atualização hierárquica no desenvolvimento do .NET Framework

Observação

Os conjuntos de dados e as classes relacionadas são tecnologias herdadas do .NET Framework do início dos anos 2000 que permitem que os aplicativos trabalhem com dados na memória enquanto os aplicativos estão desconectados do banco de dados. Eles são bastante úteis em aplicativos que permitem que os usuários modifiquem dados e persistam as alterações no banco de dados. Embora os conjuntos de dados tenham se mostrado uma tecnologia muito bem-sucedida, é recomendado que os novos aplicativos .NET usem o Entity Framework Core. O Entity Framework proporciona uma forma mais natural de trabalhar com dados tabulares como modelos de objeto e conta com uma interface de programação mais simples.

Atualização hierárquica refere-se ao processo de salvar dados atualizados (de um conjunto de dados com duas ou mais tabelas relacionadas) de volta a um banco de dados mantendo regras de integridade referencial. Integridade referencial refere-se às regras de consistência fornecidas pelas restrições em um banco de dados que controlam o comportamento de inserção, atualização e exclusão de registros relacionados. Por exemplo, é a integridade referencial que impõe a criação de um registro de cliente antes de permitir que pedidos sejam criados para esse cliente. Para obter mais informações sobre relações em conjuntos de dados, consulte Relações em conjuntos de dados.

O recurso de atualização hierárquica usa um TableAdapterManager para gerenciar os TableAdapters em um conjunto de dados tipado. O componente TableAdapterManager é uma classe gerada pelo Visual Studio, não um tipo .NET. Quando você arrasta uma tabela da janela Fontes de Dados para uma página do Windows Form ou WPF, o Visual Studio adiciona uma variável do tipo TableAdapterManager ao formulário ou página e você a vê no designer, na bandeja de componentes. Para obter informações detalhadas sobre a classe TableAdapterManager, consulte a seção Referência de tableAdapterManager de TableAdapters.

Por padrão, um conjunto de dados trata tabelas relacionadas como "somente relações", o que significa que ele não impõe restrições de chave estrangeira. Você pode modificar essa configuração em tempo de design usando o Designer de Conjunto de Dados. Selecione a linha de relação entre duas tabelas para abrir a caixa de diálogo Relação. As alterações feitas aqui determinarão como o TableAdapterManager se comporta ao enviar as alterações nas tabelas relacionadas de volta ao banco de dados.

Habilitar a atualização hierárquica em um conjunto de dados

Por padrão, a atualização hierárquica é habilitada para todos os novos conjuntos de dados adicionados ou criados em um projeto. Ative ou desative a atualização hierárquica definindo a propriedade Atualização Hierárquica de um conjunto de dados tipado no conjunto de dados como True ou False:

Configuração da atualização hierárquica

Criar uma relação entre tabelas

Para criar uma relação entre duas tabelas, no Designer de Conjunto de Dados, selecione a barra de título de cada tabela, clique com o botão direito do mouse e selecione Adicionar relação.

Menu Adicionar relação da atualização hierárquica

Entender restrições de chave estrangeira, atualizações em cascata e exclusões

É importante entender como as restrições de chave estrangeira e o comportamento em cascata no banco de dados são criados no código do conjunto de dados gerado.

Por padrão, as tabelas de dados em um conjunto de dados são geradas com relações (DataRelation) que correspondem às relações no banco de dados. No entanto, a relação no conjunto de dados não é gerada como uma restrição de chave estrangeira. O DataRelation é configurado como Somente Relação, sem UpdateRule ou DeleteRule em vigor.

Por padrão, atualizações e exclusões em cascata são desativadas mesmo que a relação de banco de dados esteja definida com as atualizações ou exclusões em cascata ativadas. Por exemplo, criar um cliente e um pedido e tentar salvar os dados pode causar um conflito com as restrições de chave estrangeira definidas no banco de dados. Para obter mais informações, confira Desativar restrições ao preencher um conjunto de dados.

Definir a ordem de execução de atualizações

Definir a ordem de execução de atualizações define a ordem das inserções, atualizações e exclusões individuais necessárias para salvar todos os dados modificados em todas as tabelas de um conjunto de dados. Quando a atualização hierárquica está habilitada, as inserções são executadas primeiro, depois as atualizações e, em seguida, as exclusões. O TableAdapterManager fornece uma propriedade UpdateOrder que pode ser definida para executar atualizações primeiro, depois inserções e depois exclusões.

Observação

É importante entender que a ordem de atualização é inclusiva. Ou seja, quando atualizações são executadas, inserções e exclusões são executadas para todas as tabelas no conjunto de dados.

Para definir a propriedade UpdateOrder depois de arrastar itens da Janela Fontes de Dados para um formulário, selecione o TableAdapterManager na bandeja de componentes e defina a propriedade UpdateOrder na janela Propriedades.

Criar uma cópia de backup de um conjunto de dados antes de executar uma atualização hierárquica

Quando você salva dados (chamando o método TableAdapterManager.UpdateAll()), o TableAdapterManager tenta atualizar os dados de cada tabela em uma só transação. Se qualquer parte da atualização de qualquer tabela falhar, toda a transação será revertida. Na maioria das situações, a reversão retorna o aplicativo para seu estado original.

No entanto, às vezes, você pode querer restaurar o conjunto de dados da cópia de backup. Um exemplo disso pode ocorrer quando você está usando valores de incremento automático. Por exemplo, se uma operação de salvamento não for bem-sucedida, os valores de incremento automático não serão redefinidos no conjunto de dados e o conjunto de dados continuará criando valores de incremento automático. Isso deixa uma lacuna na numeração que pode não ser aceitável em seu aplicativo. Em situações em que isso é um problema, o TableAdapterManager fornece uma propriedade BackupDataSetBeforeUpdate que substitui o conjunto de dados existente por uma cópia de backup quando a transação falha.

Observação

A cópia de backup fica apenas na memória enquanto o método TableAdapterManager.UpdateAll está em execução. Portanto, não há acesso programático a esse conjunto de dados de backup, porque ele substitui o conjunto de dados original ou sai do escopo assim que o método TableAdapterManager.UpdateAll termina de ser executado.

Modificar o código de salvamento gerado para executar a atualização hierárquica

Salve as alterações das tabelas relacionadas de dados no conjunto de dados para o banco de dados chamando o método TableAdapterManager.UpdateAll e passando no nome do conjunto de dados que contém as tabelas relacionadas. Por exemplo, execute o método TableAdapterManager.UpdateAll(NorthwindDataset) para enviar atualizações de todas as tabelas no NorthwindDataset para o banco de dados back-end.

Depois de soltar os itens da janela Fontes de Dados, o código é automaticamente adicionado ao evento Form_Load para preencher cada tabela (os métodos TableAdapter.Fill). O código também é adicionado ao evento de clique do botão Salvar do BindingNavigator para salvar os dados do conjunto de dados de volta ao banco de dados (o método TableAdapterManager.UpdateAll).

O código salvar gerado também contém uma linha de código que chama o método CustomersBindingSource.EndEdit. Mais especificamente, ele chama o método EndEdit do primeiro BindingSource adicionado ao formulário. Ou seja, esse código é gerado apenas para a primeira tabela arrastada da janela Fontes de Dados para o formulário. A chamada EndEdit confirma as alterações que estão em processo em qualquer controle de associação de dados sendo editado no momento. Portanto, se um controle associado a dados ainda estiver em foco e você clicar no botão Salvar, todas as edições pendentes nesse controle serão confirmadas antes da gravação real (o método TableAdapterManager.UpdateAll).

Observação

O Designer de Conjunto de Dados só adiciona o código BindingSource.EndEdit para a primeira tabela arrastada para o formulário. Portanto, é necessário adicionar uma linha de código para chamar o método BindingSource.EndEdit para cada tabela relacionada no formulário. Para este passo a passo, isso significa que você precisa adicionar uma chamada ao método OrdersBindingSource.EndEdit.

  1. Clique duas vezes no botão Salvar no BindingNavigator para abrir Form1 no Editor de Códigos.

  2. Adicione uma linha de código para chamar o método OrdersBindingSource.EndEdit após a linha que chama o método CustomersBindingSource.EndEdit. O código no evento de clique do botão Salvar deve ser semelhante ao seguinte:

    this.Validate();
    this.customersBindingSource.EndEdit();
    this.ordersBindingSource.EndEdit();
    this.tableAdapterManager.UpdateAll(this.northwindDataSet);
    

Além de confirmar as alterações em uma tabela filho relacionada antes de salvar dados em um banco de dados, você também pode confirmar registros pais recém-criados antes de adicionar novos registros filhos a um conjunto de dados. Em outras palavras, pode ser necessário adicionar o novo registro pai (Customer) ao conjunto de dados antes que as restrições de chave estrangeira permitam que novos registros filho (Orders) sejam adicionados ao conjunto de dados. Para realizar isso, você pode usar o evento filho BindingSource.AddingNew.

Observação

A necessidade de confirmar novos registros pai depende do tipo de controle usado para associar à sua fonte de dados. Neste passo a passo, você usa controles individuais para associar à tabela pai. Isso requer o código adicional para confirmar o novo registro pai. Se os registros pai foram exibidos em um controle de associação complexa como o DataGridView, essa chamada EndEdit adicional para o registro pai não seria necessária. Isso porque a funcionalidade subjacente de associação de dados do controle processa a confirmação dos novos registros.

Para adicionar código para confirmar registros pais no conjunto de dados antes de adicionar novos registros filhos

  1. Crie um manipulador de eventos para o evento OrdersBindingSource.AddingNew.

    • Abra Form1 na exibição de design, selecione OrdersBindingSource na bandeja de componentes, selecione Eventos na janela Propriedades e clique duas vezes no evento AddingNew.
  2. Adicione uma linha de código ao manipulador de eventos que chama o método CustomersBindingSource.EndEdit. O código no manipulador de eventos OrdersBindingSource_AddingNew deve ser semelhante ao seguinte:

    this.customersBindingSource.EndEdit();
    

Referência de TableAdapterManager

Por padrão, uma classe TableAdapterManager é gerada quando você cria um conjunto de dados que contém tabelas relacionadas. Para impedir que a classe seja gerada, altere o valor da propriedade Hierarchical Update do conjunto de dados para false. Quando você arrasta uma tabela que tem uma relação para a superfície de design de uma página do Windows Form ou WPF, o Visual Studio declara uma variável de membro da classe. Se você não usa a vinculação de dados, precisa declarar a variável manualmente.

A classe TableAdapterManager não é um tipo .NET. Portanto, você não pode pesquisá-la na documentação. Ela é criada em tempo de design como parte do processo de criação do conjunto de dados.

Estes são os métodos e as propriedades da classe TableAdapterManager usados com frequência:

Membro Descrição
Método UpdateAll Salva todos os dados de todas as tabelas de dados.
Propriedade BackUpDataSetBeforeUpdate Determina se é necessário criar uma cópia de backup do conjunto de dados antes de executar o método booliano TableAdapterManager.UpdateAll.
Propriedade tableNameTableAdapter Representa um TableAdapter. O TableAdapterManager gerado contém uma propriedade para cada TableAdapter que gerencia. Por exemplo, um conjunto de dados com uma tabela Clientes e Pedidos é gerado com um TableAdapterManager que contém as propriedades CustomersTableAdapter e OrdersTableAdapter.
Propriedade UpdateOrder Controla a ordem dos comandos de inserção, atualização e exclusão individuais. Defina como um dos valores na enumeração TableAdapterManager.UpdateOrderOption.

Por padrão, o UpdateOrder é definido como InsertUpdateDelete. Isso significa que inserções, atualizações e exclusões são executadas para todas as tabelas no conjunto de dados.