Access _ les macros de données

16
Access Les macros de données - Partie 2 : Historisation Dans cette 2 ème partie du didacticiel dédié aux macros de table, nous allons générer l'historisation de toutes les tables d'une base de données (Ajouts, suppressions , et modifications de n'importe quel champ de n'importe quelle table) Pour suivre ce didacticiel, il est nécessaire d'avoir compris les macros de table expliquées dans la première partie. Sommaire Introduction 1. Démonstration initiale 2. Historisation des ajouts 3. Macros nommées 4. Paramètres des macros 5. Historisation des nouveaux enregistrements 6. Réutilisabilité des macros nommées 7. Traque des erreurs à l'aide de USYSApplicationLog 8. Mise à jour des paramètres 9. Historisation des suppressions 10. Historisation des modifications 11. Ne pas historiser les données inchangées 12. Problèmes inhérents aux paramètres vides 13. Limites du champ d'action des macros de table 14. Récupération du nom d'utilisateur 15. Création d'un formulaire pour l'utilisation d'une fonction 16. Interaction Formulaires/Tables/Macros de tables 17. Formulaires plus performants 18. Comparaison Macros de table/Utilisation de formulaires 19. Introduction Je vous propose de télécharger cette base de données qui va nous servir de base pour cet exercice. Vous y découvrirez 3 tables : les deux tables "de travail" : Je prends l'exemple de deux tables seulement, mais l'historisation que je vais vous proposer fonctionnera aussi bien avec 3, 4 ou 50 tables différentes. Dans mon exemple, j'ai une table T_Materiel, qui recense une liste de différents accessoires destinés à la vente. L'autre table, T_Service, liste toutes les prestations possibles (pour une société de services informatique). Tout ce que nous faisons subir à l'une ou l'autre table (ajout, suppression ou modification d'un ou plusieurs enregistrements dans n'importe laquelle de ces tables, doit être répercuté automatiquement dans la 3 ème table : T_HistoriqueMultiTable que voici : Démonstration initiale Afin de vous aider à comprendre la finalité de notre exercice, je vais effectuer quelques modifications dans l'une et l'autre table, pour vous montrer comment ça va se répercuter dans T_HistoriqueMultiTable. 1. Dans T_Materiel, J'efface l'article N° 3 : Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php 1 of 16 2/14/2013 10:04

description

Tutoriel MS ACCESS 2010 sur les Macros de donnée

Transcript of Access _ les macros de données

Page 1: Access _ les macros de données

AccessLes macros de données - Partie 2 : Historisation

Dans cette 2ème partie du didacticiel dédié aux

macros de table, nous allons générer

l'historisation de toutes les tables d'une base de

données (Ajouts, suppressions, et modifications

de n'importe quel

champ de n'importe quelle table)

Pour suivre ce didacticiel, il est nécessaire d'avoir

compris les macros de table expliquées dans la

première partie.

Sommaire

Introduction1.Démonstration initiale2.Historisation des ajouts3.Macros nommées4.Paramètres des macros5.Historisation des nouveaux enregistrements6.Réutilisabilité des macros nommées7.Traque des erreurs à l'aide de USYSApplicationLog8.Mise à jour des paramètres9.Historisation des suppressions10.Historisation des modifications11.Ne pas historiser les données inchangées12.Problèmes inhérents aux paramètres vides13.Limites du champ d'action des macros de table14.Récupération du nom d'utilisateur15.Création d'un formulaire pour l'utilisation d'une fonction16.Interaction Formulaires/Tables/Macros de tables17.Formulaires plus performants18.Comparaison Macros de table/Utilisation de formulaires19.

IntroductionJe vous propose de télécharger cette base de données qui va nous servir de base pour cet exercice.

Vous y découvrirez 3 tables :

les deux tables "de travail" :

Je prends l'exemple de deux tablesseulement, mais l'historisation que jevais vous proposer fonctionnera aussibien avec 3, 4 ou 50 tables différentes.

Dans mon exemple, j'ai une tableT_Materiel, qui recense une liste dedifférents accessoires destinés à lavente.

L'autre table, T_Service, liste toutes lesprestations possibles (pour une société de services informatique).

Tout ce que nous faisons subir à l'une oul'autre table (ajout, suppression oumodification d'un ou plusieursenregistrements dans n'importe laquellede ces tables, doit être répercuté

automatiquement dans la 3ème table :

T_HistoriqueMultiTableque voici :

Démonstration initiale

Afin de vous aider à comprendre la finalité de notre exercice, je vais effectuer quelques modifications dans l'une et l'autre table, pour vousmontrer comment ça va se répercuter dans T_HistoriqueMultiTable.

1. Dans T_Materiel, J'efface l'article N° 3 :

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

1 of 16 2/14/2013 10:04

Page 2: Access _ les macros de données

Les champs OLE et Pièces jointes nepourront pas être historisés, puisqu'ilscontiennent carrément des fichiers externes,impossibles à traduire en simple texte.

2. Dans T_Materiel, J'ajoute une webcam, avec son PrixAchat et PrixVente

3. Dans T_Materiel, je modifie Clavier 102 touches en Clavier QWERTZ, et jepasse son PrixVente de 47 à 52.90

4. Dans T_Materiel, j'efface le PrixVente de la souris sans fil (ce qui aura pour effetde le remettre à 0):

5. Dans T_Materiel, je passe le PrixAchat de la Webcam de 54.00 à 47.50 :

6. Dans T_Service, j'efface les prestations N°3 et 4 :

Voyons le résultat dans T_HistoriqueMultiTable :

Reprenons nos exemples un par un :

1. le 16.1.2013, à 23:04, j'effectue une suppression dans la table T_Materiel. Le premier champ (IDMatériel)contenait l'ancienne valeur 3, le Libelle contenait Webcam, le PrixAchat : 48 et PrixVente : 69.9 (Ces deux dernierschiffres sont ici stockés en format Texte ) 2. à 23:07, j'ajoute une nouvelle ligne dans T_Materiel : ce sont ainsi des nouvelles valeurs qui sont introduitesdans la base de données, c'est pour cette raison que les données dont décalées par rapport à la suppressionAncienneValeur et NouvelleValeur). 3. Cette fois, à 23:13, j'effectue une modification : L'IDMateriel est un NuméroAuto qui ne risquedonc pas de changer : il reste à 2. Dans le champ Champ2, il s'agit du Libelle, et là, on voit que j'aichangé le nom : je passe de Clavier 102 touches à Clavier QWERTZ. Comme je n'ai pas modifié leprix d'achat, ces deux cases sont laissées vides. Par contre, comme j'en ai profité du même coup pourmodifier le PrixVente : j'indique logiquement l'ancien et le nouveau : de 47 à 52.9 4. Il s'agit à nouveau d'une modification - et pas d'une suppression - j'efface juste le contenu d'un seul champ : le prix de vente. Plusprécisément, je le passe de 49 à 0. On verra par la suite comment exiger qu'il passe de rien à 0 (sinon, on ne peut pas à lui faire comprendre qu'un

champ passe d'une certaine valeur à ... complètement vide). 5. Je m'occupe à nouveau de l'article N°6 (que j'avais déjà modifié un peu plus haut : Création de la webcam). Bien que l'enregistrement ait été créé à23:07, on voit qu'on revient sur ce même enregistrement à 23:38 (pour descendre son prix d'achat de 54 à 47.5). 6. (6 et 7 plus exactement - puisqu'on a sélectionné deux enregistrements en même temps dans T_Service). Voicitous les détails de ces deux suppressions qui ont donc été effectuées exactement en même temps à 23:44 et 33secondes.Les trois dernières colonnes (qui concernent le champ 4) ne sont pas remplies ici, pusiqu'il n'y a pas 4 colonnesdans cette table, mais seulement 3 (C'est dans T_Materiel qu'il y a 4 colonnes - ou 4 champs).

