Olla. D'abord, pas de panique sur la quantité des remarques : il y a pas mal de changements dans la structure de cette aplication, du fait qu'on sépare bien maintenant le modèle de base (réutilisable à merci) de la nouvelle base, copiée.
Par contre, c'est vrai que, quand tu te lances dans un essai de code comme la dernière fois, ça me permet de repérer les points faibles à travailler. Donc, commençons par les
Corrections sur Sub CopieModeleBase()
1- Le chemin d'accès à l'ancienne base : on ne le connait pas, puisque l'utilisateur peut avoir stocké cela n'importe où, en local ou sur n'importe quel serveur. On va le lui demander, dans notre interface -> nouveau contrôle txtPathOldBase + bouton btnBrowse
2- Le nom du modèle de base est inscrit dans le code : si on veut réutiliser ce modèle de moteur de mise à jour, mieux vaut stocker ce genre d'info dans une table de paramètres : voir nouvelle table taApplicationParameters. (préfixe ta pour TurboApp, bien sûr)
Au passage, note que tu aurais pu mettre ce nom dans une CONSTante, plutôt qu'une variable string.
3- analyse du code
NomModeleBase = PathModeleBase & NomModeleBase
Pratique parfaitement acceptable et courante, mais qui risque de te coûter de nombreuses erreurs mineures. Je conseille de toujours distinguer très clairement les variables qui contiennent
les noms de fichiers : XxxxFileName
les chemins d'accès : XxxxPath
la totale, avec chemin + nom : XxxxPathFileName Je n'utilise pratiquement jamais de telles variables (sauf exception), parce que je finis presque toujours par avoir besoin de changer, soit le chemin, soit le nom du fichier. Donc, la méthode qui marche toujours : une variable XxxxPath + une variable XxxxFileName.
Méthodes agiles : ce type de recommendations fait partie du "re-engineering" (ou "refactoring" ?). Ne pas hésiter à réécrire tes applications existantes, en clarifiant les noms des variables.
Et toc, en lisant plus loin, je constate ceci :
If Dir(PathAncienneBase & NomModeleBase & ".mdb") Then
Bien sûr, le test plantera, s'il n'y a pas de test sur la valeur, comme dans : If Dir(PathAncienneBase & NomModeleBase & ".mdb") > "" Then
Mais surtout, du fait que NomModeleBase contient déjà un chemin, alors PathAncienneBase & NomModeleBase en contiennent 2, l'un derrière l'autre !!! Illustration typique des erreurs que je t'annonce plus haut.
Et ça veut dire que tu nas pas testé ta routine (même avec une constante pour le chemin de destination). Là, pan sur les doigts ! Les tests sont la première mamelle de la programmation. Incontournables !!!!!!!
Enfin, rappel concernant les chemins d'accès (voir classe clLog, Public Property Let Path) : toujours s'assurer que chaque chemin se termine bien par un "\". D'où la nouvelle fonction CleanPath(), dans le module _Demarrage_Utilitaires.
If Dir(NomModeleBase & ".mdb") > "" Then (plus haut)
Tu vérifies, je cite : "'si le modèle existe dans le répertoire en cours". Mais le répertoire en cours (CurDir) peut être n'importe quel répertoire de la machine et peut être modifié par n'importe quelle application. Donc je ne vois pas trop l'intérêt ?? Mais si j'ai raté qqchose, tu me dis ?
Application.Quit
Pourquoi pas, mais le vieux soixantehuitard attardé, ex-hippie peace & love que je suis, préfère des réactions moins violentes : simple retour à l'interface de notre application, en laissant le choix à l'utilisateur
- de corriger le problème (le modèle n'est pas là où il faut : il va le réinstaller correctement...), ou
- de quitter de lui-même,
- etc.
Contrôle d'erreur : bel essai, mais planté
On ne met pas (dixit papyturbo) de contrôle d'erreur dans une classe objet. Je reviendrai sous peu en détail sur ce sujet, à la fois pour cette application et l'application principale.
On verra alors quelles routines et fonctions, généralement quels modules, en fait, ont intérêt à avoir ce genre de code, et quelles sont celles qui devraient plutôt renvoyer les erreurs à l'appelant...
4- Nom du modèle en *.mod : excellente idée, à laquelle je n'avais pas pensé, et que je vais certainement réutiliser dans mes applis futures. Probablement avec une extension de type "*.dbt" pour "Data Base Template", comme les xlT d'Excel et les .doT de Word....
Aussi que parce que, chez moi, les *.mod lancent Windows Media Player... !
5- Appel depuis App_Init : OK, mais, si l'utilisateur doit recommencer plusieurs fois, il faut faire une copie à chaque lancemnt, pour écraser la version précédente, qui n'était pas bonne ou incomplète... Donc, appel maintenant depuis le bouton cmdMAJTables.
6- Structure de l'application : tu as mis cette routine de copie dans l'objet clApplication. Le but de cette classe est de nous fournir des fonctions qui n'existent pas dans l'application Access, mais que nous allons réutiliser partout.
Par contre, la copie du fichier "modèle de base de données" est spécifique à cette application de mise à jour. On ne va pas l'utiliser dans une appli comme "SuiviAffaires", par exemple.
Donc, je l'ai (pour l'instant)
- déplacée dans les utilitaires propres à notre UpdateWizard : module SpecificTransferRoutines,
- elle appelle une routine CopyFile qui, elle, est bien dans _Demarrage_Utilitaires. Elle est mieux là, pour qu'on l'appelle directement, comme le FileCopy de VBA, sans préfixer avec ThisApp.CopyFile
Je t'ai copié "ma" routine de copie de fichier, un poil simplifiée, à partir de la librairie qui accompagne toutes mes applications. Un de buts de cet exercice est que tu commences à constituer ta propre librairie de code réutilisable d'une application à l'autre.
---------------------------------
Nouveautés + mises au point :
1- Formulaire UpdateWizard :
- Les boutons de commande sont alignés à droite (quelques lignes de code dans Form_Resize()), et MinWidth devient une simple constante. le tout, à titre d'exemple, et parce que ça m'amuse...
- bouton Supprimer le journal remplacé par une case à cocher.
- onglet Transfert, simplification pour l'utilisateur : juste les noms des tables + le fait que ce sont des données (à récupérer) ou des paramètres.
- bouton cmdEmptyDataTables : ne vide que les tables du modèle + tables locales temporaires (pour alléger le programme à envoyer aux utilisateurs).
Utilise des paramètres de la nouvelle table de paramètres, au lieu de constantes : moins il y a de modifs à faire dans le code, plus ce programme sera facile à réutiliser.
2- Connexions :
- on sépare bien maintenant
::: la connexion au modèle de base, seulement pour le développeur, et
::: la connexion à la copie, dans le même répertoire que l'ancienne base, pour l'utilisateur.
- Au démarrage, on reconnecte automatiquement le modèle, qui est "sur place" -> toutes les tables du modèle (*.dbt) sont maintenant connectées aussi.
La méthode ThisApp.CheckTablesConnection ne reconnecte plus que la base spécifiée par l'argument. Cela permettra de la réutiliser, en ne spécifiant que les bases que l'on souhaite reconnecter automatiqument au démarrage.
Noter la manière de s'arrêter ( dans App_Quit), qui n'est pas la même selon que l'utilisateur est un dévelopeur ou pas + le fait qu'au démarrage, la fenêtre base de données est maintenant masquée.
Connexions aux "vraies" bases :
- Pour l'utilisateur (question d'ergonomie) : on le laisse cliquer sur le bouton Parcourir... pour indiquer où se trouve sa base. Lorsqu'on a un chemin valide, dans cmdMAJTables_click, on reconnecte les 2 copies de la base : l'ancienne + la nouvelle (après copie).
3- Divers codes :
- Les routines OuvrirUnFichier() et OuvrirFichierSpécifique() remaniées pour pouvoir obtenir le chemin d'accès séparément du nom de fichier (voir remarques plus haut).
- Fonction CopyFile() dans le module _Demarrage_Utilitaires (à réutiliser ailleurs). Profites en pour regarder comment on crée ses propres erreurs, avec la méthode Err.Raise...
- la classe clApplication a maintenant une propriété Parameters(), en lecture (Get) + écriture (Let). Liée à la table taApplicationParameters.
Si le paramètre n'existe pas, il est créé lors de la première écriture.
Cette table va, comme indiqué + haut, te permettre de ranger ici un maximum de constantes propres à cette application, mais qu'il faudra changer pour d'autres. Très pratique, plutôt que de fouiller dans tout le code, lors de la création d'une nouvelle appli.
Attention quand même, de ne pas y ranger des séries de 100 ou 1000 valeurs semblables : on sait créer des tables pour ce genre d'usage. Le propre d'un paramètre est d'être unique (ou presque.)
-----------------------
En ce qui te concerne, je verrai bien, à titre d'exercice, l'inversion des préfixes 1_ et 2_ en postfixes (derrière le nom de chaque table).
Comme pour les tables locales, temporaires.
On peut garder à part les tables du modèle qui n'intéressent que la phase 1 (ci-dessous).
Comme déjà mentionné, je pense que tu y verras plus clair dans les seules opérations complexes, à faire avec chaque nouvelle mise à jour d'une base quelconque : mise au point des opérations de transfert entre les tables prises 2 par 2, l'ancienne et la nouvelle, parfois avec une temporaire en plus.
Rien ne t'y oblige, mais essaye les 2 avant de décider lequel est le plus pratique.
Sinon, en ce qui me concerne, notre UpdateWizard est au point, selon le scénario suivant :
1- le développeur réutilise cet assistant, reconnecte les bonnes tables, change les paramètres (dans 000 DestinationTables + taApplicationParameters), adapte le code...
Il dispose d'une base à l'ancienne version (pour ses tests) + une base à la nouvelle version. Dans cette dernière, il doit y avoir les données d'origine + quelques nouveaux enregistrements "Titi-Toto-Tata", pour tester chaque cas particulier, pendant la mise au point de son application, dernière version.
Il utilise l'onglet Nettoyage modele pour vider les tables du modèle.
Il teste et ajoute ce qu'il faut comme requêtes et code VBA pour que tout passe bien.
En fait, c'est la seule chose qui te reste à faire chaque fois : juste le spécifique.
2- Déploiement : Quand tout est bon,
- au démarrage, n'oublie pas de mettre ThisApp.Debugging = False (je l'ai fait, dans l'assistant ci-joint).
- compactage (par Access) du wizard + de l'application (non inclus ici) + du modèle de base (inclus ci-joint),
- compactage zip ou similaire. Astuce pas chère : un zip auto-extractible (*.exe) va
::: s'ouvrir,
::: créer si nécessaire un nouveau dossier pour l'application,
::: lancer automatiquement l'UpdateWizard.
Pour l'utilisateur, c'est simple et ça fait très pro
3- L'utilisateur reçoit le zip, l'exécute, lance l'assistant, met à jour sa base de données. Ça ne devrait pas lui prendre plus de 5 à 10 minutes, pour une base très lourde et complexe.
Ça peut être plus long si des interventions lui sont demandées, telles qu'une boîte de dialogue pour nettoyer les valeurs qui ne passent pas, l'impression d'un état listant les valeurs incompatibles, choisir des options, etc.
4- pour la version suivante de la même application, tu recommences en 1-
En sachant bien que, maintenant que le plus gros de ce moteur est réutilisable, tu as un très grand intérêt à faire de petites mises à jour à chaque fois qu'une modif (nouveau champ, nouvelle table...) est nécessaire.
Attendre longtemps, pour faire tout d'un coup, va te coûter beaucoup plus cher (transformations de données plus complexes...).
Vive le développement par itérations![]()
Partager