Evolução de Esquemas em OODBMS

Autor: Ricardo Shoiti Ikematu - GPT

Resumo

Para descrever a evolução de esquemas em OODBMS (Sistema Gerenciador de Banco de Dados Orientado a Objetos), é necessário mencionar e analisar as regras de integridade do modelo de objetos que o banco tem por referência. Depois são apresentadas diferentes formas de abordagem da implementação destas regras. Por último são apresentados dois aspectos da evolução de esquemas que são pouco estudados: a consistência de métodos e a evolução de instâncias.

1. Visão geral

O ambiente de aplicações orientadas a objeto é caracterizado pela sua flexibilidade e versatilidade, o que causa constantes mudanças de esquemas em aplicações que fazem uso de OODBMS. As primitivas fornecidas pelos bancos relacionais são usadas para modificar relações e seus atributos. A situação é mais complexa em OODBMS, pois o repertório de modificações possíveis é significativamente maior, tanto pelo aumento da complexidade do modelo, quanto pelo fato de que modificações em uma classe podem envolver várias classes. O conceito de hierarquia de herança exige outras operações em complementação aos que são mais significativos no modelo relacional. Evolução de esquemas é um assunto que não tem sido suficientemente investigado, visto que muitos conceitos ainda não foram implementados adequadamente.

Um dos maiores problemas é a inexistência da força de um padrão internacional, como o SQL para os bancos relacionais, para os modelos de objetos de um OODBMS. Apesar da ODMG (Object Database Management Group) definir um padrão conceitual para o modelo de objetos, os fabricantes impõem variações em seus produtos que independem da sua forma de implementação. Este trabalho é baseado na evolução de esquemas do modelo de objetos do ORION, mas grande parte pode ser aplicada genericamente.

Este artigo introduz certas restrições de integridade que garantem que se obtenha evoluções de objetos semanticamente corretos.

2. Regras de integridade de esquema

Quando são executadas modificações em um esquema, as mudanças propostas devem manter um esquema consistente. Regras de integridade são referenciadas como "schema invariants" que traduzi livremente para restrições de esquema.

O conjunto de restrições do esquema definido para o modelo de objetos do ORION são os seguintes:

* Restrição de hierarquia de herança

A hierarquia de herança deve ser um grafo não cíclico e deve ter uma raiz única que é uma classe do sistema de objetos. O grafo deve estar completamente conectado sem nós isolados. Cada nó deve ser acessível da raiz. Cada nó representa uma classe e deve ter um nome diferente.

* Restrição de nomes únicos

Todos os atributos e métodos da classe, sendo da instância ou da classe, devem ter nomes diferentes.

* Restrição de origem única

Todas os métodos e atributos devem ter uma origem distinta. Em outras palavras, uma classe C não pode ter dois atributos e métodos diferentes que têm a sua origem no mesmo atributo e método de uma superclasse de C. Na figura 1, na classe PesquisadorEstudante, o método Idade, embora exista nas duas superclasses Pesquisador em tempo parcial e Estudante, ele tem a mesma origem na classe Pessoa.


Figura 1 – Exemplo de hierarquia de herança

* Restrição de herança completa

Uma classe herda todos os atributos e métodos de cada superclasse, exceto quando a herança completa resulta em violação da restrição de nome único e a restrição de origem única. Portanto:

* Se dois atributos ou métodos têm uma origem diferente mas o mesmo nome em duas superclasses diferentes, pelo menos um destes atributos ou métodos deve ser herdado.

* Se dois atributos ou métodos têm a mesma origem em duas superclasses diferentes, somente um destes atributos ou métodos deve ser herdado.

* Restrição de compatibilidade de domínio

Se um atributo Ai de uma classe C é herdado de um atributo Aj de uma superclasse de C, então o domínio de Ai deve ser o mesmo de Aj ou uma subclasse do domínio de Aj.

