ADO .NET - O modelo Factory Genérico


Hoje eu vou escrever um pouco sobre ADO .NET e o modelo Factory Genérico. Atualmente com o popularização das ferramentas ORM esse assunto pode parecer um tanto ultrapassado. Mas creio que saber o que acontece nos bastidores pode nos levar a uma melhor compreensão de como usar as ferramentas atuais.

Se você não sabe o que é um modelo Factory genérico e você desenvolve contra os servidores de banco de dados diferentes usando ADO .NET, então você vai gostar deste artigo. A partir da ADO.NET 2.0 a Microsoft facilitou muito o desenvolvimento de aplicações que usam banco de dados para serem multiplataforma.

Hoje você pode estar desenvolvendo para um servidor SQL Server, amanhã para um Oracle e quem depois para um MySQL. Não importa qual a sua fonte de dados. A ADO .NET permite e oferece uma plataforma agnóstica sobre a qual você pode criar aplicações de forma a que você escreve o seu código uma única vez e ele vai trabalhar com qualquer fonte de dados.

O modelo Factory genérico é uma arquitetura que permite o acesso a qualquer banco de dados, a partir de um conjunto de código.

No namespace System.Data.Common existem algumas novas classes que nos permitem criar código independente de plataforma muito facilmente, mas antes de sujar as mãos, vamos rapidamente dar uma visão geral sobre o Modelo Factory Genérico.

Provedores

Durante os primórdios da plataforma .NET (versão 1.o) existiam apenas 3 provedores nos seguintes namespaces:

Naqueles dias, fomos encorajados por exemplos em toda a internet, em livros, e pelos nossos pares para usar diretamente o conjunto mais adequado de classes no namespace correto.

Fazer isso porém nos trazia alguns problemas pois depois de usar um provedor de um fornecedor específico como o SqlClient em nosso código ele não podia mais ser usado para outro servidor de banco de dados como o Oracle, ou seja , você não tinha mais opção e ficava amarrado àquele provedor.

Se você quisesse escrever um código mais genérico você teria que usar interfaces combinadas com um lógica select/case/swithc como por exemplo:

Public ReadOnly Property Connection() As System.Data.IDbConnection
  Get
    Select Case OldGenericFactoryHelper.Provider
         Case “SqlClient”
            Return New System.Data.SqlClient.SqlConnection
         Case “Odbc”
            Return New System.Data.Odbc.OdbcConnection
         Case “SqlClient”
            Return New System.Data.OleDb.OleDbConnection
         Case Else
            Return Nothing
         End Select
  End Get
End Property
public System.Data.IDbConnection Connection
{
  get {
     switch (OldGenericFactoryHelper.Provider) {
       case "SqlClient":
          return new System.Data.SqlClient.SqlConnection();
      case "Odbc":
          return new System.Data.Odbc.OdbcConnection();
      case "SqlClient":
          return new System.Data.OleDb.OleDbConnection();
     default:
     return null;
   }
 }
}

Como você pode ver, o método retorna uma interface do tipo IDbConnection, a qual é uma implementação genérica da classe Connection que todos os provedores de classes específicas (SqlConnection, OdbcConnection, etc.) implementam. Esta abordagem permite escrever código usando as interfaces, em vez dos provedores específicos, mas temos que admitir que ele não cheira muito bem.

Qualquer aplicação que aplica esta abordagem tem um design independente da plataforma. Abaixo temos a figura que representa essa arquitetura de acesso a dados:

Um dos problemas principais com este modelo era que cada vez que um fornecedor era adicionado ao sistema, a instrução select/case/switch tinha que ser alterada. Você também precisava de instruções switch/select/case para todas as outras classes específicas do fornecedor, tal como aqueles que implementam IDbCommand, de modo que a suas aplicações pudessem recuperar a classe Command correta (SqlCommand, OleDbCommand, OdbcCommand, etc.)

Embora este não seja um problema tão grande, e a abordagem geral funcionava bem, com a nova versão da ADO.NET a Microsoft veio com uma solução muito melhor: o chamado modelo de fábrica genérico.

A ADO.NET 2.0 resolveu o problema acima mencionado através da introdução de Factories.A matéria prima da Factory são os provedores que queremos usar, e os produtos são os classes independente dos provedores que precisamos usar.