Avez-vous compris pourquoi tous les champs de T_HistoriqueMultiTable sont définis en Texte (qui est le format de données le plus universel) ?

Parce que, selon les tables, le contenu des différents champs pourra être en Texte , en Numérique , en Date-Heure , ... Il faut que nouspuissions stocker de toute façon les contenus de tous les champs des différentes tables dans T_HistoriqueMultiTable.

Dans notre cas, le Champ3 contient soit PrixAchat, soit PrixForfaitaire, qui sont tout

deux des numériques, certes, mais il peut très bien arriver que le 3ème champ d'uneautre table soit du texte , une case à cocher Oui/Non , ou une Date !

Ainsi, si vous avez compris le principe, le nombre de champsde T_HistoriqueMultiTable se monte à 4 fois 3 (ChampX,AncienneValeurX, NouvelleValeurX) parce que le plus grand nombre de champs de toutes mes (deux) tables est de 4 (ils'agit ici de T_materiel avec les 4 champs suivants : IDmateriel, Libelle, PrixAchat et PrixVente).

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

2 of 16 2/14/2013 10:04

Page 3: Access _ les macros de données

Si vous désirez mettre en oeuvre ce même système d'historique sur votre base de données, qui comprend certainestables qui possèdent peut-être plus de 20 champs, il faudra le même nombre de champs (20 fois 3, donc 60) dans

T_HistoriqueMultiTable - A moins que vous ne décidiez que certains champs sont inutiles à historiser, évidemment.

Sous le 6, il n'y a pas d'enregistrement, on voit juste la valeur par défaut du moment, mais ne vous inquiétez pas, ce moment sera parfaitementmis à jour lorsque vous effectuerez d'autres changements dans les deux autres tables.

Historisation des ajoutsNous allons commencer par historiser les ajouts de nouveau matériel.

Allez dans T_Materiel, dans la macro , et recopiez la macro suivante (Le XML a copier-coller est sous l'image - Cliquez ici pour vous

rappeler) :

Ensuite, essayez d'ajouter le Scanner dans T_Materiel, puis fermez T_Materiel, et ouvrez T_HistoriqueMultiTable :

<?xml version="1.0" encoding="UTF-16" standalone="no"?><DataMacros xmlns="http://schemas.microsoft.com/office/accessservices/2009/11/application"><DataMacro Event="AfterInsert"><Statements><Action Name="SetLocalVar"><Argument Name="Name">VARIDMateriel</Argument><Argument Name="Value">[IDMateriel]</Argument></Action><Action Name="SetLocalVar"><Argument Name="Name">VARLibelle</Argument><Argument Name="Value">[Libelle]</Argument></Action><Action Name="SetLocalVar"><ArgumentName="Name">VARPrixAchat</Argument><Argument Name="Value">[PrixAchat]</Argument></Action><Action Name="SetLocalVar"><Argument Name="Name">VARPrixVente</Argument><Argument Name="Value">[PrixVente]</Argument></Action><CreateRecord><Data><Reference>T_HistoriqueMultiTable</Reference></Data><Statements><Action Name="SetField"><Argument Name="Field">[GenreChangement]</Argument><Argument Name="Value">"Ajout"</Argument></Action><ActionName="SetField"><Argument Name="Field">[TableOrigine]</Argument><Argument Name="Value">"T_Materiel"</Argument></Action><Action Name="SetField"><Argument Name="Field">[Champ1]</Argument><Argument Name="Value">"IDMateriel"</Argument></Action><Action Name="SetField"><Argument Name="Field">[NouvelleValeur1]</Argument><Argument Name="Value">[VARIDMateriel]</Argument></Action><Action Name="SetField"><Argument Name="Field">[Champ2]</Argument><Argument Name="Value">"Libelle"</Argument></Action><Action Name="SetField"><Argument Name="Field">[NouvelleValeur2]</Argument><Argument Name="Value">[VARLibelle]</Argument></Action><Action Name="SetField"><ArgumentName="Field">[Champ3]</Argument><Argument Name="Value">"PrixAchat"</Argument></Action><Action Name="SetField"><Argument Name="Field">[NouvelleValeur3]</Argument><Argument Name="Value">[VARPrixAchat]</Argument></Action><Action Name="SetField"><Argument Name="Field">[Champ4]</Argument><Argument Name="Value">"PrixVente"</Argument></Action><Action Name="SetField"><Argument Name="Field">[NouvelleValeur4]</Argument><Argument Name="Value">[VARPrixVente]</Argument></Action></Statements></CreateRecord></Statements></DataMacro></DataMacros>

Macros nomméesCette macro fonctionne parfaitement. Toutefois, si nous voulons que l'historique se génère également lorsqu'on ajoute un nouveau service, il

faudrait qu'on se retape toute cette macro dans de T_Service, et ce n'est pas très rationnel !

L'idéal serait de créer une macro générale qui récupère le nom de la table (T_Materiel ou T_Service), le genre de changement (Ajout,modification ou suppression), et les valeurs des champs.

Laissez-moi vous montrer par l'exemple, vous allez comprendre progressivement pourquoi c'est mieux.

Commençons par créer une nouvelle Macro de données . Nous avonsvu dans la leçon précédente que les macros de données peuvent

indifféremment se stocker dans n'importe quelle table, mais je vouspropose de créer celle-ci dans la table qui fait l'objet de notre attention

T_HistoriqueMultiTable :

Ajoutez un paramètre , comme ceci :

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

3 of 16 2/14/2013 10:04

Page 4: Access _ les macros de données

Pour la voir, il vous faudra bien faire attention d'être dansT_HistoriqueMultiTable, sinon elle n'apparaîtra pas.

Paramètres des macros

Je vous propose de commencer les noms de nos paramètrespar PAR pour éviter les confusions (Ce n'est pas obligatoire, c'est juste

un conseil). Un texte explicatif permettra de s'y retrouver plusfacilement par la suite :

Ajoutez ensuite tous les paramètres nécessaires, comme ceci :

Vous pouvez également copier coller ce code XML pour éviter la recopie fastidieuse :

<?xml version="1.0" encoding="UTF-16" standalone="no"?><DataMacros xmlns="http://schemas.microsoft.com/office/accessservices/2009/11/application"><DataMacro Name="MacroDonnées1"><Parameters><Parameter Name="PARNomTable" Description="Contiendra T_Materiel ou T_Service dans notre cas"/><Parameter Name="PARChamp1" Description="Contiendra &quot;IDMateriel&quot; ou &quot;IDService&quot;"/><Parameter Name="PARNouvelleValeur1" Description="Contiendra la valeur de IDMateriel ou IDService"/><Parameter Name="PARChamp2"Description="Contiendra &quot;Libelle&quot; (T_Materiel ou T_Service ont ce champ en 2ème position"/><Parameter Name="PARNouvelleValeur2" Description="Contiendra le contenu du libellé (Le matériel ou le service)"/><Parameter Name="PARChamp3"Description="Contiendra &quot;PrixAchat&quot; (T_Materiel) ou PrixForfaitaire (T_Service)"/><Parameter Name="PARNouvelleValeur3" Description="Contiendra le prix d'achat ou le prix forfaitaire"/><Parameter Name="PARChamp4" Description="Contiendra&quot;PrixVente&quot; (T_Materiel) ou &quot;&quot; (Rien - Deux guillemets vides) pour T_Service"/><Parameter Name="PARNouvelleValeur4" Description="Contiendra le prix de vente ou &quot;&quot; (Rien - Deux guillemets vides) pour T_Service"/></Parameters><Statements/></DataMacro></DataMacros>

Fermez ensuite votre macro , et enregistrez la sous MDHistoriqueMultitable(MD = Macros de Données - Mais ces deux lettres ne sont pas obligatoires) :

Vous pourrez y retourner quand bon vous semble de cette manière :

Pour l'instant, notre macro nommée ne fait pas grand chose d'autre que d'accueillir des paramètres. Nous la compléterons tout à l'heure. Pour

l'heure, retournez dans T_Materiel, et corrigez votre macro de cette manière :

Commencez par effacer tout le contenu de votre macro (oui,

c'est triste, mais c'est comme ça), et demandez l'actionExécuterMacrosDonnées :

Dès que vous choisissez votre macro de données , tous lesparamètres apparaissent. Oui, c'est triste, on l'a déjà dit...

Remplissez ces paramètres à la main. Je vous rappelle que ce quiest entre "guillemets", représente du texte littéral ("IDMateriel" = lemot IDMateriel), tandis que ce qui est entre [Crochet] représente le

contenu des champs ([IDmateriel] = 3(par exemple, si on est sur le N° 3) :

Ainsi, PARChamp1 contiendra littéralement IDMateriel, tandis quePARNouvelleValeur1 contiendra 3.

Comme d'habitude, je vous fournis le code XML, si ça vous ennuie de tout recopier :

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

4 of 16 2/14/2013 10:04

Page 5: Access _ les macros de données

<?xml version="1.0" encoding="UTF-16" standalone="no"?><DataMacros xmlns="http://schemas.microsoft.com/office/accessservices/2009/11/application"><DataMacro Event="AfterInsert"><Statements><Action Name="RunDataMacro"><ArgumentName="MacroName">T_HistoriqueMultiTable.MD_HistoriqueMultiTable</Argument><Parameters><Parameter Name="PARNomTable" Value="&quot;T_Materiel&quot;"/><Parameter Name="PARChamp1" Value="&quot;IDMateriel&quot;"/><ParameterName="PARNouvelleValeur1" Value="[IDMateriel]"/><Parameter Name="PARChamp2" Value="&quot;Libelle&quot;"/><Parameter Name="PARNouvelleValeur2" Value="[Libelle]"/><Parameter Name="PARChamp3" Value="&quot;PrixAchat&quot;"/><Parameter Name="PARNouvelleValeur3" Value="[PrixAchat]"/><Parameter Name="PARChamp4" Value="&quot;PrixVente&quot;"/><Parameter Name="PARNouvelleValeur4" Value="[PrixVente]"/></Parameters></Action></Statements></DataMacro></DataMacros>

Fermez cette macro et la table T_Materiel. Retournez dans MDHistoriqueMultiTable (qui se trouve donc dans T_HistoriqueMultiTable).

Historisation des nouveaux enregistrements

Créons maintenant un nouvel enregistrement dansT_HistoriqueMultiTable, et répartissons-y tous les

paramètres que nous allons recevoir (en fait, ça va drôlement

ressembler à ce que nous avons fait au début de cette leçon) :

Voici le code XML de la partie encadrée de rouge prête à être copiée-collée :

<?xml version="1.0" encoding="UTF-16" standalone="no"?><DataMacros xmlns="http://schemas.microsoft.com/office/accessservices/2009/11/application"><DataMacro Name="MD_HistoriqueMultiTable"><Parameters><Parameter Name="PARNomTable" Description="Contiendra T_Materiel ou T_Service dans notrecas"/><Parameter Name="PARChamp1" Description="Contiendra &quot;IDMateriel&quot; ou &quot;IDService&quot;"/><Parameter Name="PARNouvelleValeur1" Description="Contiendra la valeur de IDMateriel ou IDService"/><ParameterName="PARChamp2" Description="Contiendra &quot;Libelle&quot; (T_Materiel ou T_Service ont ce champ en 2ème position"/><Parameter Name="PARNouvelleValeur2" Description="Contiendra le contenu du libellé (Le matériel ou le service)"/><ParameterName="PARChamp3" Description="Contiendra &quot;PrixAchat&quot; (T_Materiel) ou PrixForfaitaire (T_Service)"/><Parameter Name="PARNouvelleValeur3" Description="Contiendra le prix d'achat ou le prix forfaitaire"/><Parameter Name="PARChamp4"Description="Contiendra &quot;PrixVente&quot; (T_Materiel) ou &quot;&quot; (Rien - Deux guillemets vides) pour T_Service"/><Parameter Name="PARNouvelleValeur4" Description="Contiendra le prix de vente ou &quot;&quot; (Rien - Deux guillemets vides)pour T_Service"/></Parameters><Statements><CreateRecord><Data><Reference>T_HistoriqueMultiTable</Reference></Data><Statements><Action Name="SetField"><Argument Name="Field">[TableOrigine]</Argument><Argument Name="Value">[PARNomTable]</Argument></Action><Action Name="SetField"><Argument Name="Field">[Champ1]</Argument><Argument Name="Value">[PARChamp1]</Argument></Action><Action Name="SetField"><Argument Name="Field">[NouvelleValeur1]</Argument><Argument Name="Value">[PARNouvelleValeur1]</Argument></Action><Action Name="SetField"><Argument Name="Field">[Champ2]</Argument><Argument Name="Value">[PARChamp2]</Argument></Action><Action Name="SetField"><Argument Name="Field">[NouvelleValeur2]</Argument><Argument Name="Value">[PARNouvelleValeur2]</Argument></Action><Action Name="SetField"><Argument Name="Field">[Champ3]</Argument><Argument Name="Value">[PARChamp3]</Argument></Action><Action Name="SetField"><Argument Name="Field">[NouvelleValeur3]</Argument><Argument Name="Value">[PARNouvelleValeur3]</Argument></Action><Action Name="SetField"><Argument Name="Field">[Champ4]</Argument><Argument Name="Value">[PARChamp4]</Argument></Action><Action Name="SetField"><Argument Name="Field">[NouvelleValeur4]</Argument><Argument Name="Value">[PARNouvelleValeur4]</Argument></Action></Statements></CreateRecord></Statements></DataMacro></DataMacros>

Lorsque vous avez terminé, fermez T_HistoriqueMultiTable, et retournez dans T_materiel afin d'ajouter un lecteur de code barre :

Fermez T_Materiel, et rouvrez T_HistoriqueMultiTable. Youpi : la création de ce nouvel article a bien été historisée :

Zuuuut ! Nous avons omis de préciser qu'il s'agit d'un changement detype Ajout !

Qu'à cela ne tienne ! Il suffit de l'ajouter dansMDHistoriqueMultiTable, et d'ajouter le paramètre et son

traitement :

Et modifier T_materiel, :

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

5 of 16 2/14/2013 10:04

Page 6: Access _ les macros de données

Voici le code XML de l'image de gauche si vous voulez économiser la miseà jour des paramètres à la main :

<?xml version="1.0" encoding="UTF-16" standalone="no"?><DataMacros xmlns="http://schemas.microsoft.com/office/accessservices/2009/11/application"><DataMacro Event="AfterInsert"><Statements><Action Name="RunDataMacro"><ArgumentName="MacroName">T_HistoriqueMultiTable.MD_HistoriqueMultiTable</Argument><Parameters><ParameterName="PARNomTable" Value="&quot;T_Service&quot;"/><Parameter Name="PARChamp1" Value="&quot;IDService&quot;"/><Parameter Name="PARNouvelleValeur1" Value="[IDService]"/><Parameter Name="PARChamp2" Value="&quot;Libelle&quot;"/><Parameter Name="PARNouvelleValeur2" Value="[Libelle]"/><Parameter Name="PARChamp3" Value="&quot;PrixForfaitaire&quot;"/><Parameter Name="PARNouvelleValeur3" Value="[PrixForfaitaire]"/><Parameter Name="PARChamp4" Value="&quot;&quot;"/><Parameter Name="PARNouvelleValeur4" Value="&quot;&quot;"/><Parameter Name="PARGenreChangement" Value="&quot;Ajout&quot;"/></Parameters></Action></Statements></DataMacro></DataMacros>

Bien.

A ce point, on se demande l'intérêt d'être passé par la création d'une macro nommée MDHistoriqueMultiTable !

Réutilisabilité des macros nommées

On va le comprendre maintenant :

Sélectionnez le contenu de votre macro de T_Materiel, et copiez-le :

Allez dans l'autre table (T_Service), dans , et collez :

Maintenant, il s'agit d'ajuster les paramètres , comme ceci :

Il est indispensable d'écrire des guillemets vides "" dans PARChamp4 et PARNouvellevaleur4, sinon, une erreur serait générée car cesparamètres seraient considérés comme manquants.

Testons ! Ajoutez un enregistrement dans T_Materiel et un autre dans T_Service. Fermez les deux tables, et ouvrez T_HistoriqueMultiTable :

Qu'est ce que c'est que ça Une lessiveuse USB, et un Détartrage de l'écran ? ... Ca m'amusait, c'est tout. Quoi ? Qu'est-ce qu'ily a ? Ca ne fait pas sérieux, c'est ça ? Eh ben voilà, c'était mon petit plaisir du jour.

Traque des erreurs à l'aide de USYSApplicationLog

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

6 of 16 2/14/2013 10:04

Page 7: Access _ les macros de données

Plus sérieusement, la lessiveuse a bien été historisée, mais ... Rien du côté du détartrage de l'écran !

C'est tout bête : nous avons commis une petite erreur. mais laquelle ? Regardez en bas à droite de votre écran Access : Cliquez sur

Nouvelles erreurs de l'application :

Ca ouvre USYSApplicationLog dont je vous ai parlé dans la partie 1 sur les macros de données :

J'ai surligné en jaune les informations qui peuvent nous aider à traquer l'erreur : il s'agit bien de T_Service, dansAfterInsert . Ensuite, dans la Description et le Context, il semble nous dire que PrixForfaitaire est invalide. Ah bon ? Maispourquoi ?

je me rends donc dans T_Service et je constate que je suis distrait ! ce n'estpas PrixForfaitaire, le nom du champ, mais TarifForfaitaire !

Un petit coup de bistouri suffit à tout faire rentrer dans l'ordre :

Testons : Ajoutez encore un autre service, fermez T_Service. Cette fois, l'historisationfonctionne aussi bien pour cette table que pour T_Materiel :

Mise à jour des paramètres

Bonne nouvelle : nous allons pouvoir réutiliser MDHistoriqueMultitable pour la suppression également. C'est ça qui est intéressant !

Par contre, nous allons devoir faire un peu de chirurgie interne : en effet, lors de l'ajout de nouveaux enregistrements, nous remplissons leschamps NouvelleValeurX. Maintenant, lors de la suppression, nous allons remplir les AncienneValeurX.

Et pour tout vous dire, lorsque nous nous occuperons de la modification, nous remplirons les anciennes et les nouvelles valeurs.

Ainsi, nous allons devoir doubler tous les paramètres de MDHistoriqueMultitable de manière à ce qu'il reçoive les nouvelles et les anciennesvaleurs de tous les champs (Constatez que j'ai changé l'ordre des paramètres pour plus de clarté, nous devrons faire des modifs par la suite dans

les macros de T_Materiel et T_Service par la suite ( ).

Deux solutions s'offrent à vous : tout recopier à la main - ou - télécharger la version de la base de données qui contient toutes les modificationsqui suivent (le lien sera proposé à la fin de l'explication).

Ensuite, il s'agit de compléter la mise à jour de T_HistoriqueMultiTable :

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

7 of 16 2/14/2013 10:04

Page 8: Access _ les macros de données

Maintenant, fermez T_HistoriqueMultiTable et allez dans T_Materiel

Cliquez sur Mettre à jour les paramètres :

Et maintenant, il s'agit d'envoyer lesanciennes valeurs. Mais pourquoi ? On s'en

fiche puisque nous sommes dans !

Oui, mais on doit au moins préciser qu'onenvoie des paramètres vides (""), sinon, ilva générer dicrètement une erreur dansUSYSApplicationLog (et du coup, il ne vapas mettre T_HistoriqueMultiTableà jour):

Voyez : il ne génère qu'une ligne d'erreursur PARAncienneValeur1, alors qu'en fait,aucune des 4 anciennes valeurs n'estrenseignée.

Complétez de cette manière :

Je vous propose de télélécharger cette base de données HistorisationEtape1.accdb, et continuer ce didacticiel sur cette base.

Faisons subir le même traitement à T_Service :

Je vous laisse faire :

Testez : , et allez vérifier que l'historisation a

bien eu lieu.

Historisation des suppressions

Maintenant, nous allons quand même recueillir les fruits de notre labeur ! Grâce au fait que nous avons toutes les variables detous les champs, en ancienne et nouvelle valeur, nous allons pouvoir utiliser la même macro MDHistoriqueMultiTable aussi pour lessuppressions.

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

8 of 16 2/14/2013 10:04

Page 9: Access _ les macros de données

Afin d'éviter de devoir tout recopier à la main, copiez le contenu de T_Materiel et collez-le dans T_Materiel, , puis opérez à ces

modifications :

Et voilà ! Testons. Effacez le clavier 102 touches : , et vérifiez que l'historisation de la suppression a bien eu lieu :

Je pense que vous devinez quoi faire à présent ? Oui, nous allons copier le contenu de la macro T_Materiel dans T_Service .

Faites-le et testez... Supprimez un service, puis vérifiez que cette suppression aété correctement journalisée.

Historisation des modificationsIl ne reste plus qu'à s'occuper de la modification.

Pour les ajouts, nous n'avons journalisé que les nouvelles valeurs entréesPour la suppression, nous ne nous sommes concentrés que sur les anciennes valeursPour la modification, nous allons donc journalsier les anciennes et les nouvelles valeurs.

Allez dans T_Materiel. Afin de ne pas toutrecommencer depuis zéro, copiez le contenu de

dans , puis complétez comme suit

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

9 of 16 2/14/2013 10:04

Page 10: Access _ les macros de données

:

Ensuite, comme d'hab, testez :

Modifiez une ligne de T_Materiel (Juste le libellé, pas lesprix):

et contrôlez ensuite votre T_HistoriqueMultiTable :

Ca marche parfaitement ! Il s'agit bien d'une Modification dans T_Materiel, et on a bien transformé Imprimante laser en laser printer.

La seule chose qui me chagrine, c'est que même les valeurs qui n'ont pas changé sont également répertoriées !

Bon, l'IDMateriel (AncienneValeur1 et NouvelleValeur1), il faut bien la répertorier pour qu'on puisse savoir de quel enregistrement il s'agit (On

ne peut de toute façon pas la changer), et donc, j'aurais pu choisir de la transférer indifféremment dans AncienneValeur1 ou NouvelleValeur1, maiscomme j'ai pris le parti de transférer cette donnée dans AncienneValeur1 dans le cas d'une suppression, et dans NouvelleValeur1 dans le casd'un ajout, je me dis que dans le cas d'une modification, je la transfère dans les deux...

Par contre, il n'y a vraiment aucun intérêt à transférer le PrixAchat (qui est resté à 290), ni le PrixVente (qui est resté à 389) : dans le cas d'unerecherche dans T_HistoriqueMultiTable sur les modifications, ça va juste nous embrouiller !

Ne pas historiser les données inchangées

Ce qui serait bien, ce serait qu'il ne transfère que les champs qui ont été réellement modifiés !

Eh bien, c'est possible !

Par contre, ça va nous obliger à complexifier quelque peu la macro MDHistoriqueMultiTable.

Voici le principe : dans le cas d'une mise à jour ou d'une suppression, pas de souci : on passe les paramètres depuis T_Materiel ouT_Service, et MDHistoriqueMultiTable se contente de dispatcher les différents paramètres (qui contiennent, selon les cas, la valeur deschamps ou rien ("" )).

Par contre, si nous sommes dans le cas d'une modification, il faut être attentif à chaque champ :

Si PARAncienneValeur2 est égale à PARNouvelleValeur2, On n'inscrit rien. Mais si elle est différente, alors, il faut les inscrire dansl'historique. Même chose pour PARAncienneValeur3 et PARAncienneValeur4.

PARAncienneValeur1, par contre, peu importe : de toute façon, nous les inscrirons à la fois PARAncienneValeur1 et PARNouvelleValeur1 (bien

que ce sera chaque fois les mêmes).