Há uma outra restrição para o modelo de base de objetos do GemStone chamada de restrição de preservação de informação, que garante que não há perda de informação. Esta restrição depende especificamente do fato de que não há exclusão explícita e o sistema garante que os valores de variáveis e objetos referenciados por outros objetos são mantidos.

Na definição de mecanismos para modificação de esquema, as regras pelas quais estas modificações são executadas devem ser especificadas de tal forma que as restrições de esquema sejam respeitadas. Estas regras são classificadas em 4 grupos por Banerjee et al.

O primeiro grupo de regras refere-se à resolução de conflitos causados por heranças múltiplas e redefinição de atributos e métodos na subclasse. Qualquer modificação de esquema, tais como a adição de uma superclasse ou a exclusão de um atributo de instância de uma classe, pode resultar em conflitos de herança.

As regras seguintes pertencem ao primeiro grupo:

[S1] Regra de precedência de subclasses sobre superclasses.

Se, em uma classe C, um atributo ou método é definido com o mesmo nome do atributo ou método da superclasse, a definição dada na subclasse tem precedência sobre a definição da superclasse.

[S2] Regra de precedência entre superclasses de uma origem diferente.

Se várias superclasses têm atributos ou métodos com o mesmo nome mas com uma origem diferente, o atributo ou método da primeira superclasse é herdada pela subclasse. No exemplo, a classe PesquisadorEstudante tem duas superclasses (Estudante e Pesquisador em tempo parcial) que têm o mesmo atributo Endereço mas de origens diferentes. Pelo fato de que este atributo é definido diferentemente em duas superclasses e seus domínios não podem ser comparados, este atributo é herdado da primeira superclasse e a definição herdada é a que determina a classe Adr_Office como o domínio do atributo Endereço.

[S3] Regra de precedência entre superclasses de mesma origem.

Se várias superclasses têm atributos ou métodos com o mesmo nome e com a mesma origem, o atributo ou método é herdado somente uma vez. Se o domínio do atributo tem sido redefinido em qualquer superclasse, o atributo com o domínio mais especializado é herdado pela subclasse. Finalmente, se os domínios não podem ser comparados, o atributo é herdado da primeira superclasse.

O segundo grupo de regras refere-se à propagação de modificações para subclasses. Uma modificação que refere-se a um atributo, somente é propagada para aquelas subclasses em que o atributo não tenha sido redefinido. As seguintes regras se aplicam a este grupo:

[P1] Regra de propagação de modificações.

Modificações para um atributo ou método em uma classe são sempre herdadas por uma subclasse, exceto para aquelas subclasses em que o atributo ou método foi redefinido.

[P2] Regra de propagação de modificações em evento de conflitos.

Introduzindo um novo atributo ou método ou a modificação do nome de um atributo ou método é propagado somente para aquelas subclasses em que não há conflitos de nome como resultado da modificação do esquema.

[P3] Regra para modificação de domínios.

O domínio de um atributo pode somente ser modificado por meio de generalização. E o domínio de um atributo herdado não pode ser mais generalizado do que o domínio do atributo original na superclasse.

A regra que controla a propagação de modificações no caso de conflitos (Regra P2 do segundo grupo) tem precedência sobre a Regra S2 do primeiro grupo. Uma classe que herda modificações propaga estas modificações para suas próprias subclasses, embora com as restrições mencionadas nas regras acima. Portanto, estas modificações que não são herdadas de uma classe não são propagadas para as subclasses desta classe.

O terceiro grupo de regras refere-se à agregação e exclusão de relacionamentos entre classes herdadas e a criação e exclusão de classes.

As regras seguintes pertencem a este grupo:

[E1] Regra para inserção de superclasses.

Se uma classe C é adicionada à lista de superclasses de uma classe C’, C torna-se a última das superclasses de C’. Entretanto, qualquer conflito de herança causado pela inserção da classe C é resolvida pelas regras S1, S2 e S3.

[E2] Regra para exclusão de superclasses.

