Atribuindo do BD para a classe via Reflection
No primeiro artigo prático da série Reflection na Prática: Uso na Classe de Conexão irei abordar como é construído o método Select() da Classe de Conexão, que além da já tradicional forma de atribuição “manual” faz o uso do Reflection para atribuir os valores de um registro do Banco de Dados para as variáveis privadas (e consequentemente na propriedade que expõe esta variável) da classe que implementa esta tabela.
Antes de entrar no método proprieamente dito, vou lembrar aqui a condição básica para isto funcionar: os campos (variáveis privadas) do objeto DEVEM ser nomeados conforme os campos da tabela do banco de dados precedido de underline. Por exemplo, se tivermos um campo chamado NOME a classe que implementa a tabela deverá ter uma variável privada chamada _NOME.
Com o lembrete, vamos ao método Select:
1: protected void Select(bool HaveParams)
2: {
3: DataTable dt = this.getTable(this._SelectSQL, HaveParams);
4: try
5: {
6: Type t = this.GetType();
7: if (dt.Rows.Count > 0)
8: {
9: foreach (DataColumn dc in dt.Rows[0].Table.DefaultView.Table.Columns)
10: {
11: this.ListaCamposTabela.Add(new TCampoCadastro(dc.ColumnName, dt.Rows[0][dc.ColumnName], dc.Unique));
12: //Bind direto na variável privada, via reflection. Segue convenção: Nome da var. privada = nome do campo da tabela seguido de underline.
13: FieldInfo fi = t.GetField("_" + dc.ColumnName.ToUpper(), BindingFlags.NonPublic | BindingFlags.Instance);
14: if (fi != null)
15: {
16: try
17: {
18: fi.SetValue(this, ConverterDB2Obj(dt.Rows[0][dc.ColumnName], fi.FieldType));
19: }
20: catch
21: {
22: //Não faz nada, esse try..catch é somente para não sair do foreach e manter a compatibilidade com a atribuição manual, dentro da classe derivada.
23: }
24: }
25: }
26: }
27: }
28: catch (Exception ex)
29: {
30: fMsgInfo = ex.Message;
31: }
32: finally
33: {
34: dt.Dispose();
35: }
36: }
Para pegar o registro que estamos interessado da base de dados, utilizamos o método GetTable() passando a instrução SQL necessária para fazê-lo e colocamos em um DataTable (sim, ele terá apenas UMA linha, um DataReader poderia ser utilizado para fazer isso também).
Ao verificar se a tabela tem linhas, a brincadeira começa.
Com um laço foreach varro todas as colunas desta tabela, e imediatamente adiciono na coleção ListaCamposTabela uma nova instância da classe TCampoCadastro, que em seu construtor pede o nome da coluna e o valor, e se a coluna pertence à chave.
Para pegar o valor, como no DataTable temos apenas a linha 0, utilizo como índice da coluna o próprio nome da coluna que está na variável “dc”, declarada no foreach.
Este método é o utilizado na versão anterior da Classe de Conexão e foi mantido para manter a compatibilidade com os sistemas em que já está implementado desta forma.
A brincadeira com Reflection começa agora! :-D
A classe FieldInfo contém propriedades para sabermos sobre as propriedades de uma classe, além de fornecer métodos para manipular os valores das propriedades e variáveis privadas (que é o nosso caso) de um objeto.
Antes do foreach, guardo na variável “t”, do tipo Type, as informações sobre os metadados do próprio objeto, que neste caso vai ser do tipo “filho”: lembre-se que a Classe de Conexão é sempre herdada por outro objeto.
Com esta variável, instancio na variável “fi” um objeto do tipo FieldInfo, que para inicializá-lo eu utilizo o método GetField() da classe Type (a nossa variável “t”).
Este método pede como parâmetros o nome da propriedade, que no nosso caso é o nome da coluna do DataTable que está sendo iterada no momento precedido de underline, e os BindingFlags, que são condições que determinam qual será a abrangência dos metadados a serem pesquisados e consequentemente disponíveis no GetField(): BindingFlags.NonPublic indica que queremos que as variáveis privadas estejam na pesquisa, e BindingFlags.Instance indica que queremos que variáveis de instância (não estáticas) estejam incluídas na pesquisa.
Caso o método GetField() retorne alguma coisa, estas informações estarão disponíveis na variável “fi”, e a partir dela poderemos alterar esta propriedade em qualquer objeto da classe que temos na variável “t”.
Para isso, utilizaremos o método SetValue() da classe FieldInfo.
Este método pede como parâmetros o objeto em que a propriedade terá o valor atribuído, no nosso caso, é o próprio objeto, denotado pelo ponteiro this e o valor a ser atribuído, que neste caso é o valor da coluna no registro do DataTable.
A função ConverterDb2Obj faz a conversão do tipo de dado que está no banco de dados para um tipo de dados “destino”, que no nosso caso é o tipo da propriedade que está sendo atribuída. Isto e importante para os casos em que os valores do banco de dados estejam nulos, e vem com o tipo DBNull.Value, que é incompatível com o “null” normal, de objetos.
E esse try…catch com o catch vazio, hein?
Caso dê algum problema na atribuição, ele serve para continuar a iteração nos demais campos da tabela, ou seja, para não haver paradas e para o método “antigo” ainda funcionar.
Com isso, atribuímos diretamente os valores que vem do BD para a classe. Para um exemplo prático, veja os artigos sobre o Simple PIM :-)
Um abraço!
0 comentários:
Postar um comentário