Après la théorie, la pratique. Voici comment il faut modifier MDHistoriqueMultiTable :

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

10 of 16 2/14/2013 10:04

Page 11: Access _ les macros de données

Afin de vous éviter la recopie fastidieuse, voici le code XML complet de la nouvelle version de MDHistoriqueMultiTable :

<?xml version="1.0" encoding="UTF-16" standalone="no"?><DataMacros xmlns="http://schemas.microsoft.com/office/accessservices/2009/11/application"><DataMacro Name="MD_HistoriqueMultiTable"><Parameters><Parameter Name="PARGenreChangement" Description="Contiendra &quot;Ajout&quot;,&quot;Suppression&quot; ou &quot;Modification&quot;"/><Parameter Name="PARTableOrigine" Description="Contiendra T_Materiel ou T_Service dans notre cas"/><Parameter Name="PARChamp1" Description="&quot;IDMateriel&quot;, ou&quot;IDService&quot; dans notre cas"/><Parameter Name="PARAncienneValeur1" Description="Contiendra l'ancienne valeur de IDMateriel ou IDService"/><Parameter Name="PARNouvelleValeur1" Description="Contiendra la valeur de IDMateriel ouIDService"/><Parameter Name="PARChamp2" Description="Contiendra &quot;Libelle&quot; (T_Materiel ou T_Service ont ce champ en 2ème position)"/><Parameter Name="PARAncienneValeur2" Description="Contiendra l'ancienne valeur du contenu du libellé(Le matériel ou le service)"/><Parameter Name="PARNouvelleValeur2" Description="Contiendra le contenu du libellé (Le matériel ou le service)"/><Parameter Name="PARChamp3" Description="Contiendra &quot;PrixAchat&quot; (T_Materiel) ou&quot;TarifForfaitaire&quot; (T_Service)"/><Parameter Name="PARAncienneValeur3" Description="Contiendra l'ancien prix d'achat ou ancien Tarif forfaitaire"/><Parameter Name="PARNouvelleValeur3" Description="Contiendra le prix d'achat ou le tarifforfaitaire"/><Parameter Name="PARChamp4" Description="Contiendra &quot;PrixVente&quot; (T_Materiel) ou &quot;&quot; (Rien - Deux guillemets vides) pour T_Service"/><Parameter Name="PARAncienneValeur4" Description="Contiendra l'ancien prix devente ou &quot;&quot; (Rien - Deux guillemets vides) pour T_Service"/><Parameter Name="PARNouvelleValeur4" Description="Contiendra le prix de vente ou &quot;&quot; (Rien - Deux guillemets vides) pour T_Service"/></Parameters><Statements><CreateRecord><Data><Reference>T_HistoriqueMultiTable</Reference></Data><Statements><Action Name="SetField"><Argument Name="Field">[GenreChangement]</Argument><Argument Name="Value">[PARGenreChangement]</Argument></Action><Action Name="SetField"><Argument Name="Field">[TableOrigine]</Argument><Argument Name="Value">[PARTableOrigine]</Argument></Action><Action Name="SetField"><Argument Name="Field">[Champ1]</Argument><Argument Name="Value">[PARChamp1]</Argument></Action><Action Name="SetField"><Argument Name="Field">[AncienneValeur1]</Argument><Argument Name="Value">[PARAncienneValeur1]</Argument></Action><Action Name="SetField"><Argument Name="Field">[NouvelleValeur1]</Argument><Argument Name="Value">[PARNouvelleValeur1]</Argument></Action><Action Name="SetField"><Argument Name="Field">[Champ2]</Argument><Argument Name="Value">[PARChamp2]</Argument></Action><ActionName="SetField"><Argument Name="Field">[Champ3]</Argument><Argument Name="Value">[PARChamp3]</Argument></Action><Action Name="SetField"><Argument Name="Field">[Champ4]</Argument><Argument Name="Value">[PARChamp4]</Argument></Action><ConditionalBlock><If><Condition>[PARGenreChangement]="Modification"</Condition><Statements><ConditionalBlock><If><Condition>[PARAncienneValeur2]&lt;&gt;[PARNouvelleValeur2]</Condition><Statements><ActionName="SetField"><Argument Name="Field">[AncienneValeur2]</Argument><Argument Name="Value">[PARAncienneValeur2]</Argument></Action><Action Name="SetField"><Argument Name="Field">[NouvelleValeur2]</Argument><ArgumentName="Value">[PARNouvelleValeur2]</Argument></Action></Statements></If></ConditionalBlock><ConditionalBlock><If><Condition>[PARAncienneValeur3]&lt;&gt;[PARNouvelleValeur3]</Condition><Statements><Action Name="SetField"><ArgumentName="Field">[AncienneValeur3]</Argument><Argument Name="Value">[PARAncienneValeur3]</Argument></Action><Action Name="SetField"><Argument Name="Field">[NouvelleValeur3]</Argument><Argument Name="Value">[PARNouvelleValeur3]</Argument></Action></Statements></If></ConditionalBlock><ConditionalBlock><If><Condition>[PARAncienneValeur4]&lt;&gt;[PARNouvelleValeur4]</Condition><Statements><Action Name="SetField"><Argument Name="Field">[AncienneValeur4]</Argument><Argument Name="Value">[PARAncienneValeur4]</Argument></Action><Action Name="SetField"><Argument Name="Field">[NouvelleValeur4]</Argument><Argument Name="Value">[PARNouvelleValeur4]</Argument></Action></Statements></If></ConditionalBlock></Statements></If><Else><Statements><Action Name="SetField"><Argument Name="Field">[AncienneValeur2]</Argument><Argument Name="Value">[PARAncienneValeur2]</Argument></Action><ActionName="SetField"><Argument Name="Field">[NouvelleValeur2]</Argument><Argument Name="Value">[PARNouvelleValeur2]</Argument></Action><Action Name="SetField"><Argument Name="Field">[AncienneValeur3]</Argument><ArgumentName="Value">[PARAncienneValeur3]</Argument></Action><Action Name="SetField"><Argument Name="Field">[NouvelleValeur3]</Argument><Argument Name="Value">[PARNouvelleValeur3]</Argument></Action><Action Name="SetField"><Argument Name="Field">[AncienneValeur4]</Argument><Argument Name="Value">[PARAncienneValeur4]</Argument></Action><Action Name="SetField"><Argument Name="Field">[NouvelleValeur4]</Argument><Argument Name="Value">[PARNouvelleValeur4]</Argument></Action></Statements></Else></ConditionalBlock></Statements></CreateRecord></Statements></DataMacro></DataMacros>