Se uma classe C tem uma única superclasse C’ e C’ é excluída da lista de superclasses de C, então C torna-se uma subclasse direta de cada superclasse direta de C’. A ordem das novas superclasses de C é a mesma das superclasses de C’.

[E3] Regra para inclusão de uma classe em um esquema.

Se nenhuma superclasse é mostrada na definição da classe C, então C torna-se a subclasse da classe OBJECT (raiz de todo o esquema).

[E4] Regra para remover uma classe de um esquema.

A exclusão de uma classe C de um esquema envolve a aplicação da regra E2, desde que C deve ser removido da lista das superclasses de todas as suas subclasses. A classe OBJECT não pode ser excluída.

A classe OBJECT não pode ser excluída da lista de superclasses de uma classe C se a classe OBJECT é a única superclasse de C. Isto garante que o esquema é completamente conectado e não há nós desconectados.

Há uma quarta regra controlando objetos complexos. Se o grupo de regras acima é aplicável genericamente para vários modelos de objetos, este grupo de regras aplica-se somente para aqueles modelos que suportam o conceito de objetos complexos.

[C1] Regra para modificação da definição de atributos complexos.

Um atributo definido como um objeto complexo exclusivo pode ser transformado em um atributo complexo compartilhado ou em objetos não complexos. O inverso não é possível. Um atributo definido como complexo dependente (exclusivo ou compartilhado) pode ser transformado em um atributo complexo independente e vice-versa. A formulação apresentada aqui, refere-se ao modelo extendido de objetos complexos apresentado por Kim et al.

Ao seguir estas regras de integridade, as várias operações de modificações têm diferentes efeitos nos esquemas. De todo o escopo de operações apresentaremos a seguir, segundo uma análise feita por Banerjee et al., somente os efeitos de algumas operações de modificação.

A exclusão de um atributo só poderá ser feita se ele for definido localmente na classe. Não pode haver exclusão de atributos herdados. Esta exclusão deve ser refletida em todas as suas subclasses. Se houver uma superclasse que tenha um atributo com o mesmo nome do excluído, este atributo será herdado desta superclasse.

Ao modificar a ordem das superclasses de uma classe C, a operação resulta em uma completa reavaliação da herança dos atributos e métodos, porque eles podem resultar em uma classe C herdando um atributo A (ou método) de uma superclasse diferente da que ele herdou antes da modificação. A herança deve, portanto, ser reavaliada de acordo com as regras S1, S2 e S3.

Ao excluir uma classe C, a operação tem o efeito de remover C da lista de superclasses de todas suas subclasses. Note que as subclasses de C não são excluídas como em uma integridade referencial do tipo "cascade". A definição de C é excluída e C removido do esquema. Se C é usado como domínio na definição de um atributo A, de qualquer classe C’, A é automaticamente assinalado para a primeira superclasse de C como o novo domínio. Excluindo C resulta na exclusão de todas as suas instâncias. Portanto, todas as referências para estes objetos tornam-se pendentes. Entretanto, em sistemas em que objetos com referências não podem ser excluídos, operações relacionadas à exclusão de classes deveriam ser possível somente se elas não tiverem instâncias, ou se todas as instâncias destas classes não referenciam outros objetos. Finalmente, outra possibilidade é não excluir instâncias; ao invés disto eles poderiam tornar-se instâncias de qualquer outra classe, por exemplo, uma subclasse ou uma superclasse de C.

Considerando, um exemplo de modificação de esquema, a exclusão do método Idade da classe Pessoa (este método não pode ser excluído das subclasses de Pessoa por que um atributo ou método herdado não pode ser excluído). Esta modificação resulta no método em questão sendo excluído de Pessoa e de todas suas subclasses. Se excluirmos o método SalarioMensal da classe Pesquisador, esta modificação não seria propagada para a subclasse Pesquisador em tempo parcial, porque este redefine o método. Se excluirmos o atributo Endereco da classe Pesquisador em tempo parcial, esta modificação resulta na remoção do atributo da classe e de sua subclasse PesquisadorEstudante. Entretanto, desde que a classe PesquisadorEstudante tem outra superclasse que tem um atributo com o mesmo nome e um domínio diferente, o efeito da exclusão é que a classe PesquisadorEstudante herda o atributo Endereco da superclasse Estudante. Um dos efeitos da modificação da classe Pesquisador em tempo parcial é modificar o domínio do atributo Endereco da classe PesquisadorEstudante de Office_Address para Home_Address.

