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:

C:\Documents and Settings\u83659\Meus documentos\Artigo\GenericDB\img2.JPG

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.