Para facilitar a vida dos desenvolvedores com o novo modelo de provedor ADO.NET 2.0 nós podemos criar classes genéricas para acessar vários tipos de banco com a utilização da classe DbProviderFactory que através do nome do provedor passado na string de conexão ele identifica qual o banco utilizado e a partir daí criamos as classes DbConnection e DbCommand.
Vamos à prática. Abra o Visual Studio 2005 e crie um novo projeto Class Library como mostra a figura 1:
Figura 1 – Criando o Projeto
Após criar o projeto GenericDataBase exclua a classe que já vem como padrão Class1.cs do projeto e adicione uma nova pasta com o nome Configuration e dentro da pasta adicione uma nova classe com o nome ConnectionDB. Veja figura 2:
Figura 2 – Adicionando uma Classe
Antes de programarmos e falarmos sobre esta classe vamos adicionar outra pasta com o nome GenericDB e dentro dela a classe GenericDB.
A classe ConnectionDB deve ser declarada como publica e estática para que possamos ter acesso a ela e as suas propriedades sem ter que criar uma instância nova dela. Seu namespace deve ser alterado para GenericDataBase. Esta classe servirá apenas para armazenar a string de conexão e o nome do provedor que será utilizado no projeto. O código completo desta classe segue logo abaixo:
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
namespace GenericDataBase
{
///
/// Classe de configuração da Conexão com o BD
///
public static class ConnectionDB
{
///
/// Construtor Default
///
static ConnectionDB()
{
try
{
// Recebe do arquivo de configuração Web.Config a string de conexão e o nome do provedor
connectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
providerName = ConfigurationManager.ConnectionStrings["ConnectionString"].ProviderName;
}
catch
{
throw new Exception("Erro ao receber dados da Conexão. Por favor verifique se a string de conexão está declarada corretamente.");
} }
///
/// Field String de Conexão
///
private static string connectionString;
///
/// Field Nome do Provedor
///
private static string providerName;
///
/// Propriedade que apenas informa a String de Conexão
///
public static string ConnectionString
{
get
{
return connectionString;
}
}
///
/// Propriedade que apenas informa o Nome do Provedor
///
public static string ProviderName
{
get
{
return providerName;
}
}
}
}
O código está todo comentado e isso deve ser uma obrigação de cada programador ao desenvolver seus códigos.
Veja que no construtor default da classe eu faço uso da Classe ConfigurationManager para pegar a string de conexão no arquivo Web.Config e para isso não devemos esquecer de declarar seu namespace no início da classe :
using System.Configuration;
Obs.: Para utilização desta DLL será necessário declarar a string de conexão no arquivo Web.Config no seu projeto como ConnectionString.
Antes de programarmos a classe GenericDB vamos definir quais os tipos de comando que a DLL irá executar no banco de dados. Para isso vamos criar uma nova classe no projeto com o nome TypeCommand. Altere a declaração de class para enum igual está o código abaixo:
namespace GenericDB
{
///
/// Tipos de Commandos a serem
/// executados no BD
///
public enum TypeCommand
{
ExecuteNonQuery,
ExecuteReader,
ExecuteScalar,
ExecuteDataTable
}
}
Abra a classe GenericDB e faça sua declaração da mesma forma que a classe ConnectionDB (Public e Static). Segue o código da declaração da classe:
using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Common;
using System.Data;
namespace GenericDataBase
{
///
/// Classe de execução de comandos no BD
///
public static class GenericDB
{
///
/// Construtor Default
///
static GenericDB()
{
//
// TODO: Add constructor logic here
//
}
}
}
Vamos agora adicionar um método para criar os objetos DbConnection e DbCommand utilizando o Factory de acordo com o nome de provedor passada na string de conexão. O código deste método comentado segue logo abaixo:
///
/// Método que Cria um objeto DBCommand com os dados
/// da classe ConnectionDB utilizando Factory
///
/// DBCommand criado
public static DbCommand createCommand(String cmmdText, CommandType cmmdType, List<DbParameter> listParameter)
{
// Cria um novo factories de acordo com o nome do provedor
DbProviderFactory factory = DbProviderFactories.GetFactory(ConnectionDB.ProviderName);
// Cria um objeto específico de conexão de acordo com o nome do provedor
DbConnection conn = factory.CreateConnection();
// Atribui a String de Conexão
conn.ConnectionString = ConnectionDB.ConnectionString;
// Cria um objeto command específico de acordo com o nome do provedor
DbCommand comm = conn.CreateCommand();
// Atribui o comando Text
comm.CommandText = cmmdText;
// Atribui o tipo de comando
comm.CommandType = cmmdType;
// Se existir algum parâmetro ele adiciona
// ao comando
if (listParameter != null)
{
foreach (DbParameter param in listParameter)
{
// Adicionando o parâmetro
comm.Parameters.Add(param);
}
}
// Retorna o comando criado
return comm;
}
Este método recebe três parâmetros, o primeiro serve para receber um comando SQL ou o nome da stored procedure o segundo é o tipo de comando (Stored Procedure ou Text) e o terceiro é uma lista de parâmetros. Irei mostrar depois como criar essa lista de parâmetros, pois será necessário criar um método para criar os parâmetros. Não esqueça de fazer referência ao namespace System.Collections.Generic para poder fazer uso das Listas Genéricas.
Repare o uso da classe DbProviderFactory. Com ela eu crio um factory recebendo da classe ConnectionDB o nome do provedor.
DbProviderFactory factory = DbProviderFactories.GetFactory(ConnectionDB.ProviderName);
E é através deste factory criado que eu crio os objetos de conexão
DbConnection conn = factory.CreateConnection();
e de comando
DbCommand comm = conn.CreateCommand();
Após criado o comando eu atribuo ao comando o comando a ser executado (cmmdText) e o tipo de comando (cmmdType).
Para adicionar os parâmetros ao comando eu verifico se a lista não é nula. Se não for eu percorro toda a lista de parâmetros e adiciono cada um ao comando.
// Se existir algum parâmetro ele adiciona
// ao comando
if (listParameter != null)
{
foreach (DbParameter param in listParameter)
{
// Adicionando o parâmetro
comm.Parameters.Add(param);
}
}
Vamos agora ao método para criar parâmetros. Nós sabemos que todo parâmetro sempre tem o nome, tipo e valor, então vamos criar um método que recebe como parâmetro essas três variáveis. Veja o método abaixo:
///
/// Método responsável por criar um Parâmetro
///
/// List param = new List();
/// param.Add(criaParameter(nome, tipo, valor));
///
///
/// Nome do Parâmetro
/// Tipo do Parâmetro
/// Valor do Parâmetro
/// Parâmetro preenchido
public static DbParameter criaParameter(String nameParameter, DbType typeParameter, Object valueParameter)
{
// Cria um novo factories de acordo com o nome do provedor
DbProviderFactory factory = DbProviderFactories.GetFactory(ConnectionDB.ProviderName);
// Cria o Parâmetro e add seu valores
DbParameter param = factory.CreateParameter();
param.ParameterName = nameParameter;
param.DbType = typeParameter;
param.Value = valueParameter;
// Retorna o Parâmetro criado
return param;
}
Este método é bem simples mas o principal detalhe é que para criar o DbParameter eu devo utilizar o factory também.
DbParameter param = factory.CreateParameter();
Depois é só adicionar os valores ao parâmetro e retorná-lo.
Na hora de utilizar a DLL você deverá fazer assim:
List param = new List();
param.Add(criaParameter(nome1, tipo1, valor1));
param.Add(criaParameter(nome2, tipo2, valor2));
param.Add(criaParameter(nome3, tipo3, valor3));
E assim pra quantos parâmetros tiver.
Agora vamos ao último método e o mais importante que é o método de execução. Ele receberá os mesmos parâmetros do método createCommand e mais um que é o tipo de comando a ser executado. Segue o método:
///
/// Método que cria um comando e executa esse comando.
///
/// String SQL ou StoredProcedure
/// Tipo de Commando (Text ou Stored Procedure
/// Lista de parâmetros
/// Comando a ser executado (ExecuteNonQuery, ExecuteReader, ExecuteScalar, ExecuteDataTable)
/// Object
public static Object executeCommand(String cmmdText, CommandType cmmdType, List<DbParameter> listParameter, TypeCommand typeCmmd)
{
// Cria comando com os dados passado por parâmetro
DbCommand command = CreateCommand(cmmdText, cmmdType, listParameter);
// Cria objeto de retorno
Object objRetorno = null;
try
{
// Abre a Conexão com o banco de dados
command.Connection.Open();
switch (typeCmmd)
{
case TypeCommand.ExecuteNonQuery:
// Retorna o número de linhas afetadas
objRetorno = command.ExecuteNonQuery();
break;
case TypeCommand.ExecuteReader:
// Retorna um DbDataReader
objRetorno = command.ExecuteReader(CommandBehavior.CloseConnection);
break;
case TypeCommand.ExecuteScalar:
// Retorna um objeto
objRetorno = command.ExecuteScalar();
break;
case TypeCommand.ExecuteDataTable:
// Cria uma tabela
DataTable table = new DataTable();
// Executa o comando e salva os dados na tabela
DbDataReader reader = command.ExecuteReader();
table.Load(reader);
// Fecha o Reader
reader.Close();
// Retorna a tabela
objRetorno = table;
break;
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (typeCmmd != TypeCommand.ExecuteReader)
{
// Sempre fecha a conexão com o BD
command.Connection.Close();
}
}
return objRetorno;
}
A primeira coisa a fazer neste método é chamar o método que criamos para criar o comando: DbCommand command = CreateCommand(cmmdText, cmmdType, listParameter);
Este mesmo método servirá para excutar todos os tipos de comando no banco de dados e para cada comando ele retorna um objeto diferente, veja tabela abaixo:
...