3. Abordagens de implementação

A primeira abordagem que veremos e que chamaremos de abordagem postergada, envolve o adiamento (mesmo que indefinidamente) das modificações destas instâncias. Duas formas de implementar esta abordagem são: o uso de versões de classes e efetivação da modificação no momento de acesso pelas aplicações. No mecanismo de versões de classes é gerada uma nova versão quando houver uma modificação nesta classe. Quando a aplicação tenta ler ou gravar um atributo do objeto que foi criado com uma versão de classe diferente da usada na aplicação, um gerenciador apropriado é ativado, e em muitos casos, executa a transformação apropriada do atributo para a versão correta da classe.

Num segundo mecanismo, baseado na abordagem postergada, as instâncias são modificadas somente quando elas são acessadas pelas aplicações. Se as modificações envolvem exclusão de um atributo da classe, o atributo não é removido das instâncias quando a definição da classe é modificada. Depois, quando uma instância da classe é acessada, o sistema não apresenta o atributo excluído para a aplicação; ele é escondido. Entretanto, se a modificação é uma adição de um atributo, o atributo não é imediatamente adicionado ao objeto. Para cada pedido para ler o atributo, depois da modificação, um valor "default" ou um valor nulo do atributo é retornado. O atributo é efetivamente adicionado depois do primeiro pedido de modificação do valor do atributo. Conseqüentemente, o custo envolvido não é muito mais alto do que uma modificação normal dos valores do atributo.

Outra abordagem, chamada de abordagem imediata, envolve modificação de todas as instâncias em seguida da modificação da definição da classe.

Cada uma das abordagens tem suas vantagens e desvantagens. A vantagem da abordagem postergada, é que a modificação não é cara. Entretanto, o acesso a instâncias demora mais por causa do tratamento dos atributos. A abordagem imediata torna as operações de modificações muito caras. Há pesquisas contínuas em combinar estas duas abordagens em um mecanismo flexível que permitiria o seu uso de acordo com a situação.

Outras abordagens que capacitam OODBMS a suportar modificações de esquemas incluem o uso de versões de esquemas (Kim e Chou) e visões orientadas a objetos (Bertino). Estas abordagens diferem das abordagens descritas anteriormente de forma que os esquemas antigos não são substituídos pelo esquema modificado. Ao invés disto, há dois esquemas; um é o esquema original e o outro reflete modificações executadas no original. Várias modificações podem produzir uma seqüência de versões posteriores do esquema ou visões diferentes do esquema. Uma diferença essencial entre usar versões de esquema e visões é que adotando a abordagem de versões, um objeto criado em uma versão de esquema específica somente é visível naquela versão de esquema específica, se adotar uma abordagem de visões, um objeto é visível em todas as visões, se as condições para pertencer a este são encontradas. Mecanismos de visão desenvolvidos para bancos relacionais devem ser estendidos para suportar evolução de esquema. Uma destas extensões consiste de visões que adicionam atributos e métodos em complementação daqueles recebidos das classes em que eles são definidos. Deve ser possível acessar instâncias das visões com OID ou "queries". Uma vantagem de usar visões ao invés de modificar diretamente o esquema é que não há perda de informação. Se a modificação do esquema for insatisfatória, o esquema original pode sempre ser retornado sem perda de qualquer informação. Por exemplo, se um atributo é excluído da classe, todas suas instâncias perderão o atributo. Mas uma visão pode ser definida e mostrar todos os atributos exceto aquele que foi removido. O esquema original não sofre qualquer modificação e os valores do atributo não são perdidos.

4. Consistência de métodos