As classes de provedor independentes incluem DbConnection, DbCommand e DbParameter, bem como um série de outras classes. A maneira como elas são usadas, é muito semelhante à forma como elas foram usados no antigo modelo, mas elas vêm de uma Factory e você não tem que escrever nenhum código para obtê-las.

Em outras palavras você não tem mais que codificar qualquer instrução select/case/switch e melhor ainda, a plataforma .NET irá fazer todo o trabalho para você. Assim, por exemplo se você desejar trabalhar como objeto connection SqlConnection tudo o que você precisa fazer é o seguinte:

Public Shared Function GetConnection(ByVal providerName As String)
      Return System.Data.Common.DbProviderFactories.GetFactory(providerName).CreateConnection()
End Function
public static object GetConnection(string providerName)
{
return System.Data.Common.DbProviderFactories.GetFactory(providerName).CreateConnection();
}

Se você quer usar um objeto Command é tão simples como chamar CreateCommand() na Factory retornada por GetFactory().

Este código é muito mais limpo e fácil de manter. Você nunca terá que modificá-lo, até mesmo para usar provedores.

DbProviderFactories

A Factory é a chave do Modelo Factory Genérico ela é a responsável por criar todas as suas classes sendo que a plataforma .NET já vem com várias implementações de Factory. Elas são definidas no arquivo machine.config e você abrir este arquivo e dar uma espiada no seu conteúdo basta acessar o caminho: C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config (o caminho pode ser diferente dependendo da sua versão da plataforma .net)

Existem atualmente 5 provedores definidos por padrão mas você pode adicionar outros provedores . Abaixo temos os principais provedores fornecidos com a plataforma .NET:

Obs: Na versão do Visual Studio 2012 veja o documento da Oracle para o provedor Oracle : http://www.oracle.com/technetwork/topics/dotnet/utilsoft-086879.html

Você pode adicionar novos provedores tanto no arquivo machine.config, no arquivo app.cinfig e no arquivo web.config. Para isso basta incluir uma seção <DbProviderFactories> do arquivo conforme exemplo abaixo:

<DbProviderFactories>
<add name=”Odbc Data Provider” invariant=”System.Data.Odbc” description=”.Net Framework Data Provider for Odbc” type=”System.Data.Odbc.OdbcFactory, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089” />
</DbProviderFactories>

A seguir um exemplo, a título de comparação, que mostra a abordagem tradicional e a abordagem do modelo Factory usando DbProviderFactory:

    SqlConnection nwindConn = new SqlConnection();
    nwindConn.ConnectionString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind";
    SqlCommand catCMD = nwindConn.CreateCommand();
    catCMD.CommandText = "SELECT CategoryID, CategoryName FROM Categories";

    nwindConn.Open();

    SqlDataReader myReader = catCMD.ExecuteReader();

    while (myReader.Read())
    {
      Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1));
    }

    myReader.Close();
    nwindConn.Close();
System.Data.SqlClient
DbProviderFactory dpf = DbProviderFactories.GetFactory("System.Data.SqlClient");
DbConnection nwindConn = GetDbProviderFactory().CreateConnection(); 
nwindConn.ConnectionString = "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind";

DbCommand catCMD = nwindConn.CreateCommand();
catCMD.CommandText = "SELECT CategoryID, CategoryName FROM Categories";

DbDataReader myReader = catCMD.ExecuteReader();
 while (myReader.Read())
    {
      Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1));
    }


 myReader.Close();
 nwindConn.Close();
DbProviderFactory

Aqui estão algumas razões para usar o modelo Factory genérico:

E claro que nada é perfeito e existem algumas desvantagens também:

Cabe a você avaliar se vale ou não pena.

Se você tem a absoluta certeza de que seu servidor de banco de dados nunca vai mudar então para que migrar ???

1Ts 4:2 Pois vós sabeis que preceitos vos temos dado pelo Senhor Jesus.

1Ts 4:3 Porque esta é a vontade de Deus, a saber, a vossa santificação: que vos abstenhais da prostituição,

1Ts 4:4 que cada um de vós saiba possuir o seu vaso em santidade e honra,

1Ts 4:5 não na paixão da concupiscência, como os gentios que não conhecem a Deus;

1Ts 4:6 ninguém iluda ou defraude nisso a seu irmão, porque o Senhor é vingador de todas estas coisas, como também antes vo-lo dissemos e testificamos.

Referências:


José Carlos Macoratti