Anúncios

Construindo camadas de acesso a dados

A principal motivação para o uso de uma camada de acesso a dados (data access layer, DAL) em nossa aplicação é manter os códigos (e as tecnologias) de acesso a dados encapsulados em uma camada que fique responsável por comunicar-se com a fonte de dados, persistindo e recuperando dados de nossas entidades.

Uma camada de acesso a dados deve fornecer recursos para criação, leitura, atualização e exclusão de dados, além de controles de transação, segurança, mapeamento, concorrência, e outros. A sua criação favorece o uso de uma administração centralizada que separa o comportamento da camada de negócios das lógicas de acesso a fontes de dados e serviços.

data-net

Vale ressaltar que estamos nos referenciando a uma “fonte de dados”, não apenas a um banco de dados, pois a camada de acesso a dados pode ser responsável por trabalhar com diferentes fontes de dados (i.e. arquivos XML, bancos de dados orientados a objetos, bancos de dados NoSQL, arquivos de texto, storages na nuvem), não apenas com bancos de dados relacionais.

A camada de acesso a dados não deve conter nenhuma regra de negócio, sua única responsabilidade é comunicar-se com sua respectiva fonte de dados. Além disso, deve ser acessada apenas camada de negócio. É recomendado o uso de interfaces para a comunicação entre estas duas camadas, pois desta forma (com base nos princípios de mínimo conhecimento e designs levemente ligados) tornamos a camada de negócio independente da estratégia de acesso a dados adotada. Este uso também é importante para nossos testes, pois podemos executá-los sem que existam dependências a sistemas externos, como: diretórios de arquivos, servidores de bancos de dados, conexões com a internet, conexões de rede, etc.

A camada de acesso a dados também é responsável por encapsular todas as demais funcionalidades de acesso a dados, tais como: ocultar os detalhes de acesso à fonte de dados, gerenciar as conexões com a fonte de dados, construir estruturas de consultas e mapear as entidades da aplicação com a estrutura da fonte de dados. O usuário consumidor da camada de acesso a dados não deve ter conhecimento de detalhes internos da camada de acesso a dados, apenas ter conhecimento de suas interfaces expostas.

Nossa camada de acesso a dados deve atender os requisitos de nossa aplicação, ser eficiente, segura e manutenível. A escolha da tecnologia de acesso a dados deve ser apropriada para o tipo de dados que será manipulado e para as funcionalidades que trabalharão com estes dados, pois certas tecnologias são melhores do que outras em cenários específicos, como: manipulação de dados, armazenamento de arquivos, velocidade de retorno, flexibilidade de estruturas, soluções de cache, formato de dados, etc.

É importante conhecer as diferentes características de cada fonte de dados e compreender quais os cenários indicados para o uso de cada uma destas fontes de dados, pois o seu uso, ao invés de outra tecnologia que não provê os mesmos recursos, simplifica a sua solução e agrega melhores resultados.

Ganhos com o uso de camadas de acesso a dados

Com o uso de camadas de acesso a dados encapsulamos todo sistema de conexão, persistência e consulta de dados. Assim, promovemos:

– Reaproveitamento de código: evitamos códigos duplicados que executam a mesma tarefa;

– Diminuição de erros: com o encapsulamento de comandos e o reaproveitamento de código, acabamos por desenvolver menos código, e com menos código temos uma quantidade menor de possibilidades de erros;

– Centralização de políticas de acesso a dados: com o uso de camadas de acesso a dados podemos adicionar de maneira mais fácil políticas de acesso ou controles de cache;

– Habilidade de testar facilmente a camada de negócios de maneira desconectada da fonte de dados.

Estratégias de acesso a dados

Existem diferentes estratégias de acesso a dados, cada uma possui suas respectivas vantagens, desvantagens e indicações de uso. A seguir, algumas das mais utilizadas:

1 – Repository Pattern e Generic Repository Pattern