Bon, il ne reste plus qu'à tester, encore et toujours :

Ca marche formidablement bien !

Problèmes inhérents aux paramètres vides

Seul petit bémol : dans le cas où l'utilisateur efface purement et simplement un PrixAchat ou de PrixVente (ou le

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

11 of 16 2/14/2013 10:04

Page 12: Access _ les macros de données

PrixForfaitaire dans T_Service), les paramètres de MDHistoriqueMultiTable ne supportent pas de recevoir unevaleur vide en paramètre (Ben non, vous aimeriez, vous, qu'on vous fasse un cadeau vide ?).

C'est assez vicieux, parce que MDHistoriqueMultiTable va fonctionner sans donner d'erreur, ni même remplir une ligne deUSYSApplicationLog, mais elle va laisser un champ vide, illégitimement :

Afin de pallier à ce cas de figure,allons respectivement dans

T_Materiel et T_Service, dans

leur macro de table et

demandons-leur qu'en cas devaleurs vides dans leurs champs,

il faut les remplacer par 0,comme ceci :

Et voilà !

Il re reste plus qu'à tester :

Voilà ! Ca fonctionne fort bien !

Par contre, si on remplace le Libelle - qui est un champ texte - par rien (qu'on l'efface, donc), lemême problème surviendra ! Vous allez me dire que ça n'a pas grand sens d'effacer un libellésans effacer carrément tout l'enregistrement. Certes ! On peut d'ailleurs même interdire que le

champ Libelle soit vide dans les deux tables :

Mais... Ce n'est qu'à moitié satisfaisant ! On peut très bien imaginer des tables pourvues de champs texte

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

12 of 16 2/14/2013 10:04

Page 13: Access _ les macros de données

facultatifs, qu'on peut effacer tout à fait logiquement...

Du coup, que faire ?

Dans le cas de numériques, on remplace les vides par 0, mais dans le cas d'un texte, on ne vaquand même pas écrire "0" dans un champ qu'on efface, ça fait un peu amateur ! ... On nepeut pas écrire Guillemets-Guillemets"" , ça ne marche pas. A la rigueur, on pourrait inscrireGuillemets Espace Guillemets " " ... Ca fonctionnerait mais ça nous impose un espace dansnotre champ.

Je vais être franc : je n'ai pas de solution miracle à vous proposer pour ce cas de figure .

Limites du champ d'action des macros de tableDans ce dernier paragraphe, autant vous prévenir : nous n'arriverons pas à nos fins élégamment : nousatteignons la limite des macros de table . De plus, cette section exige que vous connaissiez un minimum deVBA (Mais je vais vous épauler, vous me connaissez, je suis bon comme le pain)

Dans le cas d'une base de données multi-utilisateurs , cette historisation ne serait définitivement complète que sil'on inscrit le nom de l'utilisateur qui a effectué l'ajout, la suppression ou la modification.

Or, pour ce faire, nous devons créer une fonction personnalisée VBA qui va nous renvoyer le nom d'utilisateur utilisé lors du loginWindows .

Récupération du nom d'utilisateur

La fonction VBA personnalisée qui renvoie le nom de l'utilisateur courant se présente comme ceci :

Function Utilisateur() Utilisateur = Environ("username")End Function

Afin de la tester, faites ceci :

Recopiez à la main ce qui est encadré en bleu, comme ceci :

Testez en cliquant sur TesterLaFonction, et en appuyant sur F5.

Fermez. Assez bizarrement, il ne vous est pas proposé d'enregistrer votre module VBA . Forçons-lui lamain : fermez la base de données !

Access vous propose (enfin !) d'enregistrervotre module . Appelez-le P_Perso

(P comme Programmation).

Création d'un formulaire pour l'utilisation d'une f onction

Maintenant, avant de vous montrer comment ça ne marche pas, je vais déjà vous montrer comment çamarche !

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

13 of 16 2/14/2013 10:04

Page 14: Access _ les macros de données

Ajoutez un champ UtilisateurCourant dans T_Materiel :

Fermez cette table, et créez un nouveau formulaire, comme ceci :

Ecrivez =Utilisateur() dans la propriété Valeur par défaut du champ UtilisateurCourant, comme ceci :

Lancez le formulaire en mode saisie de données , et ajoutez un nouveau matériel :

Interaction Formulaires/Tables/Macros de tables

Constatez qu'il ajoute automatiquement le nom d'utilisateur dans UtilisateurCourant. Fermez le formulaire, et profitez-enpour l'enregistrer sous F_Materiel. Bien que vous ayez entré un nouveau matériel via un formulaire , et non via la table

T_Materiel directement, la macro de T_Materiel s'est exécutée, car la table a vraiment été mise à jour en arrière-plan (ce

qui est très logique, puisque les formulaire ne contiennent pas de données, ils ne sont que des filtres esthétiques basés sur lestables).

