Dans l'article "Strong Delphi RTTI - Une discussion sur la nécessité de comprendre plusieurs langages de développement", j'ai dit que j'avais utilisé le RTTI de Delphi pour implémenter une objectivation simple des ensembles de données. Cet article présentera en détail ma méthode de mise en œuvre.
Commençons par un exemple simple: supposons qu'il existe un contrôle Adodataset qui se connecte à la base de données Roswen, et SQL est:
Sélectionner * parmi les employés
Vous devez maintenant afficher les quatre champs EmployeeId, FirstName, LastName et Birth Date dans son contenu dans la ListView. Le code traditionnel est le suivant:
Avec Adodataset1 commencez à ouvrir; FieldByName («LastName»).
Il y a plusieurs problèmes principaux ici:
1. Tout d'abord, il y a beaucoup de codes très verbeux. Par exemple, FieldByName et Asxxx, etc., en particulier ASXXX, vous devez toujours vous souvenir du type de chaque champ, ce qui est facile à faire des erreurs. De plus, si certains types incompatibles ne peuvent pas être automatiquement convertis, les erreurs ne seront pas trouvées avant l'exécution.
2. Vous devez traiter vous-même le mouvement d'enregistrement actuel dans la boucle. Comme le prochain, sinon une boucle morte se produira une fois que vous l'oubliez.
3. La chose la plus importante est que le nom du champ est passé par le paramètre de la chaîne. FieldByName, il est probable que le problème n'apparaîtra que s'il est retardé pour le client. Ce type de mauvais noms de champ est facile à se produire, surtout lorsque le programme utilise plusieurs tables, il est facile de confondre les noms de champ de différentes tables.
À cette époque régie par OO, lorsque nous rencontrons des opérations liées aux ensembles de données, nous devons toujours tomber dans les détails de la base de données relationnelle mentionnée ci-dessus. Bien sûr, il existe également un moyen de s'en débarrasser maintenant, c'est-à-dire la cartographie O / R, mais la cartographie O / R est trop différente des méthodes de développement traditionnelles après tout, en particulier pour certaines petites applications, il n'est pas nécessaire d'exagérer It.
Inspiré par Java et d'autres langages dynamiques, j'ai pensé à utiliser le puissant RTTI de Delphi pour implémenter ce schéma d'objectivation de l'ensemble de données simple. Ce qui suit est le code d'application objectivé de l'ensemble de données qui implémente les mêmes fonctions que le code traditionnel:
Type TDSPEMPLOYEE = CLASSE (TMDATASETPROXY) Propriété publiée EmployeeId: Integer Index 0 Read GetInteger Write SetInteger; SetVariant; end; procédure tform1.listClick (expéditeur: tobject); var emp: tdSpemployee; (Emp.EmployeeId); Emp.free; fin;
L'utilisation est très simple. La chose la plus importante est de définir d'abord une classe de proxy, qui utilise l'attribut publié pour définir tous les champs, y compris leurs types, puis vous pouvez manipuler l'ensemble de données de manière objet. Cette classe de proxy est dérivée de TMDATASetProxy, qui utilise RTTI pour implémenter le mappage des opérations d'attribut aux opérations de champ. Les unités de mise en œuvre de cette classe seront expliquées en détail ci-dessous.
En surface, il existe une classe de proxy supplémentaire qui définit l'ensemble de données, qui semble avoir plus de code, mais c'est une chose unique, surtout lorsque le programme doit réutiliser la même structure d'ensembles de données à plusieurs reprises, le code sera fait. De plus, la définition de cette classe proxy est très simple. Les fonctions d'accès à l'attribut getxxx / setxxx utilisées sont toutes implémentées dans la classe de base tmdatasetproxy.
Regardons maintenant la boucle correspondant au code d'origine:
1. FieldByName et Asxxx ne sont pas nécessaires, et ils sont devenus des opérations d'attribut sur les classes proxy. It. Si le mauvais type est utilisé, une erreur sera signalée lors de la compilation.
2. Utilisez un foreach pour effectuer une traversée record et ne vous inquiétez pas d'oublier la boucle vicieuse causée par la prochaine.
3. Le plus grand avantage est que le nom du champ devient une propriété, vous pouvez donc profiter des avantages de la vérification du nom de champ au moment de la compilation.
Maintenant, commencez à discuter de tmdatasetproxy. Le code de son implémentation est le suivant:
(************************************************* ********************** Le proxy de données implémenté avec RTTI peut simplement objectiver l'ensemble de données.Date: 28-05 janvier ****************************************** * *****. (Aindex: entier): shortstring; Fonction GetProp (Aindex: Integer): PPROPINFO; ; ; ; : Tdataset); ClassInfo) ^. (FPROPLIST) alors FreeMem (FPROPLIST); Tmproplist.getPropName (aindex: entier): shortstring; begin result: = getprop (aindex) ^. Name; fin; {tmrefdataset} ; end; procédure tmdatasetproxy.beginedit; begin if (fdataset.state <> dsedit) et (fdataset.state <> dsinsert) puis fdataset.edit; end; procédure tmdatasetproxy.endit; begin if (fdataset.state = dsedit) ou (fdataset .State = dsinsert) puis fdataset.post; fin; fonction tmdatasetproxy.getInteger (aindex: entier): Integer; : Entier): double; begin résultat: = fdataset.fieldByName (fproplist.propNames [aindex]) .asfloat; fin; fonction tmdatasetproxy.getString (aindex: entier): string; begin result: = fdataset.fieldByName (fproplist .propNames [ aindex]) .assstring; end; fonction tmdatasetproxy.getVariant (aindex: Integer): variant; begin result: = fdataset.fieldByName (fproplist.propNames [aindex]) .value; end; procédure tmdatasetproxy.setInteger (aIndex, Avalue: Integer: Integer )). ]) .Asfloat: = Avalue; fin; procédure tmdatasetproxy.setstring (aindex: entier; Avalue: String); beginbeginedit; aindex: entier; Avalue: Variant); Commencez à terminer;
La classe TMProplist est une encapsulation de certaines fonctions de l'opération d'attribut de RTTI. Sa fonction consiste à utiliser certaines fonctions RTTI définies par Delphi dans l'unité Typefo pour implémenter une classe dérivée tpersistent pour maintenir ses informations de liste de propriétés publiées. La classe proxy obtient le nom d'attribut via cette liste d'attributs et fonctionne enfin via ce nom d'attribut et les champs correspondants de l'ensemble de données.
TMDATASETPROXY est la classe de base de la classe Proxy de l'ensemble de données. La partie la plus importante est de créer une liste de propriétés dans la suite.
Le fonctionnement des attributs implémente uniquement quatre types de données: entier, double / float, chaîne et variante. Si nécessaire, vous pouvez dériver votre propre classe de base proxy sur cette base pour implémenter la mise en œuvre d'autres types de données. La mise en œuvre du remplacement de celle-ci. Cependant, pour les types qui ne sont pas très couramment utilisés, il est recommandé de définir la classe de proxy réelle avant de la mettre en œuvre. Par exemple, dans l'exemple précédent, en supposant que TdateTime n'est pas un type couramment utilisé, vous pouvez le faire:
TDSPEMPLOYEE = CLASSE (TMDATASETPROXY) Fonction Protégée GetDateTime (const Index: Integer): TDATETime; Procédure SetDateTime (const: INTERNET INTERNE; CONSTAGE: TDATETIME); Lire getString SetString; (GetVariant (index); fin; procédure tDSPEMPLOYEE.SetDateTime (const: INTEGER; const Value: TdateTime);
De cette façon, vous pouvez utiliser directement la date de naissance comme type tdatetime.
De plus, en profitant de cela, il est possible de fournir des opérations unifiées pour certains types de données spéciaux personnalisés.
De plus, BeginDedit a été appelé avant tous les Setxxx pour éviter les erreurs d'exécution causées par l'oubli pour utiliser DataSet.Edit.
ForEach est mis en œuvre pour être réutilisable. De plus, EndEdit est appelé avant de soumettre automatiquement les modifications.
Ce schéma d'objectivation de l'ensemble de données est une solution très simple. En effet, Delphi est toujours un langage de développement natif après tout. Aucune dynamique, vous ne pouvez donc utiliser la méthode actuelle que pour vous inscrire.