Funciona como uma coleção em memória, fornecendo recursos para persistência e recuperação de dados. Consiste de uma classe que provê recursos de recuperação e persistência de dados dado um tipo genérico. Padrão bastante associado ao uso de ferramentas de mapeamento objeto relacional (ORM). Este padrão faz proveito das estruturas mapeadas pelas ferramentas ORM.

public interface IRepository
{
    // Procura uma entidade a partir
    // de sua Primary Key
    T Find<T>(long id) where T : Entity;

    // Executa uma consulta a partir de uma 
    // query LINQ
    IQueryable<T> Query<T>(Expression<Func<T, bool>> where);

    // Operações básicas de persistência
    void Delete(object target);
    void Save(object target);
    void Insert(object target);

    // Retorna todos os registros de 
    // uma entidade que estão registrados
    // na fonte de dados
    T[] GetAll<T>();
}

Geralmente, abordagens que utilizam o padrão repository implementam códigos muito parecidos de consulta e persistência de dados. O uso do padrão generic repository toma proveito do uso de generics e simplifica o seu uso, pois cria um conjunto de lógicas genéricas de persistência e recuperação de dados que padroniza o modelo de comunicação com a fonte de dados.

2 – Data Access Objects

Padrão desenhado para separar os elementos de nossa camada de acesso do restante da aplicação. Geralmente, é criado um DAO para cada tabela do banco de dados.

public interface CustomerDAO
{
    // Operações básicas de persistência
    public void Insert(Customer customer);
    public void Update(Customer customer);
    public void Delete(Customer customer);

    // Retorna todos os registros de 
    // customer na fonte de dados
    public Customer[] FindAll();

    // Retorna um customer a partir
    // de uma Primary Key
    public Customer FindByPrimaryKey(String email);

    // Retorna um customer a partir
    // de uma Primary Key de uma company
    public Customer[] FindByCompany(int companyId);
}

3 – Data Mapper

Camada de mapeamento entre os entidades e a estrutura do banco de dados. Mapeia os dados entre os objetos e o banco de dados enquanto mantém um independente do outro.

Objetos e bancos de dados relacionais são baseados em paradigmas diferentes, orientado a objetos e relacional, respectivamente. Quando criamos um sistema que une esses dois paradigmas precisamos de uma camada que faça o mapeamento entre estas duas formas de representação dos dados. Também, não é interessante que um paradigma tenha conhecimento do funcionamento do outro, pois caso algum dos dois sofra alterações o impacto será mínimo.

clip_image002

4 – Data Transfer Object

Objeto de transferência de informação, armazena os dados transportados entre processos. Os DTOs são objetos que não contém nenhuma lógica de negócio. São muito utilizados como retornos de serviços, substituição de objetos não serializáveis ou apresentação de dados.

Uma de suas principais motivações é acarretar na diminuição de chamadas a métodos, pois geralmente agrupam dados de entidades relacionadas, o que favorece a diminuição de invoques de métodos e serviços, pois já trazem os dados prontos.

clip_image004

Questões relevantes

– Abra conexões o mais tarde possível e as feche o mais cedo possível. Nunca mantenha conexões abertas por mais tempo do que o necessário.

– Execute transações por meio de uma única conexão sempre que possível.

– Utilize estruturas XML para interoperabilidade com outros sistemas e plataformas, ou quando trabalhar com estruturas de dados que podem mudar durante o tempo.

– Construa uma estratégia de log e notificações para erros críticos, mas lembre-se de não revelar informações sigilosas por meio destas estratégias.

– Implemente processos de retry para operações de timeout sempre que for seguro fazê-lo.

– Utilize queries parametrizadas e parâmetros tipados, para mitigar questões de segurança e reduzir a chance de ataques por SQL Injections.

 

Por

MSc. Fernando Henrique Inocêncio Borba Ferreira

Microsoft Most Valuable Professional – Visual C#

 

Referências

Microsoft Application Architecture Guide – 2nd Edition – Microsoft Patterns and Practices

Professional ASP.Net Design Patterns – Scott Millett

The Repository Pattern – http://msdn.microsoft.com/en-us/library/ff649690.aspx

