Neste artigo irei mostrar
como criar um DLL de acesso à dados Genérica, ou seja, servirá para qualquer
banco que for utilizado no seu projeto.
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
{
/// <summary>
/// Classe de configuração
da Conexão com o BD
/// </summary>
public static class ConnectionDB
{
/// <summary>
///
Construtor Default
/// </summary>
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.");
} }
/// <summary>
/// Field String de Conexão
/// </summary>
private
static string
connectionString;
/// <summary>
/// Field Nome do Provedor
/// </summary>
private
static string
providerName;
/// <summary>
///
Propriedade que apenas informa a String de Conexão
/// </summary>
public
static string
ConnectionString
{
get
{
return
connectionString;
}
}
/// <summary>
///
Propriedade que apenas informa o Nome do Provedor
/// </summary>
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
{
/// <summary>
/// Tipos de Commandos a serem
/// executados no
BD
/// </summary>
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
{
/// <summary>
/// Classe de execução de comandos no BD
/// </summary>
public static class GenericDB
{
/// <summary>
/// Construtor Default
/// </summary>
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:
/// <summary>
/// Método que Cria um objeto DBCommand com os dados
/// da classe ConnectionDB utilizando Factory
/// </summary>
/// <returns>DBCommand
criado</returns>
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:
/// <summary>
/// Método responsável por criar um Parâmetro
/// <example>
/// List<DbParameter> param = new List<DbParameter>();
/// param.Add(criaParameter(nome, tipo, valor));
/// </example>
/// </summary>
/// <param
name="nameParameter">Nome do
Parâmetro</param>
/// <param
name="typeParameter">Tipo do
Parâmetro</param>
/// <param
name="valueParameter">Valor do
Parâmetro</param>
/// <returns>Parâmetro preenchido</returns>
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<DbParameter> param = new List<DbParameter>();
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:
/// <summary>
/// Método que cria um comando e executa esse comando.
/// </summary>
/// <param name="cmmdText">String SQL ou StoredProcedure</param>
/// <param
name="cmmdType">Tipo de Commando (Text ou
Stored Procedure</param>
/// <param
name="listParameter">Lista de
parâmetros</param>
/// <param
name="typeCmmd">Comando a ser
executado (ExecuteNonQuery, ExecuteReader, ExecuteScalar, ExecuteDataTable)</param>
/// <returns>Object</returns>
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:
Comando |
Objeto |
ExecuteNonQuery |
Inteiro |
ExecuteReader |
DbDataReader |
ExecuteScalar |
Objeto |
ExecuteDataTable |
DataTable |
Veja
que utilizo o switch case para verificar qual o tipo de comando e faço a
execução. Após a execução no bloco finally eu verifico se não é do tipo DbDataReader
para poder fechar a conexão porque se eu fechar a conexão agora não será
possível utilizar o DbDataReader após a consulta. Mas veja também que para isso
é necessário acrescentar no método ExecuteReader o parâmetro CommandBehavior.CloseConnection que quer dizer que quando eu fechar o
DbDataReader ele automaticamente fecha a conexão. Por isso é importante
observar que toda vez que você executar o comando ExecuteReader não deve-se esquecer
de fechar o DbDataReader após o seu uso.
Bom
agora basta apertar CTRL + SHIFT + B para compilar o projeto e se não houver
nenhum erro será criado na pasta bin do projeto um arquivo chamado
GenericDataBase.dll. Agora crie um novo projeto para poder fazer os testes e
verificar o funcionamento desta dll.
Neste
artigo não irei mostrar o funcionamento dela para não ficar extenso de mais.
Mas logo irei publicar outro artigo com um exemplo de uso desta dll de acesso a
dados. Para quem for fazer os testes segue exemplo de como utilizá-la:
Primeiramene
deve adicionar a dll como referência da seguinte forma:
Clique
com o botão direito do mouse em cima do projeto e em Add Reference... Selecione
a dll e clique em Ok.
Depois
adicione no início da classe o uso do namespace GenericDataBase.
using GenericDataBase;
Ex1.:
GridView.DataSource = (DataTable)GenericDB.executeCommand("Nome da Procedure", CommandType.StoredProcedure, null, TypeCommand.ExecuteDataTable);
Ex2.: // Cria Lista
de Parâmetros
List<DbParameter> param = new
List<DbParameter>();
//
Adiciona os parâmetros
param.Add(GenericDB.criaParameter("@NOME", DbType.String,
nome));
param.Add(GenericDB.criaParameter("@ENDERECO", DbType.String,
endereco));
param.Add(GenericDB.criaParameter("@TELEFONE", DbType.String,
telefone));
GenericDB.executeCommand("stpAddPessoa",
CommandType.StoredProcedure, param, TypeCommand.ExecuteNonQuery);
Ex3.:
// Cria string
SQL
string selectSQL = "SELECT * FROM TBPESSOA WHERE ID = " +
id;
// Executa o comando
DbDataReader
dr = (DbDataReader)GenericDB.executeCommand(selectSQL,
CommandType.Text, null,
TypeCommand.ExecuteReader);
Este
exemplo é pequeno e bem simples e pode servir de início para quem ainda está
iniciando. Agora vocês podem acrescentar métodos que utilizam transaction,
métodos de email, validações e muito mais de acordo com a necessidade e
criatividade de cada um. Quero deixar claro também que está dll não é uma regra
dizendo que sempre tem que ser desse jeito. Um exemplo é que para cada tipo de
execução (ExecuteNonQuery, ExecuteReader, ExecuteScalar, ExecuteDataTable) poderia ter sido criado um método diferente
que retorne o seu objeto específico ao invés de um método só como foi feito
neste artigo.
É
isso ai espero ter acrescentado algum conhecimento a mais à muita gente.
Qualquer dúvida podem entrar em contato através do email: ebenezer05@gmail.com
Abraços
e até a próxima.