A consistência de modificações dos métodos é um problema significativo na evolução de esquema. O tratamento das evoluções de esquema descrito nas seções anteriores refere-se somente aos componentes estruturais do esquema, as classes e suas organizações em termos de hierarquia de herança e de agregação. Outro tipo de consistência que deveria ser observado é o que refere-se aos aspectos dinâmicos de objetos. Por exemplo, se um atributo é excluído ou modificado, um método referindo este atributo em sua implementação não deveria ser mais consistente em termos de esquema atual. Uma solução é recompilar o esquema inteiro e seus métodos. Esta solução pode ser cara se esquemas são freqüentemente modificados e ela pode ser aplicada somente em sistemas usando compilação. Para sistemas baseados em interpretação, inconsistência de métodos relacionados a modificações do esquema pode resultar em erros de tipo do atributo. E se não tiver erros de tipo, as modificações de esquema podem resultar em acionamento de métodos semanticamente incorretos.

Em geral não há soluções que podem ser aplicadas genericamente. Isto se deve ao fato que métodos são freqüentemente implementados em linguagens de programação imperativas, e não é fácil determinar os efeitos da modificação do esquema para o conjunto de métodos das classes envolvidas na modificação. Uma possível solução, proposta por Coen-Porisini et al. é usar um conjunto de ferramentas interativas que quando um esquema é modificado, pode mostrar os efeitos da modificação para o usuário e sugerir modificações alternativas se ocorrerem inconsistências.

5. Evolução de instâncias

O modelo orientado a objetos introduz tipos diferentes de evolução para objetos, em que objetos individuais podem modificar sua própria estrutura e comportamento, mantendo sua identificação constante. Uma estrutura e/ou comportamento de um objeto pode ser modificado com:

* Migrações do objeto para classes diferentes;
* A adição dinâmica de classes, aquelas não relacionadas por herança;
* Especialização de instâncias.

A migração de um objeto para uma nova classe é diferente da adição de uma nova classe para aquele objeto. No primeiro caso, a classe a que a instância pertencia previamente é perdida, no segundo caso, não. Neste caso, um objeto deve ser capaz de ser a instância de várias classes ao mesmo tempo. Estes tipos de evolução ainda não são suportados por muitos sistemas, porque eles criam problemas de implementação e consistência. Se um objeto é capaz de migrar para diferentes classes ou para adquirir e perder classes dinamicamente, restrições apropriadas devem ser impostas para garantir que evoluções corretas sejam definidas. Por exemplo, é significativo para um estudante tornar-se um pesquisador na vida, mas não tornar-se uma instância da classe documento.

Zdonik especificou restrições de integridade especiais:

* Especificando classes como essencial.

Uma classe C, é essencial se um objeto que é membro da classe C não pode, em um ponto subseqüente no tempo, migrar para outra classe e parar de pertencer ao conjunto de membros da classe C. Isto significa que migrações de um objeto que é um membro de C são confinadas à hierarquia de herança que tem C como sua raiz. Um objeto pode ter várias classes essenciais se o modelo permite herança múltipla.

* Especificando classes como exclusiva.

Uma classe é exclusiva se pertence a uma classe como uma instância e exclui sua habilidade de pertencer a outra classe.

O fato de uma classe ser essencial não implica em ser exclusiva. Uma classe essencial C pode ser adicionada a um objeto O, mesmo que o objeto já tenha classes essenciais. A única restrição é que O não pode perder mais tarde C. Pelo outro lado, um objeto pode perder uma classe exclusiva.

A migração de objetos pode causar problemas de domínio. Se um determinado objeto faz parte de um atributo em um objeto complexo, a simples migração de classe, mesmo que na hierarquia de herança, causará uma violação da restrição de integridade estabelecida pela especificação do domínio deste atributo.

REFERÊNCIA BIBLIOGRÁFICA

[1] BERTINO, E.; MARTINO, L. Object-oriented database systems: concepts and architectures. Wokingham: Addison-Wesley, 1993.