Persistência de dados com Reflection

Luciano Lima (e-mail) é Microsoft Certified Professional C#, Diretor de Projetos da iArts Soluções e Tecnologia, ja atuou em empresas como CEF (Caixa Econômica Federal) e FGV (Fundação Getúlio Vargas), na área de Desenvolvimento de sistema. Atualmente presta serviços de consultoria em Desenvolvimento e Coordenação de Projetos para empresas no Brasil, Estado Unidos e Inglaterra, utilizando a platadorma .Net"

Olá pessoal! Finalmente acho que consegui voltar a escrever meus artigos, depois de tanto tempo de estudos e muuuito trabalho.

Pois bem, peço desculpas pelos e-mails não respondidos e pelos artigos não finalizados. Pensei até em finalizá-los, mas como muita coisa mudou de lá pra cá, resolvi não mexer com eles. Sendo assim, prefiro “investir” em artigos mais interessantes.

Para voltar com força total, resolvi escrever um artigo sobre Persistência de dados via Reflection, que será dividido em 2 etapas. Inicialmente vamos falar um pouco sobre Attribute, ver o que é e como criá-lo. Logo depois iremos ver Reflection, alguns conceitos, suas classes e utilização.

Pois bem, um dos maiores problemas, senão o maior, de nós desenvolvedores está relacionado com a forma na qual os bancos de dados são desenvolvidos. Isto é, nós programamos OO (Orientado ao Objeto), enquanto os banco de dados são ER (Entidades Relacionais), sendo assim, é um “saco” ficarmos escrevendo StoredProcedures, Instruções SQL e tal... Mudou uma tabela, lá vamos nós no código e/ou na procedure.

Não interessa qual foi a modificação, temos sempre que estar atentos às modificações feita no banco. Com uma programação utilizando Reflection, Attribute e algumas outras classes, podemos desenvolver nossos projetos sem nos preocuparmos com qual banco de dados iremos trabalhar. Com esse “bum” do .Net, nós programadores podemos criar muitas classes que fazem coisas que não eram possíveis antigamente, devido a forma na qual os dados eram gerados (compilados). Precisaríamos de programação de baixo nível para certar coisas. Mas nem tudo está perdido, que venha o .Net!

Inicialmente, vamos ver o que é um Atributo, ou seja Attribute, como é conhecido em .Net.

Não existe uma forma de “definirmos” um Attribute. Para que você possa entender melhor o que vem a ser, é preciso utilizar. Mas para início de conversa, vamos dizer que um Attribute é uma informação a mais que podemos acrescentar em nossos blocos de código dentro de uma montagem, exemplo disso, temos os método, propriedades e classes.

Você deve estar se perguntando "onde encontro um Attribute?". Bem, basta abrirmos um arquivo chamado AssemblyInfo.cs ou .vb para vermos Attributes em ação.

[assembly: AssemblyTitle("Persistencia")]

[assembly: AssemblyDescription("")]

[assembly: AssemblyCopyright("Copyright © 2006")]

[assembly: AssemblyTrademark("")]

[assembly: AssemblyCulture("")]

No exemplo acima temos os Attributes do arquivo AssemblyInfo.cs de nosso futuro projeto!

Ainda temos Attributes Internos, mais comumente utilizados no Framework, são eles:

- System.Diagnostics.ConditionalAttribute

- System.ObsoleteAttribute

- System.SerializableAttribute

- System.Reflection.AssemblyDelaySignAttribute

Estes Attributes pertencem ao .Net Framework, a idéia deste artigo é dar um visão geral dos mesmos, mas vamos nos concentrar em como criá-los e utilizar nossos próprios Atributos. Para saber mais sobre estes Attributes, dêem uma olhada na documentação do .Net Framework.

Para não passarmos em branco, vou deixar aqui um exemplo de Attribute:

System.Diagnotics.ConditionalAttribute

using System;

using System.Collections.Generic;

using System.Text;

using System.Diagnostics; //Obrigatório para utilizar Conditional

namespace Pessoa
{
class Program
{
static void Main( string[] args )
{
Program p = new Program( );

p.Display( );

p.DisplayDebug( );

Console.Read( );
}
public void Display( )
{
Console.WriteLine( "Display Normal!" );
}

[Conditional( "DEBUG" )] //Diz ao compilador para executar este método somente no modo DEBUG

public void DisplayDebug( )
{
Console.WriteLine( "Estou no Attribute Debug!" );
}
}
}

Mudando a forma de compilação de Debug para Release, vocês irão observar que o método public void DisplayDebug( ); não será executado. Esta é uma forma muito útil para testarmos nosso programas antes de o colocarmos em produção.

