No artigo "Strong Delphi Rtti - uma discussão sobre a necessidade de entender vários idiomas de desenvolvimento", eu disse que usei o RTTI da Delphi para implementar uma simples objetificação de conjuntos de dados. Este artigo apresentará meu método de implementação em detalhes.
Vamos começar com um exemplo simples: suponha que haja um controle do Adodataset que se conecte ao banco de dados de Roswen, e o SQL é:
Selecione * do funcionário
Agora você precisa exibir o Four Fields EmployeeID, FirstName, LastName e Birthdate em seu conteúdo no ListView. O código tradicional é o seguinte:
Com o adodataSet1 Começa aberto; FieldByName ('Nome') .Assring);Existem vários problemas principais aqui:
1. Primeiro de tudo, existem muitos códigos que são muito detalhados. Por exemplo, FieldByName e ASXXX, etc., especialmente asxxx, você deve sempre lembrar que tipo de campo é, o que é fácil de cometer erros. Além disso, se alguns tipos incompatíveis não puderem ser convertidos automaticamente, os erros não serão encontrados até o tempo de execução.
2. Você precisa processar o movimento atual do registro no loop. Como o próximo acima, caso contrário, um loop morto ocorrerá quando você esquecer. Embora esse problema seja fácil de detectar e lidar, os programadores não devem estar enredados com detalhes tão pequenos.
3. O mais importante é que o nome do campo seja passado através do parâmetro da string. FieldByName, é provável que isso faça com que o problema só apareça se estiver atrasado para o cliente. É fácil acontecer esse tipo de nomes de campos errados, especialmente quando o programa usa várias tabelas, é fácil confundir os nomes de campo de diferentes tabelas.
Nesta época, governada pela OO, quando encontramos operações relacionadas a conjuntos de dados, ainda precisamos cair nos detalhes do banco de dados relacional mencionado acima. Obviamente, há também uma maneira de se livrar deles agora, isto é, mapeamento de O/R, mas o mapeamento de O/R é muito diferente dos métodos de desenvolvimento tradicionais, afinal, especialmente para algumas pequenas aplicações, não há necessidade de exagerar It.
Inspirado no Java e em outros idiomas dinâmicos, pensei em usar o poderoso RTTI da Delphi para implementar esse esquema de objetivificação simples do conjunto de dados. A seguir, é apresentado o código do aplicativo objetivado do conjunto de dados que implementa as mesmas funções do código tradicional:
TIPO TDSPEMSPOLHO = CLASSE (TMDATASETPROXY) PROPRIEDADE PROPRIEDADEIRO: ÍNDICE INTERGENTE 0 LEIA Getinteger Write Setinteger; SetVarian; final; procedimento TForm1.ListClick (remetente: TObject); VAR EMP: TDSPEMPLAYE; (Emp.EmployeeD); Emp.Free;
O uso é muito simples. O mais importante é definir primeiro uma classe de proxy, que usa o atributo publicado para definir todos os campos, incluindo seus tipos, e você pode manipular o conjunto de dados de uma maneira de objeto. Essa classe proxy é derivada do TMDataSetProxy, que usa o RTTI para implementar o mapeamento das operações de atributo para operações de campo. As unidades de implementação desta classe serão explicadas em detalhes abaixo.
Na superfície, há uma classe de proxy extra que define o conjunto de dados, que parece ter mais código, mas isso é uma coisa única, especialmente quando o programa precisa reutilizar a mesma estrutura de conjuntos de dados muitas vezes, o código será feito. Além disso, a definição dessa classe proxy é muito simples. As funções de acesso ao atributo getxxx/setxxx usadas são todas implementadas na classe base tmdatasetProxy.
Agora vamos olhar para o loop correspondente ao código original:
1. FieldByName e ASXXX não são necessários e eles se tornaram operações de atributo nas classes de proxy. isso. Se o tipo errado for usado, um erro será relatado durante a compilação.
2. Use um forach para executar o Record Traversal e não precisa mais se preocupar em esquecer o loop cruel causado pelo próximo.
3. A maior vantagem é que o nome do campo se torna uma propriedade, para que você possa aproveitar os benefícios da verificação do nome do campo no horário de compilação.
Agora comece a discutir o tmdatasetProxy. O código de sua implementação é o seguinte:
(***************************************************** ********************** Proxy do conjunto de dados implementado com o RTTI pode simplesmente objetivar o conjunto de dados.Data: Jan.28-05 ****************************************** ********************* (Aindex: Inteiro): Função Short; Propriedade de propriedade [Aindex: Função virtual virtual; Procedimento virtual; : Destruir; Classinfo)^PropCount; (FPROPLIST) então Freemem (FPROPLIST); Tmproplist.getPropname (Aindex: Inteiro): ShortString; BEGIN BRILITO: = GETPROP (AINDEX)^. Nome; END; {Tmrefdataset} Construtor TmdataSet FALSO; end; procedimento tmdatasetProxy.Beginedit; Begin if (fdataset.state <> dsedit) e (fdataset.state <> dsinsert) depois fdataset.edit; end; procedimento tmdatasetProxy.end; .State = dsinsert) Então fdataset.post; end; função tmdatasetproxy.getInteger (AINDEX: Inteiro): Inteiro; : Integer): duplo; início do resultado: = fdataset.fieldbyname (fproplist.propnames [aindex]) .asfloat; end; function tmdatasetProxy.getString (AIndex: inteiro): string; resultado: = fdataset.fieldbyName (froplist. aindex]) .ASSTRING; END; FUNÇÃO TMDATASETPROXY.GETVARONT (AINDEX: INTEGER): VARIANT; BEGN RESULTO: = fdataset.fieldbyName (fProplist.propNames [Aindex]) .Value; End; procedimento tmdatasetProxy.setinteger (AINDEXTERGER (AINDEX). ); ]) .Asfloat: = Avalue; end; procedimento tmdatasetProxy.SetString (Aindex: Integer; Avalue: String); BeginBeginedit; Aindex: Inteiro; BEGINE ENDIDO;
A classe TMPROPLIST é um encapsulamento de algumas funções da operação de atributo da RTTI. Sua função é usar algumas funções RTTI definidas por Delphi na unidade Typinfo para implementar uma classe derivada do TPERSISTENT para manter suas informações publicadas na lista de propriedades. A classe Proxy obtém o nome do atributo através desta lista de atributos e, finalmente, opera com esse nome de atributo e os campos correspondentes no conjunto de dados.
O tmdatasetProxy é a classe base da classe Proxy do conjunto de dados. A parte mais importante é criar uma lista de propriedades na pós -construção.
A operação de atributos implementa apenas quatro tipos de dados: número inteiro, dupla/flutuação, string e variante. Se necessário, você pode derivar sua própria classe base de proxy nessa base para implementar a implementação de outros tipos de dados. A implementação da substituição dele. No entanto, para tipos que não são muito usados, é recomendável definir a classe de proxy real antes de implementá -la. Por exemplo, no exemplo anterior, assumindo que o TDATETIME não é um tipo comumente usado, você pode fazer isso:
TDSPEMPLAYE = Classe (TMDatasetProxy) Função protegida GetDateTime (Const Index: Inteiro): TDATETIMENTE; Leia o Settring SetString; (GetVariant (índice); final; procedimento TDSPEMPLAYEE.SETDATETIMENTE (INDEX DE CONSTRUIÇÃO: INTERGEM;
Dessa forma, você pode usar diretamente a data de nascimento como o tipo TDATETIME.
Além disso, aproveitando isso, é possível fornecer operações unificadas para alguns tipos de dados especiais personalizados.
Além disso, o BELINGIT foi chamado antes de todo o setxxx para evitar erros de tempo de execução causados pelo esquecimento de usar o DataSet.edit.
O foreach é implementado para ser reutilizado. Além disso, o EndEdit é chamado antes de enviar automaticamente as alterações.
Esse esquema de objetificação do conjunto de dados é uma solução muito simples. Isso ocorre porque o Delphi ainda é uma linguagem de desenvolvimento nativa, afinal. Sem dinâmico, então você pode usar apenas o método atual para se registrar.