Esses dias me peguei pensando em um costume interessante que temos. Quando digo “nós”, falo de min e das pessoas com as quais já trabalhei nesses 4 anos que atuo com .NET. Fomos acostumados, em se tratando de persistência em banco de dados, de sempre utilizar modelo relacional pra qualquer tipo de armazenamento de objeto. O problema é que nem sempre isso é necessário e acabamos perdendo ou tempo em codificação ou desempenho ou espaço em disco.
A idéia de banco de dados orientado a objetos sempre me agradou e acho uma pena não ter chegado ao mainstream. No entanto o conceito de armazenar o grafo todo de objetos é muito interessante em algumas situações. Vou usar um exemplo que talvez não seja o melhor, mas deve passar a idéia.
Imagine um cadastro de cliente com diversas entidades relacionadas: diversos endereços, vários telefones para contato, dependentes, etc.
Normalmente criaríamos uma tabela para cada uma das entidades e essas tabelas teriam uma referência (FK) para a tabela principal de clientes:
Se considerássemos que um endereço ou automóvel pudesse pertencer a mais de um cliente a coisa ficaria ainda mais complicada e teríamos que criar tabelas de relacionamento N:M.
Para que o exemplo seja útil, vamos considerar que nesse sistema não fosse possível efetuar pesquisas utilizando como filtro nenhuma dessas entidades (em um sistema real é óbvio que requisito é um absurdo) e só seria disponibilizada uma funcionalidade de busca por meio de código (id). Mesmo com esse requisito, como pensamos sempre em de forma relacional o caminho natural seria criar o modelo de dados acima e armazenar tudo bastante normalizado.
No entanto existe outra opção que em determinados casos é muito interessante. Guardar o objeto inteiro no banco.
Em .NET, por exemplo, bastaria criar um modelo simples de dados contendo o idCliente e um campo que armazene binário (varbinary em SQL), serializar o objeto e pronto.
public Cliente Consultar(int codigoCliente)
{
//Recupera do DB
byte[] clienteSerializado = DaoCliente.ConsultarPorCodigo(codigoCliente);
//Devolve o objeto deserializado
return this.DeserializarObjeto<Cliente>(clienteSerializado);
}
public void Salvar(Cliente novoCliente)
{
//Serializa o objeto
byte[] clienteSerializado = this.SerializarObjeto<Cliente>(novoCliente);
//Guarda o cliente no DB
DaoCliente.Inserir(novoCliente.Codigo, clienteSerializado);
}
private byte[] SerializarObjeto<T>(T objeto)
{
MemoryStream ms = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, objeto);
byte[] objetoSerializado = ms.ToArray();
ms.Close();
return objetoSerializado;
}
private T DeserializarObjeto<T>(byte[] objetoSerializado)
{
MemoryStream ms = new MemoryStream();
BinaryFormatter formatter = new BinaryFormatter();
ms.Write(objetoSerializado, 0, objetoSerializado.Length);
ms.Position = 0;
return (T)formatter.Deserialize(ms);
}
Dessa maneira, sempre que precisarmos, já iremos ter o objeto completo e não seria necessário executar diversas instruções SQL ou stored procedures e muitas chamadas ao banco. Iriamos apenas executar uma chamada que nos retornaria o objeto completo e pronto para uso.
Essa é uma solução diferente e que pode ser útil em alguns cenários, principalmente se você não utiliza nenhum framework ORM. Contudo, é importante verificar todos os requisitos com bastante cuidado, com essa solução corremos o risco de ficar com dados desatualizados e perdemos a possibilidade de efetuar buscas por campos que estejam dentro dos objetos armazenados.
Acho muito legal encontrarmos formas diferentes de fazer as mesmas coisas que estamos habituados. É uma maneira muito eficiente de aprendizado e conhecimento das nossas ferramentas.
O que você acha?
Editado: sem saber, acabei descrevendo o pattern Serialized Lob já catalogo pelo Fowler em seu livro PoEAA. O Bruno achou e comentou o post colocando este link. Valeu!



Antonio, já havia pensado nisso antes. A Microsoft faz coisa parecida com o Profiles do ASP.Net. E todo mundo reclama, porque os campos não são “pesquisáveis”. Acho que aí fica o grande problema, não é pesquisável, ao menos não com facilidade. E a utilização de índices também fica comprometida.
O SQL Server é um banco relacional. Colocar objetos lá pode trazer problemas. Estamos cruzando uma linha perigosa. Acho que há cenários em que se aplica, mas na maioria vai comprometer muito a capacidade de crescimento do aplicativo.
[]!
Sem dúvida, os problemas tendem a ser maior do que a solução. Só em casos especifícos mesmo.
Mas o que eu acho mais importante é encontrarmos uma forma diferente de lidar com persistência. Persistir tudo sempre na mão é perda de tempo. Persistência, na minha opinião, é algo que não deveriamos mais perder tempo fazendo. O LINQ e o EF ainda não me parecem a melhor solução também. Enquanto o EF novo não sai temos o NHibernate e métodos manuais de persistência.
Além das desvantagens que você citou, não vejo vantagem em utilizar algum SGBD para armazenar os dados. Nesse caso utilizar algum framework de prevalência parece-me um pouco melhor e mais lógico. Prevalência foi um assunto que deu bastante discussão no passado no mundo JAVA mas faz algum tempo que não vejo ninguém mais falando sobre isso.
Me lembro de ter feito um pequeno app em Winforms alguns anos atrás utilizando um port do Prevayler(http://prevayler.org) que não me lembro o nome agora. Como o app e o volume de dados eram pequenos foi uma boa opção na época.
Um amigo acabou de me lembrar o nome do port do Prevayler.
Bamboo.Prevalence – a .NET object prevalence engine
http://bbooprevalence.sourceforge.net/
Opa Bruno, também ouvi bastante a respeito há uns 3 anos atrás, mas nunca fui atrás.
Obrigado pelo link!
Só acrescentando mais um pouquinho… estava dando uma olhada no livro P of EAA do Fowler e lá tem um pattern chamado Serialized LOB que é igual ao que você descreveu nesse post.
[]’s
[...] de pedir desculpas aos leitores que utilizam o Internet Explorer, pois desde que publiquei este post o blog ficou com o layout todo deformado neste navegador. Isso aconteceu, pois tinha escrito [...]