domingo, 26 de dezembro de 2010

Dynamic table mapping - Hibernate


Ao longo dos anos se tornou comum utilizar frameworks ORM na construção de softwares que necessitem armazenar informações, esse tipo de framework facilita a manipulação dos dados fornecendo muitos recursos como: controle da conexão, transação, sessão, desacoplamento com as particularidades dos SGBD's, entre outros.

No meu caso, estou utilizando JAVA + Hibernate sendo o mapeamento entre classes/tabelas feito por XML e Annotations, porém nesse software eu precisei mapear a mesma classe para tabelas diferentes durante a execução, ou seja, eu precisei alterar o mapeamento dinamicamente. Junto da equipe a primeira idéia que surgiu foi alterar o xml de configuração (hibernate.cfg.xml), o que não fazia nenhum sentido pois teríamos que ao final da execução, retornar a configuração inicial. 

A partir daí o raciocínio foi simples, em algum momento o Hibernate tem que carregar o mapeamento para algum dos seus objetos e de alguma forma ele deve expor essa “facilidade”. Após algum tempo para a busca, não encontramos nada que resolvesse algo que é aparentemente simples: “Se estamos trabalhando com um framework de mapeamento objeto-relacional, nada mais óbvio que a necessidade de alterar o mapeamento em tempo de execução”.

Eu acredito que sempre que esse tipo de coisa acontece, o jeito é forçar a solução e como diria meu pai: “a necessidade faz o ladrão”, abrimos o código do Hibernate 3.5.6 para entender as estruturas de mapeamento. Realmente o Hibernate é muito bem construído é não deixou a galera na mão, encontramos uma classe interna da org.hibernate.cfg.Configuration, que implementa a Mappings, a partir dessa classe conseguimos fazer nosso dynamic table mapping.

Segue abaixo a parte mais importante do post, o exemplo:

// instancia o org.hibernate.cfg.Configuration
conf = new AnnotationConfiguration();
//carrega o hibernate.cfg.xml
conf.configure();
// carrega o mapeamento class-entity/table
conf.buildMappings();
// cria o manipulador de mappings
Mappings mps = conf.createMappings();
// Exemplo de alteração do mapeamento
Table t = mps.getTable(null, null, "tabela_antiga");
t.setName("tabela_nova");


Vale lembrar que após a alteração do mapeamento um novo SessionFactory deve ser criado, assim como os objetos que são criados a partir dele (Session, Transaction, etc). Espero que esse post ajude as outras pessoas que como nós não encontraram essa "simples" resposta, nem na documentação do Hibernate.

Observação: Como o mapeamento está sendo alterado direto no código, é importante lembrar que essa estrutura deve existir no banco de dados, caso não exista também é possível criá-la pelo Hibernate, mas  essa questão não faz parte desse post.

Referência: Documentação Hibernate - 2.Arquitetura