Como disse, não vou entrar em detalhes, mas para os mais curiosos, abram o arquivo *.exe gerado com o ILDASM, assim vocês poderam observar como é uma montagem.

Então, como vocês viram, esta é uma das formas na qual podemos utilizar atributos, mas eles vão muito além disso, atributos agregados a Reflection, podemos gerar códigos bem mais interessantes, como iremos ver a partir de agora!

Criando nosso próprio Attribute

Antes de criarmos nosso Attribute personalizado, devemos ter em mente que para criá-los devemos seguir duas regras básicas, são elas:

- Nossa class deve derivar de System.Attribute;

- Os construtores só poderão conter tipos que possam ser resolvidos, como strings e números inteiros.

A partir daí, podemos criar nossos atributos, lembrando que Attributes são nada menos que uma classe especial que segue os padrões acima citados.

Vamos lá.

Para iniciarmos, iremos criar as classes, conforme código abaixo.

Para aqueles que irão copiar e colar o código, atente para os comentários entre as classes, eles não fazem parte do código!

Neste código criamos 3 classes que são: TableAttribute, ColumnAttribute e KeyAttribute.

TableAttribute – responsável por informar o nome de nossa Tabela no banco

ColumnAttribute – responsável pelas colunas em nosso banco.

KeyAttribute – responsável pelas chaves primárias em nossas colunas.

using System;

using System.Collections.Generic;

using System.Text;

namespace Persistencia
{

Na classe TableAttribute, definimos seu construtor para receber apenas o nome da tabela (tableName), bem como para recuperarmo seu valor, chamamos a propriedade TableName. Veja no código abaixo:

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

public class TableAttribute : Attribute
{
private string _tableName;

public string TableName
{
get { return _tableName;
}
}
public TableAttribute( string tableName )
{
this._tableName = tableName;
}
}

Na classe acima ColumnAttribute, definimos seu construtor para receber o nome da coluna, seu tipo e um tamanho, isto por que iremos utilizar futuramente.

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

public class ColumnAttribute : Attribute
{
private string _columnName;

private ColumnType _cType;

private int _columnSize;

public int ColumnSize
{
get { return _columnSize; }

set { _columnSize = value; }
}

public ColumnType CType
{
get { return _cType; }

set { _cType = value; }
}
public string ColumnName
{
get { return _columnName; }
}

public ColumnAttribute( string columnName, ColumnType type, int size )
{
this._columnName = columnName;

this._cType = type;

this._columnSize = size;
}
}

Nessa parte, criamos uma Enumeração (enum) de tipos, para serem setados no tipo da coluna ColumnType

/// <summary>

/// Tipos de campos para as colunas

/// </summary>

public enum ColumnType
{
Int32,

String,

DateTime
}

Para a classe KeyAttribute, definimos somente o nome da chave keyName

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

public class KeyAttribute : Attribute
{
private string _keyName;

public string KeyName
{
get { return _keyName; }

set { _keyName = value; }
}

public KeyAttribute( string key )
{
this._keyName = key;
}
}
}

Observem que todas as classes (TableAttribute, ColumnAttribute e KeyAttribute) herdam de System.Attribute, pois sem essa herança não conseguiremos criar nossos atributos. Para que possamos criar nossos atributos, devemos também utilizar atributos prontos, como é o caso de AttributeUsage, que irá definir em qual parte de código nosso atributo será aceito, dentre eles temos AttributeTargets.Class, Method, Property, Enum, Event, Delegates dentre outros. Observem o código abaixo:

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

public class TableAttribute : Attribute

Nele definimos alguns itens a mais, como mostrado:

AllowMultiple – define se o usuário poderá acrescentar mais de um atributo ao mesmo elemento.

Inherited – define se será possível de ser herdado, ou seja, caso a class seja herdada seu atributo irá ser herdado também.

Para as classes ColumnAttribute e KeyAttribute, definimos AllowMultiple com sendo false e Inherited como sendo true, assim nossos atributos Colum e Key não aceitarão outros atributos na mesma propriedade, porém eles podem ser herdados.

Estas classes que acabamos de criar irão definir nossos atributos personalizado, onde através deles iremos criar nossa “Class de Persistência” via Reflection.

Como disse, não entrei em detalhes, pois acho que uma boa pesquisada na Internet sobre o assunto poderá clarear mais a idéia de vocês.

Este artigo foi bem simples, não entramos em detalhes complexos, mas creio que deva ter dado para introduzi-los no mundo dos Attributes.

Para aqueles que não entenderam, peço um pouco de paciência, pois verão que é muito produtivo trabalharmos com Attribute e Reflection.

Aguardem o próximo artigo, ele estará “felomenau”, como diria um amigo meu!

Espero que tenham gostado!

Abraço a todos!