Construindo o projeto.

Vamos agora estabelecer os objetivos do nosso Projeto.

A) Ele será desenvolvido para ser utilizado em projetos que utilizem o conceito arquitetura de três camadas seguindo as seguintes regras:

§ Nossa ferramenta irá criar uma classe DAL que será genérica, ou seja, não precisaremos criar nenhuma classe DAL específica para cada classe Model em nosso projeto de teste. Teremos apenas uma classe DAL que será acessada pelas classes Business;

§ Estabeleceremos regras de acesso à essa classe DAL Genérica;

§ Estabeleceremos regras para a criação das classes Model – forçando que nessas classes estejam contidas funcionalidades ORM;

§ Estabeleceremos regras para a criação de classes Business;

B) Deverá ser independente de banco de dados;

C) Todas as operações de bancos de dados deverão estar associadas à uma transação (transaction);

D) Poderá ser utilizado para qualquer tipo de projeto (Windows, Web, Móbile etc.).

Vamos agora estabelecer as restrições do projeto:

A) Não poderemos utilizar componentes de terceiros;

B) Usaremos somente recursos nativos do .Net Framework;

Iniciaremos agora a codificação do nosso projeto. Iremos utilizar o Visual Studio 2008 com a linguagem C#.

Com o Visual Studio 2008, crie uma nova solução em branco de nome “Library”, clicando em “File”- “New” – “Project”. Na tela “New Project”, expanda “Other Project Types” e selecione “Visual Studio Solutions”. Clique em “Blank Solution”.

Nossa solução terá os seguintes projetos:


Ilustração 7 – Solução/Projetos

Os tipos de projetos serão descritos na tabela abaixo:

Nome do projeto

Tipo de Projeto

Attributes

Class Library

BaseClasses

Class Library

DataBaseLib

Class Library

Interfaces

Class Library

TestProject

Console Application

Tabela 5 – Descrição dos tipos de projetos da solução

O projeto Attributes

Este projeto conterá todos os atributos que iremos utilizar em nossas classes model. Eles conterão informações importantes para conseguirmos, por exemplo, mapear as propriedades de uma classe com os campos de uma tabela, ou parâmetros de uma Stored Procedure.

O primeiro atributo que criaremos é o atributo que irá informar se a classe irá refletir uma tabela ou parâmetros de Stored Procedure ou ambos.

Como temos três opções de valor para este atributo, é de bom tom utilizarmos uma enumeração. Então primeiramente criaremos um enum:


namespace GenDAL.Library.Attributes

{

     public enum DataAccesType

    {

        None = 0,

        StoredProcedure = 1,

        DirectTableAcces = 2,

        Both = 3

       

    }

Com esse código criamos um enum com as três opções citadas e mais uma, para utilizarmos como padrão. Sendo assim, podemos criar nosso primeiro atributo:



[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]

public class AttDataAccessType : Attribute

    {

        private DataAccesType _dataAccesType;

        public DataAccesType DataAccesType

        {

            get { return _dataAccesType; }

            set { _dataAccesType = value; }

        }

 

        public AttDataAccessType(DataAccesType dataAccessType)

        {

            this._dataAccesType = dataAccessType;

        }

    }

 

}

Como podemos verificar, é muito simples criar atributos. Eles seguem a mesma regra de uma classe comum com campos privados, propriedades e construtores. Para ser um atributo a classe precisa herdar de System.Attribute.

Vale ressaltar que é de extrema importante utilizar o atributo “AttributeUsage” do .net, onde criamos regras para a utilização dos nossos atributos. No nosso caso, definimos que este atributo poderá ser utilizado apenas por classes, ou seja, ele conterá informações relativas a classes. Definimos também que ele poderá ser utilizado somente uma vez.

Podemos verificar que nosso atributo possui uma propriedade do tipo DataAccesType, que é a enumeração que criamos. Essa propriedade será lida em tempo de execução para tomar decisões específicas para cada situação.

Abaixo segue o código completo do atributo:


using System;

 namespace GenDAL.Library.Attributes

{

    public enum DataAccesType

    {

        None = 0,

        StoredProcedure = 1,

        DirectTableAcces = 2,

        Both = 3

       

    }

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]

    public class AttDataAccessType : Attribute

    {

        private DataAccesType _dataAccesType;

        public DataAccesType DataAccesType

        {

            get { return _dataAccesType; }

            set { _dataAccesType = value; }

        }

 

        public AttDataAccessType(DataAccesType dataAccessType)

        {

            this._dataAccesType = dataAccessType;

        }

    }

}

O próximo atributo a ser criado é o atributo que conterá informações que irão possibilitar o mapeamento de uma propriedade de uma classe model com os parâmetros de uma stored procedure.

Aqui temos algumas ponderações a fazer.

A) Stored Procedures podem ter diversas finalidades ou tipos. Uma SP pode servir para realizar um Insert, um Update, Delete, Select. Pode – se realizar tabém algumas ou todas essas operações dentro de apenas uma Stored Procedure. Para nosso exemplo assumiremos os seguintes tipos de SPs:



public enum ProcedureTypes

    {

        Insert = 0,

        Update = 1,

        SelectNoFilter = 2,

        SelectFilter = 3,

        Delete = 4

}

B) Quando trabalhamos com chamadas de SP via código c#, precisamos utilizar objetos que informem dados relativos aos parâmetros de SPs como a Direction, o DBType, o Size etc. Então deveremos utilizar esse objetos como tipos de propriedades do nosso Atributo.

Abaixo segue o código completo de nosso atributo:



using System;

using System.Data;

 

namespace GenDAL.Library.Attributes 

{

    public enum ProcedureTypes

    {

        Insert = 0,

        Update = 1,

        SelectNoFilter = 2,

        SelectFilter = 3,

        Delete = 4

 

    }

     [AttributeUsage(AttributeTargets.Property, AllowMultiple=true)]

    public class AttParamProcDB : Attribute

    {

        private ProcedureTypes _tipoProcedure;

        private string _procName;

        private string _paramName;

        private DbType _dbType;

        private ParameterDirection _direction;

        private int _paramSize;

 

        public ProcedureTypes TipoProcedure

        {

            get { return _tipoProcedure; }

            set { _tipoProcedure = value; }

        }

        public string ProcName

        {

            get { return _procName; }

            set { _procName = value; }

        }

        public string ParamName

        {

            get { return _paramName; }

            set { _paramName = value; }

        }

        public DbType DbType

        {

            get { return _dbType; }

            set { _dbType = value; }

        }

 

        public ParameterDirection Direction

        {

            get { return _direction; }

            set { _direction = value; }

        }

 

        public int ParamSize

        {

            get { return _paramSize; }

            set { _paramSize = value; }

        }

 

        public AttParamProcDB(ProcedureTypes pProcTipo, string pProcName)

        {

            this._tipoProcedure = pProcTipo;

            this._procName = pProcName;

        }

 

        public AttParamProcDB(ProcedureTypes pProcTipo, string pProcName, string pParamName)

        {

            this._tipoProcedure = pProcTipo;

            this._procName = pProcName;

            this._paramName = pParamName;

        }

 

        public AttParamProcDB(ProcedureTypes pProcTipo, string pProcName, string pParamName, DbType pDbType)

        {

            this._tipoProcedure = pProcTipo;

            this._procName = pProcName;

            this._paramName = pParamName;

            this._dbType = pDbType;

        }

 

        public AttParamProcDB(ProcedureTypes pProcTipo, string pProcName, string pParamName, DbType pDbType, ParameterDirection pDirection)

        {

            this._tipoProcedure = pProcTipo;

            this._procName = pProcName;

            this._paramName = pParamName;

            this._dbType = pDbType;

            this._direction = pDirection;

        }

        public AttParamProcDB(ProcedureTypes pProcTipo, string pProcName, string pParamName, DbType pDbType, ParameterDirection pDirection, int paramSize)

        {

            this._tipoProcedure = pProcTipo;

            this._procName = pProcName;

            this._paramName = pParamName;

            this._dbType = pDbType;

            this._direction = pDirection;

            this._paramSize = paramSize;

        }

    }

}

Basicamente temos 6 propriedades que informarão o tipo de procedure, o nome da procedure, o nome do parâmetro o DbType do parâmetro o ParameterDirection e o Size. Temos também 5 construtores diferentes que inicializam conjuntos de propriedades específicos.

O próximo atributo a ser criado é o atributo que irá informar qual a tabela do banco de dados que a classe está representando. Portanto teremos apenas uma propriedade do tipo string que informará qual a tabela. Abaixo segue o código completo deste atributo.


using System;

 

namespace GenDAL.Library.Attributes

{

    [AttributeUsage(AttributeTargets.Class)]

    public class AttTableName : Attribute

    {

        private string _tableName;

 

        public string TableName

        {

            get { return _tableName; }

            set { _tableName = value; }

        }

        public AttTableName(string pTableName)

        {

            this._tableName = pTableName;

        }

 

    }

}

O próximo atributo é aquele que irá mapear as propriedades de uma classe com os campos da tabela que ela representa. Neste atributo, informamos o nome do campo da tabela e o tipo de dado deste campo:


using System;

using System.Data;

 

namespace GenDAL.Library.Attributes

{

    [AttributeUsage(AttributeTargets.Property)]

    public class AttFieldDB : Attribute

    {

        private string _fieldName;

        private DbType _dbType;

 

 

        public string FieldName

        {

            get { return _fieldName; }

            set { _fieldName = value; }

        }

        public AttFieldDB(string pFieldName)

        {

            this._fieldName = pFieldName;

        }

 

        public AttFieldDB(string pFieldName, DbType pDbType)

        {

            this._fieldName = pFieldName;

            this._dbType = pDbType;

        }

    }

}

Com nossos atributos criados, vamos compilar o projeto para gerarmos uma Dll. É importante observar a nomenclatura que demos na nossa Namaspace – ‘GenDAL.Library.Attributes’. Essa Namespace será referenciada para utilizarmos os nossos atributos em nosso projeto de classes ‘Model’.