• Nenhum resultado encontrado

Capítulo V Camada de Persistência

5.3 Mapeamentos

5.3.1 Mapeando objetos para Tabelas

Para permitir a correta persistência de objetos em um banco de dados relacional, algum acordo deve ser feito no tocante à forma como os dados serão armazenados. Existem diversas técnicas que permitem o mapeamento de conjuntos de objetos, cada qual com suas vantagens e desvantagens sobre as demais. Em geral, uma Camada de Persistência implementa uma destas técnicas, de forma que o desenvolvedor de software, ao escolher o mecanismo de persistência com o qual trabalhará, sabe como deve organizar as tabelas em seu banco de dados para suportar o esquema de objetos desejado. No decorrer deste artigo, detalhamos como é feito o mapeamento de cada um dos elementos de um objeto: seus atributos, relacionamentos e classes descendentes (herança).

5.3.2 Mapeando atributos

Ao transpor-se um objeto para uma tabela relacional, os atributos do mesmo são mapeados em colunas da tabela. Este processo de mapeamento deve levar em consideração fatores como a tipagem dos dados (alguns SGBDs podem não suportar tipos binários longos, por exemplo) e o comprimento máximo dos campos (no caso de números e strings). Também é importante lembrar que, em diversos casos, atributos de um objeto não devem ter obrigatoriamente uma coluna em uma tabela que os referencie. Como exemplo, podemos citar o valor total de um pedido:

este dado poderia ser armazenado no objeto para fins de consulta, mas mantê-lo no banco de dados talvez não seja uma idéia tão interessante, por tratar-se de um valor que pode ser obtido através de consultas. Além disso, existem casos onde um atributo pode ser mapeado para diversas colunas (exemplos incluem endereços completos, nome dividido em 'primeiro nome' e 'sobrenome' no banco de dados) ou vários atributos podem ser mapeados para uma mesma coluna (prefixo e número de telefone). As implementações de Camadas de Persistência prevêem, em alguns casos, suporte a este tipo de situação.

5.3.3 Mapeamento de classes em tabelas

O mapeamento de estruturas de classes em tabelas de uma base de dados relacional nem sempre é um processo simples: enquanto alguns acham interessante a adoção de "tabelões" (isto é, tabelas não-normalizadas agrupando dados de diversas entidades) como repositório para os dados, outros preferem ater-se às regras propostas pelas teorias de normalização de bancos de dados relacionais. As três técnicas de mapeamento de objetos mais comumente implementadas (inclusive em Camadas de Persistência) são detalhadas a seguir. É comum a adoção de uma destas técnicas, mesmo quando nenhum tipo de mecanismo de persistência automático é adotado no desenvolvimento.

5.3.4 Mapeamento de uma tabela por hierarquia

Segundo esta estratégia, toda a hierarquia de classes deve ser representada por uma mesma tabela no banco de dados: uma coluna que identifique o tipo do objeto (Object Type) serve para identificar a classe do objeto representado por cada linha na tabela, quando nenhum outro modo de identificação é viável. As desvantagens desta estratégia são evidentes: a ausência de normalização dos

dados fere as regras comuns da teoria de modelagem de dados – além disso, para hierarquias de classes com muitas especializações, a proliferação de campos com valores nulos na maioria das linhas da tabela se torna também um problema potencial.

5.3.5 Mapeamento de uma tabela por classe concreta

Nesta estratégia, tem-se uma tabela no banco de dados para cada classe concreta presente em nosso sistema. A tabela identifica a classe de todos os elementos contidos na mesma, tornando desnecessário o mecanismo de Object Type adotado na estratégia anterior. A estratégia de geração de uma tabela para cada classe concreta leva à redundância de dados: quaisquer atributos definidos em uma classe abstrata na hierarquia devem ser criados em todas as tabelas que representam classes-filhas da mesma. Além disso, mudar o tipo (especializar ou generalizar), um objeto torna-se um problema, já que é necessário transferir todos os seus dados de uma tabela para outra no ato da atualização.

5.3.6 Mapeamento de uma tabela por classe

Na terceira estratégia proposta, cria-se uma tabela para cada classe da hierarquia, relacionadas através do mecanismo de especialização padrão do banco de dados (utilização de chaves estrangeiras). Segundo esta modalidade de mapeamento, tenta-se ao máximo manter a normalização de dados, de forma que a estrutura final das tabelas fica bastante parecida com a hierarquia das classes representada pela UML. A colocação de um identificador de tipo (Object Type) na classe-pai da hierarquia permite identificar o tipo de um objeto armazenado nas tabelas do sistema sem forçar junções entre as tabelas, garantindo melhorias na performance; sendo uma estratégia comumente utilizada. Esta é a técnica que mais naturalmente mapeia objetos para bancos de dados relacionais, de forma que as Camadas de Persistência geralmente forçam a utilização de um esquema de dados que siga esta modalidade de mapeamento. A quantidade de junções (joins) entre tabelas para obter todos os dados de um objeto é o seu principal ponto negativo.

Tabela 1 – Comparativo entre técnicas de mapeamento de classes

Uma tabela por hierarquia de

classes

Uma tabela por classe concreta

Uma tabela por classe

Ad-hoc reporting Simples Médio Médio/Difícil Facilidade de

implementação Simples Médio Difícil

Facilidade de acesso Simples Simples Médio/Simples

Acoplamento Muito alto Alto Baixo

Velocidade de

acesso Rápido Rápido Médio/Rápido

Suporte a

polimorfismos Médio Baixo Alto

A tabela 1 faz um comparativo destas três técnicas quanto à facilidade de consulta a dados interativa (ad-hoc reporting), facilidade implementação, facilidade de acesso aos dados, acoplamento dos dados das classes mapeadas, velocidade de acesso e suporte a polimorfismo.

5.3.7 Mapeamento de Relacionamentos

Os relacionamentos de associação entre objetos são uma das características mais facilmente mapeadas. Conceitualmente, existem apenas três tipos de relacionamentos possíveis – um-para-um, um-para-muitos e muitos-para-muitos.

Relacionamentos um-para-um necessitam que uma chave (foreign key) seja posta em uma das duas tabelas, relacionando o elemento associado na outra tabela.

Dependendo da disposição desta chave estrangeira, podemos definir a navegabilidade do relacionamento (que se dá sempre da tabela que possui a chave estrangeira para a tabela referenciada). Para manter relacionamentos um -para-

muitos, adota-se a mesma técnica: uma referência na forma de chave estrangeira deve ser posta na tabela que contém os objetos múltiplos (lado "n" do relacionamento). No caso de relacionamentos muitos-para-muitos (ou n-para-n), convenciona-se criar uma tabela intermediária que armazene pares de chaves, identificando os dois lados do relacionamento.

Documentos relacionados