Regardez T_HistoriqueMultiTable :

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

14 of 16 2/14/2013 10:04

Page 15: Access _ les macros de données

Il nous manque évidemment l'utilisateur courant dans cet historique. Ajoutez-le :

1. Ajoutez un champ UtilisateurCourant dans T_HistoriqueMultiTable2. Modifiez MDHistoriqueMultiTable afin de considérer ce nouveau champ

3. Modifiez de T_Materiel, pour prendre aussi en compte ce nouveau champ

Comme ceci :

Pour tester

vous devez retourner dans le formulaire F_Materielajouter encore un autre matérielfermer le formulairecontrôler T_HistoriqueMultiTable :

Ca fonctionne très bien !

Formulaires plus performants

Mais pourquoi diable est-on passé par un formulaire ???

L'astuce consistant à écrire =Utilisateur() dans la valeur par défaut du champ UtilisateurCourant de F_Materiel, pourquoi n'a-t-on pasécrit =Utilisateur() directement dans la valeur par défaut de la table T_Materiel ?

Tout simplement parce que ce n'est paspossible !

Bien qu'il s'agisse de la même propriété, lesoptions des valeurs par défaut

proposées dans les formulaires sontbeaucoup plus nombreuses que dans les

tables.

Regardez ce comparatif :

Comparaison Macros de table/Utilisation de formulaires

