.NET - Dicas para boas práticas de programação - Camada de dados


A seguir algumas dicas de boas práticas de programação retirados do : Manual do Desenvolvedor .NET - Microsoft Consulting Services. Resolvi publicar para incentivar a leitura. Então leia...

Usando uma Camada de Dados

As classes deste grupo isolam o resto da aplicação de tudo que esteja relacionado à manipulação dos bancos de dados. Elas fornecem dados para as regras de negócio de forma mais simplificada e modificam o conteúdo do banco de dados sob a orientação dessas regras, isolando as funcionalidades e os detalhes da implementação física.

Na plataforma .NET temos muitas possibilidades de uso do ADO.NET; assim, é importante identificar padrões que resolvam os tipos de problemas mais comuns no dia a dia de forma a garantir produtividade e facilidade em futuras manutenções de código.

É importante notar que o que é sugerido como boa prática em termos de arquitetura de aplicação .NET coloca a aplicação dividida em camadas funcionais.

A utilização de uma camada de dados entre a camada de regra de negócios encapsulando o ADO.NET garante a padronização do mesmo para as funcionalidades mais comuns do dia a dia, promovendo facilidades de manutenção, extensão e produtividade.

Figura 2 - As diversas camadas funcionais no modelo de programação .NET

Recomendações para a criação das classes da camada de dados

1- Retorne apenas os dados de que você realmente necessita;

2- Use as Stored Procedures para abstrair o acesso aos dados (recomendável);

3- Balanceie a utilização de Stored Procedures quanto a implementação de regras de negócio. Faça isso tendo em mente bom senso quanto ao real reaproveitamento de lógica e facilidade de manutenção. Muitas Stored Procedures podem ser afetadas, o que acabará resultando em dificuldades de manutenção;

4- Evite a situação em que uma Stored Procedure chama outra Stored Procedure, e assim por diante. Isso é um sintoma de excesso de Stored Procedures;

5- Implemente um conjunto padrão de Stored Procedures para aquelas tarefas mais comuns, tais como insert, delete, update, find, etc. Se possível, use geradores de código. Isso trará produtividade, consistência e padrão ao desenvolvimento;

6- Quando houver funcionalidades que sejam utilizadas por vários componentes, implemente-as em uma interface separada;

7- Planeje e faça a interface de comunicação com a camada de negócios de forma consistente e compatível, evitando sempre a necessidade de transformações ou “mappings”;

8- Utilize DataReaders sempre que houver operações de leitura de dados (read-only, forward only) apenas. Nesse caso, faça a sua camada de dados retornar DataReaders objects;

9- Quando há a necessidade de uso prolongado do objeto DataReader, aconselha-se considerar a opção de se utilizar Datasets, que são sempre desconectados (isso aumenta a escalabilidade). Quando possível, é interessante que a camada de dados exponha metadados (informações a respeito dos dados) tais como schema ou nomes de colunas: isso oferece maior flexibilidade para a camada de negócio. Os ganhos com flexibilidade têm um custo que é pago com degradação de desempenho ou até mesmo escalabilidade.

10- Evite a construção automática de um componente de acesso a dados para cada tabela física. Considere a possibilidade de escrever seus componentes de acesso a dados num nível de abstração e de normalização maior e mais próximo das necessidades imediatas da camada de negócio. É muito comum a criação de uma classe representando uma tabela que faz relacionamento entre duas tabelas. Neste caso, dê preferência por implementar métodos nas classes principais.

Por exemplo, imagine que existem em sua base as seguintes entidades: Livros e Autores. Essas entidades contêm um relacionamento do tipo vários para vários.

Esse relacionamento é implementado fisicamente na base de dados por uma tabela. Em vez de se criar uma classe responsável por essa tabela, dê preferência por criar métodos, nas camadas Autor e ou na classe Livro, que façam a inclusão desse relacionamento (na classe Autor, crie o método AcrescentarLivro e, na classe Livro, crie o método AcrescentarAutor);

11- Sempre que for necessário guardar dados criptografados, será esta camada que deverá criptografar e descriptografar os dados;

Quando as classes da camada de negócio usarem Enterprise Services (COM+), crie as classes de acesso a dados como sendo do tipo componentes de serviços e faça seu deployment no Enterprise Service (COM+) como uma library Application;

12- Habilite transações apenas quando for realmente imprescindível. Nunca marque todos os componentes de acesso a dados com “Require Transactions”. Marque tais componentes com “Supports Transactions”, adicionando o seguinte atributo:

[Transaction (TransactionOption.Supported)]

12- Ao fazer uso de níveis alternativos ao default de “isolation levels” em consultas, balanceie seu benefício quanto a performance e contenção, confrontando os requisitos de vazão e precisão dos dados. Em casos de alta vazão (throughput), a precisão dos dados pode ser prejudicada se forem utilizados níveis de isolamento menos rígidos;

13- Quando houver transações heterogêneas e a camada de dados tiver de participar, garanta que esta nunca seja o root da transação. É mais apropriado que a camada de negócio ou a gerenciadora seja o root da transação;

14- Quando a aplicação contiver múltiplos componentes de acesso a dados, recomenda-se usar a camada testada e de alta performance Data Access Application Block em suas aplicações para gerenciar as conexões, executar comandos, fazer cache de parâmetros, etc. (veja a figura).

Figura 3 - Esquema de construção de componentes de dados


Implementando  Componentes de Acesso a Dados

1- Faça simples transformações e mapeamentos para entrada e saída de dados;

2- Use um componente para interfacear os dados e um componente (apenas um) para conectar-se à fonte dos dados;

3- Componentes da camada de acesso a dados não necessariamente devem encapsular operações em apenas uma tabela. Geralmente, eles atuam em uma tabela principal e operam algumas tarefas em outras tabelas relacionadas.

Exemplo de Componente para a Camada de Dados :

O código em VB.NET  a seguir mostra um exemplo de um simples componente de acesso a dados. Este código não tem a intenção de ser um modelo a ser copiado em seu código. Sua função é apenas ilustrar o conceito envolvido nesta seção:

  1. Public Class OrderData
  2.     Private conn_string As String
  3.    
  4.             ' obtém a string de conexão em fonte segura e criptografada
  5.             ' atribui a string a conn_string
  6.     Public Sub New()
  7.     End Sub
  8.     Public Function RetrieveOrders() As DataSet
  9.         ' Código que retorna um DataSet contendo Dados da tabela Orders
  10.     End Function
  11.     Public Function RetrieveOrder(ByVal OrderId As Guid) As OrderDataSet
  12.         ' Código que retorna um tipo DataSet de nome OrderDataSet
  13.         ' que representa uma Order específica.
  14.         ' (OrderDataSet terá um schema que tenha sido definido no Visual Studio)
  15.     End Function
  16.     Public Sub UpdateOrder(ByVal updatedOrder As DataSet)
  17.         ' código que altera o Banco de dados baseado nas propriedades
  18.         ' da Order passada como parâmetro do tipo Dataset
  19.     End Sub
  20. End Class

Agora é por em prática para garantir um código mais robusto e elegante.


José Carlos Macoratti