Diretriz: Bancos de Dados Relacionais de Engenharia Reversa
Esta diretriz descreve as etapas envolvidas em reverter a engenharia de um banco de dados e mapear as tabelas resultantes do Modelo de Dados para as Classes de Design no Modelo de Design.
Relacionamentos
Elementos Relacionados
Descrição Principal

Introdução

Esta diretriz descreve as etapas envolvidas em reverter a engenharia de um banco de dados e mapear as tabelas resultantes do Modelo de Dados para as Classes de Design no Modelo de Design. Esse processo pode ser utilizado pelo Designer de Banco de Dados para ocasionar o desenvolvimento de modificações no banco de dados como parte de um ciclo de desenvolvimento evolutivo. O Designer de Banco de Dados precisará gerenciar o processo de engenharia reversa em todo o ciclo de vida de desenvolvimento do projeto. Em muitos casos, o processo de engenharia reversa é desempenhado logo no início do ciclo de vida do projeto e, depois, as alterações no design de dados são gerenciadas de modo incremental, sem a necessidade de desempenhar a engenharia reversa subseqüente do banco de dados.

As principais etapas no processo para reverter a engenharia de um banco de dados e transformar os elementos resultantes do Modelo de Dados em elementos do Modelo de Design são mostradas a seguir:

  • Crie um Modelo de Dados físico que contenha tabelas para representar o layout físico de dados persistentes no banco de dados. Esta etapa pode ser desempenhada automaticamente utilizando as ferramentas fornecidas com o RDBMS (Relational Database Management) ou por meio das ferramentas mais modernas de modelagem visual.
  • Transforme as tabelas no Modelo de Dados físico em Classes de Design no Modelo de Design. Esta etapa pode ser desempenhada por uma combinação de suporte a ferramentas automatizadas para a transformação inicial, seguida por ajustes manuais.
  • Defina associações entre as classes no Modelo de Design.
  • Defina operações apropriadas nas classes do Modelo de Design com base nas ações executadas nos elementos correspondentes do Modelo de Dados.
  • Agrupe as classes do Modelo de Design em subsistemas e pacotes, conforme necessário.

Engenharia Reversa do Banco de Dados RDBMS ou do Script DDL para Gerar um Modelo de Dados

O processo de engenharia reversa do banco de dados ou do script DDL (Data Definition Language) geralmente apresenta um conjunto de elementos de modelo (tabelas, visualizações, procedimentos armazenados, etc.) . Dependendo da complexidade do banco de dados, o designer de banco de dados pode precisar particionar os elementos do modelo da engenharia reversa em pacotes de áreas de assunto que contêm conjuntos logicamente relacionados de tabelas.

Transformando o Modelo de Dados em Modelo de Design

O procedimento a seguir pode ser utilizado para produzir Classes de Design a partir dos elementos de modelo no Modelo de Dados. A replicação da estrutura do banco de dados em um modelo de classe é um procedimento relativamente simples. O processo listado a seguir descreve o algoritmo para transformar os elementos do Modelo de Dados em elementos do Modelo de Design.

A tabela a seguir mostra um resumo do mapeamento geral entre os elementos do Modelo de Design e os elementos do Modelo de Dados.

Elemento do Modelo de Dados 

Elemento do Modelo de Design Correspondente 

Tabela  Classe 
Coluna  Atributo 

Relacionamento sem Identificação 

Associação 

Tabela de Interseção

 

Classe de Associação

Associação de Muitos-para-Muitos

Associação Qualificada 

Relacionamento de Identificação 

Agregação 

Cardinalidade 

 

Multiplicidade 

 
Restrição de Verificação com uma cláusula enumerada  Classe <<ENUM>> 
Esquema  Pacote 

Há alguns elementos de modelo no Modelo de Dados que não possuem correlação direta no Modelo de Design. Esses elementos incluem os Espaços de Tabelas e o próprio Banco de Dados, que modelam as características de armazenamento físico do banco de dados e são representados como componentes. Um outro item é a visualização do banco de dados, que é uma tabela "virtual" e não tem significado no Modelo de Design.  Por último, índices em chaves principais de tabelas e funções do acionador do banco de dados, que são utilizados para otimizar a operação do banco de dados, têm significado apenas no contexto do banco de dados e do Modelo de Dados.

Transformar uma Tabela em uma Classe

Para cada tabela que você deseja transformar, crie uma classe para representar a tabela. Para cada coluna, crie um atributo na classe com o tipo de dado apropriado. Tente fazer a correspondência mais aproximada possível entre o tipo de dado do atributo e o tipo de dado da coluna associada.

Exemplo

Considere a tabela de banco de dados Cliente, com a estrutura mostrada na figura a seguir:

Nome da Coluna Tipo de Dados
ID_do_Cliente Número
Nome Varchar
Rua Varchar
Cidade Varchar
Estado/Província Char(2)
CEP Varchar
País Varchar

Definição da tabela Cliente

A partir deste ponto, criamos uma classe, Cliente, com a estrutura mostrada na figura a seguir:

Definição da classe Cliente

Classe Cliente inicial

Nesta classe Cliente inicial, há um atributo para cada coluna na tabela Cliente. Cada atributo possui visibilidade pública, já que qualquer coluna da tabela de origem pode ser consultada.

Observe que o ícone "+" listado à esquerda do atributo indica que o atributo é 'público'; por padrão, todos os atributos derivados das tabelas RDBMS devem ser públicos, pois o RDBMS geralmente permite que qualquer coluna seja consultada sem restrição.

Identificar Classes Incorporadas ou Implícitas

Geralmente, a classe que resulta do mapeamento direto das classes de tabela contém atributos que podem ser separados em uma outra classe, principalmente nos casos em que os atributos aparecerem em várias classes convertidas. Esses 'atributos repetidos' podem resultar de uma desnormalização das tabelas, por razões de desempenho, ou de um Modelo de Dados muito simplificado. Nesses casos, divida a classe correspondente em duas ou mais classes para representar uma visão normalizada das tabelas.

Exemplo

Depois de definir a classe Cliente anterior, é possível definir uma classe Endereço que contenha todas as informações de endereço (considerando que haverá outros endereços no sistema), resultando nas classes a seguir:

Diagrama descrito no texto associado.

Classe Cliente revisada, com classe Endereço extraída

A associação dessas duas classes resulta em uma agregação, já que o endereço do cliente pode ser considerado como parte do cliente.

Manipular Relacionamentos de Chave Estrangeira

Para cada relacionamento de chave estrangeira da tabela, crie uma associação entre as classes associadas, removendo o atributo da classe mapeada para a coluna de chave estrangeira. Se a coluna de chave estrangeira tiver sido representada inicialmente como um atributo, remova-a da classe.

Exemplo

Considere a estrutura da tabela Pedido listada a seguir:

Nome da Coluna  Tipo de Dados 
Número  Número 
ID_do_Cliente  Varchar 

Estrutura da tabela Pedido

Na tabela Pedido listada anteriormente, a coluna ID_do_Cliente é uma referência de chave estrangeira; esta coluna contém o valor da chave principal do Cliente associado ao Pedido. Essa representação é mostrada a seguir no Modelo de Design:

Diagrama UML descrito a seguir.

Representação dos relacionamentos de chave estrangeira no modelo de design

A chave estrangeira é representada como uma associação entre as classes Pedido e Item.

Manipular Relacionamentos de Muitos-para-Muitos

Os modelos de dados RDBMS representam relacionamentos de muitos-para-muitos que foram chamados de tabela de junção ou tabela de associação. Essas tabelas permitem que esses relacionamentos sejam representados através de uma tabela intermediária, contendo as chaves primárias de duas tabelas diferentes que podem ser associadas. As tabelas de junção são necessárias porque uma referência de chave estrangeira pode conter apenas uma referência a um único valor de chave estrangeira. Quando uma única linha puder ser relacionada a várias outras linhas de uma tabela diferente, a tabela de junção será necessária para associá-las.

Exemplo

Considere o caso de Produtos, que podem ser fornecidos por qualquer um dos diversos Fornecedores, e de qualquer Fornecedor que possa fornecer fornecer qualquer número de Produtos. As tabelas Produto e Fornecedor possuem a estrutura definida a seguir:

Tabela de Produtos
Nome da Coluna Tipo de Dados
ID_do_Produto Número
Nome Varchar
Descrição Varchar
Preço Número
Tabela de Fornecedores
Nome da Coluna Tipo de Dados
ID_do_Fornecedor Número
Nome Varchar
Rua Varchar
Cidade Varchar
Estado/Província Char(2)
CEP Varchar
País Varchar

Definições das Tabelas Produtos e Fornecedores

Para vincular essas duas tabelas e localizar os produtos oferecidos por um determinado fornecedor, é necessária uma tabela Produto-Fornecedor, definida na tabela a seguir.

Tabela de Produto-Fornecedor
Nome da Coluna  Tipo de Dados 
ID_do_Produto  Número 
ID_do_Fornecedor  Número 

Definição da Tabela Produtos-Fornecedores

Esta tabela de junção contém as chaves primárias de produtos e fornecedores, vinculando-os. Uma linha na tabela indicaria que um fornecedor específico oferece um determinado produto. Todas as linhas cuja coluna ID_do_Fornecedor correspondesse a uma identificação específica de fornecedor forneceriam uma listagem de todos os produtos oferecidos por esse fornecedor.

No Modelo de Design, essa tabela intermediária é redundante pois um modelo de objeto pode representar diretamente as associações muitos-para-muitos. As classes Fornecedor e Produto e seus relacionamentos são mostrados na figura a seguir, juntamente com a classe Endereço, que é extraída do Fornecedor, de acordo com a discussão anterior.

Diagrama UML descrito em legenda.

Representação das Classes Produtos e Fornecedores

Introduzir a Generalização

Geralmente, algumas tabelas terão uma estrutura semelhante. No Modelo de Dados, não há conceito de generalização, portanto não há como representar duas ou mais tabelas com alguma estrutura em comum. Algumas vezes, uma estrutura comum resulta de uma desnormalização de desempenho, como o caso anterior em que a tabela Endereço, extraída em uma classe separada, está 'implícita'. Nos outros casos, as tabelas compartilham características mais fundamentais que podem ser extraídas em uma classe pai generalizada com duas ou mais subclasses. Para localizar oportunidades de generalização, procure por colunas repetidas em várias tabelas, em que as tabelas têm mais semelhanças do que diferenças.

Exemplo

Considere as tabelas, SoftwareProduct e HardwareProduct, mostradas a seguir:

Tabela de Produtos de Software
Nome da Coluna  Tipo de Dados 
ID_do_Produto  Número 
Nome  Varchar 
Descrição  Varchar 
Preço  Número 
Versão  Número 
Tabela de Produtos de Hardware
Nome da Coluna  Tipo de Dados 
ID_do_Produto  Número 
Nome  Varchar 
Descrição  Varchar 
Preço  Número 
Versão  Número 


Tabelas SoftwareProduct e HardwareProduct

Observe que as colunas destacadas em azul são idênticas; essas duas tabelas compartilham a maior parte de suas definições em comum e diferem somente um pouco. Podemos representar isso extraindo uma classe Produto comum, com SoftwareProduct e HardwareProduct como subclasses do Produto, conforme mostrado na figura a seguir:

Diagrama descrito no texto associado.

Classes SoftwareProduct e HardwareProduct, mostrando uma generalização da classe Produtos

A figura a seguir, que reúne todas as definições de classe, mostra um diagrama de classes consolidado para o sistema Entrada de Pedidos (somente as classes principais).

Diagrama UML complexo descrito no texto associado.

Diagrama de Classes Consolidado para o Sistema Entrada de Pedidos

Replicando o Comportamento do RDBMS no Modelo de Design

Replicar um comportamento é um procedimento mais difícil, pois geralmente os bancos de dados relacionais não são orientados a objetos e não parecem ter nada semelhante às operações em uma classe no modelo de objeto. Os passos a seguir podem ajudar a reconstruir o comportamento das classes identificadas acima:

  1. Criar operações para obter e configurar cada atributo. É necessário encontrar uma maneira de configurar, alterar e consultar os valores dos atributos de objetos. Como a única maneira de acessar os atributos de um objeto é através de operações fornecidas pela classe, essas operações devem ser definidas na classe. Ao criar as operações que definirão o valor de um atributo, verifique se incorporou todas as restrições de validação que possam ser operadas na coluna associada. Se não houver restrições de validação, você poderá optar por simplesmente representar o fato de que os atributos podem ser obtidos e configurados, marcando-os como tendo visibilidade "pública", como isso foi feito nos diagramas anteriores (com o ícone à esquerda do nome do atributo).
  2. Criar uma operação na classe para cada procedimento armazenado que opera na tabela associada Os procedimentos armazenados são sub-rotinas executáveis que são executadas no próprio DBMS. Essa lógica precisa ser convertida no Modelo de Design. Se um procedimento armazenado operar apenas em uma classe, crie uma operação na classe com os mesmos parâmetros e o mesmo tipo de retorno do procedimento armazenado. Documente o comportamento do procedimento armazenado na operação, certificando-se de anotar na descrição do método que a operação é implementada pelo procedimento armazenado.
  3. Criar operações para gerenciar associações entre classes. Quando há uma associação entre duas classes, é necessário que haja uma maneira de criar, gerenciar e remover associações. As associações entre os objetos são gerenciadas por meio de referências dos objetos. Portanto, para criar uma associação entre um Pedido e um LineItem (isto é, incluir o LineItem no Pedido), uma operação seria chamada em Pedido, transmitindo o LineItem como um argumento (isto é, Order.add(aLineItem)). É necessário que também haja maneiras de remover e atualizar a associação (isto é, Order.remove(aLineItem) e Order.change(aLineItem,aNewLineItem)).
  4. Manipular a Exclusão de Objetos. Se o idioma de destino suportar a exclusão explícita, inclua o comportamento no destrutor da classe que implementará a verificação de integridade referencial. Nos casos em que houver restrições de integridade referencial no banco de dados, como exclusão em cascata, o comportamento precisará ser replicado nas classes apropriadas. Por exemplo, o banco de dados pode definir uma restrição que determine que sempre que um Pedido é excluído, todos os LineItems associados também devem ser excluídos. Se o idioma de destino suportar coleta de lixo, crie um mecanismo que permita remover linhas de tabelas quando o objeto associado for coletado para a lixeira. Observe que isso é mais difícil do que parece (e mesmo assim parece difícil), pois será necessário implementar um mecanismo que assegure que nenhum cliente de banco de dados tenha qualquer referência ao objeto que será coletado para a lixeira. Não basta depender dos recursos de coleta de lixo do ambiente de execução/máquina virtual; essa é uma visão simplista do cliente de perceber o mundo.
  5. Manipular o Comportamento Imposto por Consultas. Examine as instruções Select que acessam a tabela para verificar como as informações são recuperadas e manipuladas. Para cada coluna diretamente retornada por uma instrução Select, configure a propriedade public do atributo associado como true; todos os outros atributos devem ser private. Para cada coluna calculada em uma instrução Select, crie uma operação na classe associada para calcular e retornar o valor. Ao considerar as instruções Select, inclua também as instruções Select incorporadas nas definições View.

Organizar Elementos no Modelo de Design

As Classes de Design criadas a partir das transformações de tabela em classe devem ser organizadas em pacotes de design e/ou subsistemas de design apropriados no Modelo de Design, conforme necessário, com base na estrutura arquitetural geral do aplicativo. Consulte Conceito: Divisão em Camadas e Conceito: Arquitetura de Software para uma visão geral da arquitetura do aplicativo.