C'est vraiment gênant, parce que si vous ajoutez un nouveau matériel directement dans la table (sans passer par le formulaire, donc), la macro

ne va pas compléter le champ UtilisateurCourant.

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

15 of 16 2/14/2013 10:04

Page 16: Access _ les macros de données

Même commentaire si vous modifiez ou si vous supprimez un enregistrement depuis la table T_Materiel : il ne sera pas possible d'envoyerl'UtilisateurCourant dans l'historique.

Il faudra absolument penser à faire toutes les modifications, ajouts et suppressions depuis des formulaires.

Et encore : nous n'avons pas fini l'exercice ! Nous avons effectivement défini la valeur par défaut pourUtilisateurCourant, ce qui règle la mise à jour de l'historique dans le cas de nouveaux services, mais il faudramaintenant, par programmation VBA, remplir le champ UtilisateurCourant de F_Materiel dans le cas d'unesuppression d'enregistrement, ainsi que lors d'un changement !

Et refaire toute la même manipulation pour le formulaire que vous devrez alors créer pour les services !

Nous allons donc nous retrouver avec une moitié de travail effectué dans les macros de table , et, juste àcause du fait qu'on ne peut pas appeler de fonction peronnalisée depuis les valeurs par défaut des tables (ni, d'ailleurs, en aucune manière depuis les

macros de table), on va se retrouver avec du code VBA dans les formulaires.

On finit par se demander si on ne devrait pas carrément gérer l'ensemble de tous les ajouts de lignes dans T_HistoriqueMultiTable avec de laprogrammation VBA dans les formulaires ?

Mais ceci est un autre débat, et nous allons nous arrêter là, car le but était ici de vous montrer commentétablir un historique des modifications de vos tables à l'aide de macros de table.

Voici la base de données complètement terminée.

Access : les macros de données http://www.info-3000.com/access/macrodonnee/index2.php

16 of 16 2/14/2013 10:04