Data Access Architecture Guide – Microsoft Patterns and Practices – http://www.microsoft.com/en-us/download/details.aspx?id=193

Data Mapper – Martin Fowler – http://martinfowler.com/eaaCatalog/dataMapper.html

Design Patterns for Data Persistence – Jeremy Miller – http://msdn.microsoft.com/en-us/magazine/dd569757.aspx

Data Access Object – http://www.codefutures.com/data-access-object/

Anúncios

13 Responses to Construindo camadas de acesso a dados

  1. Grande Fernando, mais um ótimo artigo 🙂

    Vou recomendar seu texto para alguns conhecidos que ainda não entenderam as responsabilidades de uma camada de acesso a dados rsss…

    Muito boa a indicação dos patterns também, muito mais elegante e reaproveitável desta forma.

    Abraços!

  2. Ray Silva says:

    Realmente excelente leitura.

    Em uma parte do texto você cita:

    “A camada de acesso a dados não deve conter nenhuma regra de negócio, sua única responsabilidade é comunicar-se com sua respectiva fonte de dados.”

    Estive em contato com o Design Pattern MVP (Model View Presenter) e pude notar que na DAL é muito comum implementar algumas regras de negócio…porém, nunca encontrei a razão pela qual a pattern faz isso.

    Saberia me dizer?

    • Grande Ray!
      Tudo beleza?
      Nesse caso, o que é possível, é o uso de algumas rotinas validação dos dados. Algo que impeça a camada de acesso a dados de utilizar valores nulos. Mas, não acredito que vc tenha visto grandes regras de negócio compostas por outras chamadas a classes de negócios sendo chamadas. Algo além disso pode ser discutido se a camada de acesso a dados foi implementada corretamente ou não.
      O que acha?
      []s e obrigado por postar!

  3. cleitonfelipe says:

    Bom dia Fernando,
    Muito bom seu artigo, deixa bem claro a utilização da camada de acesso a dados e como podemos fazer proveito de estrategias de acesso a dados em nossas aplicações.

    Abraços…

  4. Engraçado que comecei um texto sobre isso no mês retrazado e nunca terminei. Ainda bem que a comunidade tem você mestre,hahha, muito bom. Quero te ver apresentando isso dia 14

  5. Pedro Lima says:

    Bom dia Henrique, gostaria de saber sobre como tratar uma exclusão onde a tabela possui relacionamento e a tabela relacionada possui dados e na hora da exclusão não retornar o erro e sim uma mensagem, estou usando LazyLoad para carregar as entidades relacionadas e quando mando excluir um objeto ele perde os dados carregados pelo uso do Lazy load. Tem alguma dica?

  6. Francisco Berrocal says:

    Gostaria de saber como funcionam os testes em relação à camada de acesso aos dados, isto é, devemos testar pelo padrão utilizado na camada, ou diretamente?
    Acredito que tais testes sejam considerados testes de integração, e por isso aplicados após os testes unitários.Mas é estranho nós testarmos o acesso a camada de dados antes mesmo de qualquer outra funcionalidade, não?
    Você utiliza algum framework específico como o NDBUnit, ou algum outro?
    Parabéns pela atuação na comunidade e trabalho que vem desenvolvendo.

    • Olá Francisco,
      Tudo beleza?

      Sim, realmente neste caso, por conta da necessidade de trabalharmos com recursos externos, teremos de construir testes de integração da lógica de acesso a dados com a fonte de dados.

      Neste tipo de cenário nossos testes serão mais lentos, pois exigem uma integração externa.

      Acredito que para a realização destes testes vc pode assumir algumas frentes:
      – criar um projeto de testes unitários que façam a execução das lógicas de acesso a dados
      – criar um projeto de teste de carga e stress da camada de acesso a dados

      O que acha?

      Obrigado por postar e obrigado pelos elogios!

      []s!

  7. Pingback: Construindo camadas de acesso a dados – Parte III – Repositórios Genéricos (Pantheon) | Fernando Henrique Ferreira

  8. Pingback: Entity Framework – Melhores práticas em busca de performance | Fernando Henrique Ferreira

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: