Comment utilisez-vous le contrôle de version avec le développement Access?


163

Je suis impliqué dans la mise à jour d'une solution Access. Il contient une bonne quantité de VBA, un certain nombre de requêtes, une petite quantité de tables et quelques formulaires pour la saisie de données et la génération de rapports. C'est un candidat idéal pour Access.

Je souhaite apporter des modifications à la conception de la table, au VBA, aux requêtes et aux formulaires. Comment puis-je suivre mes modifications avec le contrôle de version? (nous utilisons Subversion, mais cela vaut pour n'importe quelle saveur) Je peux coller le mdb entier dans subversion, mais cela stockera un fichier binaire, et je ne pourrai pas dire que je viens de changer une ligne de code VBA.

J'ai pensé à copier le code VBA dans des fichiers séparés et à les enregistrer, mais je pouvais voir ceux-ci se désynchroniser rapidement avec le contenu de la base de données.


1
Crossposting de cette solution à la question connexe de l'exportation du schéma Access db.
Eric G

1
Access prend en charge l'interface SCC, de sorte que tout contrôle de version compatible avec cette interface est prêt pour Access. Avertissement: je travaille pour plasticscm.com et plusieurs clients l'utilisent avec Access.
pablo du

Réponses:


180

Nous avons écrit notre propre script en VBScript, qui utilise le Application.SaveAsText () non documenté dans Access pour exporter tous les modules de code, formulaire, macro et rapport. Voilà, cela devrait vous donner quelques indications. (Attention: certains messages sont en allemand, mais vous pouvez facilement changer cela.)

EDIT: Pour résumer les divers commentaires ci-dessous: Notre projet suppose un fichier .adp. Afin d'obtenir ce travail avec .mdb / .accdb, vous devez changer OpenAccessProject () en OpenCurrentDatabase (). (Mis à jour pour utiliser OpenAccessProject()s'il voit une extension .adp, sinon utiliser OpenCurrentDatabase().)

decompose.vbs:

' Usage:
'  CScript decompose.vbs <input file> <path>

' Converts all modules, classes, forms and macros from an Access Project file (.adp) <input file> to
' text and saves the results in separate files to <path>.  Requires Microsoft Access.
'

Option Explicit

const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3

' BEGIN CODE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim sADPFilename
If (WScript.Arguments.Count = 0) then
    MsgBox "Bitte den Dateinamen angeben!", vbExclamation, "Error"
    Wscript.Quit()
End if
sADPFilename = fso.GetAbsolutePathName(WScript.Arguments(0))

Dim sExportpath
If (WScript.Arguments.Count = 1) then
    sExportpath = ""
else
    sExportpath = WScript.Arguments(1)
End If


exportModulesTxt sADPFilename, sExportpath

If (Err <> 0) and (Err.Description <> NULL) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function exportModulesTxt(sADPFilename, sExportpath)
    Dim myComponent
    Dim sModuleType
    Dim sTempname
    Dim sOutstring

    dim myType, myName, myPath, sStubADPFilename
    myType = fso.GetExtensionName(sADPFilename)
    myName = fso.GetBaseName(sADPFilename)
    myPath = fso.GetParentFolderName(sADPFilename)

    If (sExportpath = "") then
        sExportpath = myPath & "\Source\"
    End If
    sStubADPFilename = sExportpath & myName & "_stub." & myType

    WScript.Echo "copy stub to " & sStubADPFilename & "..."
    On Error Resume Next
        fso.CreateFolder(sExportpath)
    On Error Goto 0
    fso.CopyFile sADPFilename, sStubADPFilename

    WScript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    WScript.Echo "opening " & sStubADPFilename & " ..."
    If (Right(sStubADPFilename,4) = ".adp") Then
        oApplication.OpenAccessProject sStubADPFilename
    Else
        oApplication.OpenCurrentDatabase sStubADPFilename
    End If

    oApplication.Visible = false

    dim dctDelete
    Set dctDelete = CreateObject("Scripting.Dictionary")
    WScript.Echo "exporting..."
    Dim myObj
    For Each myObj In oApplication.CurrentProject.AllForms
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acForm, myObj.fullname, sExportpath & "\" & myObj.fullname & ".form"
        oApplication.DoCmd.Close acForm, myObj.fullname
        dctDelete.Add "FO" & myObj.fullname, acForm
    Next
    For Each myObj In oApplication.CurrentProject.AllModules
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acModule, myObj.fullname, sExportpath & "\" & myObj.fullname & ".bas"
        dctDelete.Add "MO" & myObj.fullname, acModule
    Next
    For Each myObj In oApplication.CurrentProject.AllMacros
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acMacro, myObj.fullname, sExportpath & "\" & myObj.fullname & ".mac"
        dctDelete.Add "MA" & myObj.fullname, acMacro
    Next
    For Each myObj In oApplication.CurrentProject.AllReports
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acReport, myObj.fullname, sExportpath & "\" & myObj.fullname & ".report"
        dctDelete.Add "RE" & myObj.fullname, acReport
    Next

    WScript.Echo "deleting..."
    dim sObjectname
    For Each sObjectname In dctDelete
        WScript.Echo "  " & Mid(sObjectname, 3)
        oApplication.DoCmd.DeleteObject dctDelete(sObjectname), Mid(sObjectname, 3)
    Next

    oApplication.CloseCurrentDatabase
    oApplication.CompactRepair sStubADPFilename, sStubADPFilename & "_"
    oApplication.Quit

    fso.CopyFile sStubADPFilename & "_", sStubADPFilename
    fso.DeleteFile sStubADPFilename & "_"


End Function

Public Function getErr()
    Dim strError
    strError = vbCrLf & "----------------------------------------------------------------------------------------------------------------------------------------" & vbCrLf & _
               "From " & Err.source & ":" & vbCrLf & _
               "    Description: " & Err.Description & vbCrLf & _
               "    Code: " & Err.Number & vbCrLf
    getErr = strError
End Function

Si vous avez besoin d'une commande cliquable, au lieu d'utiliser la ligne de commande, créez un fichier nommé "decompose.cmd" avec

cscript decompose.vbs youraccessapplication.adp

Par défaut, tous les fichiers exportés vont dans un sous-dossier "Scripts" de votre application Access. Le fichier .adp / mdb est également copié à cet emplacement (avec un suffixe "stub") et dépouillé de tous les modules exportés, ce qui le rend vraiment petit.

Vous DEVEZ archiver ce stub avec les fichiers source, car la plupart des paramètres d'accès et des barres de menus personnalisées ne peuvent pas être exportés d'une autre manière. Assurez-vous simplement de ne valider les modifications dans ce fichier que si vous avez vraiment changé un paramètre ou un menu.

Remarque: Si vous avez défini des Autoexec-Makros dans votre application, vous devrez peut-être maintenir la touche Maj enfoncée lorsque vous invoquez la décomposition pour l'empêcher de s'exécuter et d'interférer avec l'exportation!

Bien sûr, il existe également le script inverse, pour construire l'application à partir du répertoire "Source":

compose.vbs:

' Usage:
'  WScript compose.vbs <file> <path>

' Converts all modules, classes, forms and macros in a directory created by "decompose.vbs"
' and composes then into an Access Project file (.adp). This overwrites any existing Modules with the
' same names without warning!!!
' Requires Microsoft Access.

Option Explicit

const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3

Const acCmdCompileAndSaveAllModules = &H7E

' BEGIN CODE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim sADPFilename
If (WScript.Arguments.Count = 0) then
    MsgBox "Please enter the file name!", vbExclamation, "Error"
    Wscript.Quit()
End if
sADPFilename = fso.GetAbsolutePathName(WScript.Arguments(0))

Dim sPath
If (WScript.Arguments.Count = 1) then
    sPath = ""
else
    sPath = WScript.Arguments(1)
End If


importModulesTxt sADPFilename, sPath

If (Err <> 0) and (Err.Description <> NULL) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function importModulesTxt(sADPFilename, sImportpath)
    Dim myComponent
    Dim sModuleType
    Dim sTempname
    Dim sOutstring

    ' Build file and pathnames
    dim myType, myName, myPath, sStubADPFilename
    myType = fso.GetExtensionName(sADPFilename)
    myName = fso.GetBaseName(sADPFilename)
    myPath = fso.GetParentFolderName(sADPFilename)

    ' if no path was given as argument, use a relative directory
    If (sImportpath = "") then
        sImportpath = myPath & "\Source\"
    End If
    sStubADPFilename = sImportpath & myName & "_stub." & myType

    ' check for existing file and ask to overwrite with the stub
    if (fso.FileExists(sADPFilename)) Then
        WScript.StdOut.Write sADPFilename & " exists. Overwrite? (y/n) "
        dim sInput
        sInput = WScript.StdIn.Read(1)
        if (sInput <> "y") Then
            WScript.Quit
        end if

        fso.CopyFile sADPFilename, sADPFilename & ".bak"
    end if

    fso.CopyFile sStubADPFilename, sADPFilename

    ' launch MSAccess
    WScript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    WScript.Echo "opening " & sADPFilename & " ..."
    If (Right(sStubADPFilename,4) = ".adp") Then
        oApplication.OpenAccessProject sADPFilename
    Else
        oApplication.OpenCurrentDatabase sADPFilename
    End If
    oApplication.Visible = false

    Dim folder
    Set folder = fso.GetFolder(sImportpath)

    ' load each file from the import path into the stub
    Dim myFile, objectname, objecttype
    for each myFile in folder.Files
        objecttype = fso.GetExtensionName(myFile.Name)
        objectname = fso.GetBaseName(myFile.Name)
        WScript.Echo "  " & objectname & " (" & objecttype & ")"

        if (objecttype = "form") then
            oApplication.LoadFromText acForm, objectname, myFile.Path
        elseif (objecttype = "bas") then
            oApplication.LoadFromText acModule, objectname, myFile.Path
        elseif (objecttype = "mac") then
            oApplication.LoadFromText acMacro, objectname, myFile.Path
        elseif (objecttype = "report") then
            oApplication.LoadFromText acReport, objectname, myFile.Path
        end if

    next

    oApplication.RunCommand acCmdCompileAndSaveAllModules
    oApplication.Quit
End Function

Public Function getErr()
    Dim strError
    strError = vbCrLf & "----------------------------------------------------------------------------------------------------------------------------------------" & vbCrLf & _
               "From " & Err.source & ":" & vbCrLf & _
               "    Description: " & Err.Description & vbCrLf & _
               "    Code: " & Err.Number & vbCrLf
    getErr = strError
End Function

Encore une fois, cela va avec un compagnon "compose.cmd" contenant:

cscript compose.vbs youraccessapplication.adp

Il vous demande de confirmer l'écrasement de votre application actuelle et crée d'abord une sauvegarde, si vous le faites. Il collecte ensuite tous les fichiers source du répertoire source et les réinsère dans le stub.

S'amuser!


1
J'adore ce code. J'ai trouvé que oApplication.OpenAccessProject ne fonctionnerait pas sur un fichier .accdb (ou peut-être que c'est une chose Access 2007) et j'ai dû utiliser oApplication.OpenCurrentDatabase à la place.
hughdbrown

1
Je fais quelque chose de similaire (SaveAsText, mais en VBA et avec un fichier MDB au lieu d'ADP), mais il me reste un gros problème: après chaque exportation, Subversion reconnaît environ 100 fichiers comme modifiés (même si je n'en ai changé qu'un ou deux ). quand je regarde les changements, je vois que certains noms de variables ou noms de contrôle ont changé leur orthographe en majuscules / minuscules. Par exemple: chaque fichier qui contenait autrefois "OrderNumber" contient désormais "Ordernumber" dans l'export et est donc marqué comme "changé" (au moins par SVN, je n'ai pas encore essayé d'autres SCM). Une idée comment je peux éviter cela? Merci beaucoup!
Christian Specht

3
Oui, c'est un ennui constant dans notre projet également. D'après ce que nous avons déterminé, le problème est que les variables de votre projet portent les mêmes noms que les contrôles, juste dans des cas différents (haut / bas). Maintenant, selon l'ordre des modules en cours de composition, Access semble prendre une orthographe et "corriger" toutes les autres, puisque VBA est censé être insensible à la casse. Access fait cela, même si les contrôles sont sur des formes différentes! Le problème s'aggrave si vous avez même plusieurs contrôles du même nom dans différents cas sur différents formulaires.
Oliver

3
La seule solution est de rechercher chaque nom de variable / contrôle et de changer l'orthographe en une forme commune. Après une exportation et la validation des modifications, les noms doivent être stables. Le préfixage des noms de contrôle avec leurs types garantit à peu près par la convention de dénomination que les noms ne sont pas en conflit avec les variables. (par exemple, txtTitle pour une zone de texte contenant le champ Titre ou cmbUsers pour une zone de liste déroulante et ainsi de suite)
Oliver

J'ai oublié d'ajouter que pour obtenir ce travail avec mdb, j'ai dû changer OpenAccessProject en OpenCurrentDatabase .
DaveParillo

19

Cela semble être quelque chose de tout à fait disponible dans Access:

Ce lien de msdn explique comment installer un complément de contrôle de source pour Microsoft Access. Il a été livré en téléchargement gratuit dans le cadre des extensions Access Developer pour Access 2007 et en tant que complément gratuit distinct pour Access 2003.

Je suis heureux que vous ayez posé cette question et j'ai pris le temps de la chercher, car j'aimerais aussi cette capacité. Le lien ci-dessus contient plus d'informations à ce sujet et des liens vers les compléments.

Mise à jour:
j'ai installé le complément pour Access 2003. Il ne fonctionnera qu'avec VSS, mais il me permet de mettre des objets Access (formulaires, requêtes, tables, modules, ect) dans le référentiel. Lorsque vous modifiez un élément du référentiel, vous êtes invité à le retirer, mais vous n'êtes pas obligé de le faire. Ensuite, je vais vérifier comment il gère l'ouverture et la modification sur un système sans le complément. Je ne suis pas fan de VSS, mais j'aime vraiment l'idée de stocker des objets d'accès dans un dépôt.

Update2: Les
machines sans le complément ne peuvent pas apporter de modifications à la structure de la base de données (ajouter des champs de table, des paramètres de requête, etc.). Au début, j'ai pensé que cela pourrait être un problème si quelqu'un en avait besoin, car il n'y avait aucun moyen apparent de supprimer la base de données Access du contrôle de source si Access n'avait pas chargé le complément.

Id a découvert que l'exécution de la base de données «compacter et réparer» vous invite à supprimer la base de données du contrôle de code source. J'ai choisi oui et j'ai pu modifier la base de données sans le complément. L'article du lien ci - dessus donne également des instructions sur la configuration d'Access 2003 et 2007 pour utiliser Team System. Si vous pouvez trouver un fournisseur MSSCCI pour SVN, il y a de fortes chances que vous puissiez le faire fonctionner.


Notez que nous avons eu pas mal de problèmes avec l'impossibilité d'extraire un ADP à partir de VSS si plus d'une personne l'avait édité. Nous avons fini par devoir avoir une sauvegarde séparée en place pour cela!
Simon

J'ai joué avec cette approche (en utilisant Vault, puisque je ne connais aucun fournisseur MSSCCI gratuit pour SVN ... TortoiseSVNSCC n'est pas entretenu et n'a pas fonctionné pour moi, et les deux ou trois autres options sont commerciales). Cela fonctionne, mais cela vous oblige à utiliser l'approche archaïque de verrouillage exclusif pour le contrôle de code source, et pour cette raison, je prévois de l'abandonner et d'utiliser la solution de @ Oliver.
Todd Owen

14

La solution de composition / décomposition publiée par Oliver est excellente, mais elle présente quelques problèmes:

  • Les fichiers sont codés au format UCS-2 (UTF-16), ce qui peut amener les systèmes / outils de contrôle de version à considérer les fichiers comme binaires.
  • Les fichiers contiennent de nombreux éléments qui changent souvent - sommes de contrôle, informations sur l'imprimante, etc. C'est un problème sérieux si vous voulez nettoyer les diffs ou devez coopérer sur le projet.

J'avais l'intention de résoudre ce problème moi-même, mais j'ai découvert qu'une bonne solution était déjà disponible: timabell / msaccess-vcs-integration sur GitHub. J'ai testé msaccess-vcs-integration et cela fonctionne très bien.

Mise à jour le 3 mars 2015 : Le projet était à l'origine maintenu / détenu par bkidwell sur Github, mais il a été transféré à timabell - le lien ci-dessus vers le projet est mis à jour en conséquence. Il y a des fourches du projet original de bkidwell, par exemple par ArminBra et par matonb , qui AFAICT ne devraient pas être utilisées.

L'inconvénient de l'utilisation de msaccess-vcs-integration par rapport à la solution de décomposition d'Olivers:

  • C'est beaucoup plus lent. Je suis sûr que le problème de vitesse peut être résolu, mais je n'ai pas besoin d'exporter mon projet en texte aussi souvent ...
  • Il ne crée pas de projet Access de stub avec les éléments exportés supprimés. Cela peut également être corrigé (en adoptant le code du script de décomposition), mais encore une fois - pas si important.

Quoi qu'il en soit, ma recommandation claire est msaccess-vcs-integration. Cela a résolu tous les problèmes que j'avais avec l'utilisation de Git sur les fichiers exportés.


On dirait que la fourche ArminBra est en avance maintenant (d'après le graphique du réseau ). Matonb n'a pas répondu à la seule demande d'extraction, donc je suppose qu'ils l'ont abandonnée pour le moment au moins.
Tim Abell

1
Et maintenant, il y a aussi mon fork github.com/timabell/msaccess-vcs-integration - corrige la rupture d'exportation de la table de clés composée. Les deux autres semblent un peu abandonnés, donc je suis heureux de prendre les rapports de bogues des demandes d'extraction, etc. sur mon fork.
Tim Abell

Je suggérerais poliment de modifier cette réponse pour pointer vers ma fourchette car c'est maintenant la version la plus activement maintenue.
Tim Abell

2
@TimAbell: J'ai mis à jour ma réponse pour refléter le fait que le projet vous a été transféré. PS! J'espère que nous pourrons obtenir des votes car je pense que c'est la meilleure solution.
hansfn

2
gentil, naviguer dans les fourches d'un projet github semble être le dernier problème que nous nous sommes inventé :-)
Tim Abell

14

Olivers répond aux roches, mais la CurrentProjectréférence ne fonctionnait pas pour moi. J'ai fini par arracher les tripes du milieu de son export et le remplacer par celui-ci, basé sur une solution similaire d' Arvin Meyer . A l'avantage d'exporter des requêtes si vous utilisez un mdb au lieu d'un adp.

' Writes database componenets to a series of text files
' @author  Arvin Meyer
' @date    June 02, 1999
Function DocDatabase(oApp)
    Dim dbs 
    Dim cnt 
    Dim doc 
    Dim i
    Dim prefix
    Dim dctDelete
    Dim docName

    Const acQuery = 1

    Set dctDelete = CreateObject("Scripting.Dictionary")

    Set dbs = oApp.CurrentDb() ' use CurrentDb() to refresh Collections
    Set cnt = dbs.Containers("Forms")
    prefix = oApp.CurrentProject.Path & "\"
    For Each doc In cnt.Documents
        oApp.SaveAsText acForm, doc.Name, prefix & doc.Name & ".frm"
        dctDelete.Add "frm_" & doc.Name, acForm
    Next

    Set cnt = dbs.Containers("Reports")
    For Each doc In cnt.Documents
        oApp.SaveAsText acReport, doc.Name, prefix & doc.Name & ".rpt"
        dctDelete.Add "rpt_" & doc.Name, acReport
    Next

    Set cnt = dbs.Containers("Scripts")
    For Each doc In cnt.Documents
        oApp.SaveAsText acMacro, doc.Name, prefix & doc.Name & ".vbs"
        dctDelete.Add "vbs_" & doc.Name, acMacro
    Next

    Set cnt = dbs.Containers("Modules")
    For Each doc In cnt.Documents
        oApp.SaveAsText acModule, doc.Name, prefix & doc.Name & ".bas"
        dctDelete.Add "bas_" & doc.Name, acModule
    Next

    For i = 0 To dbs.QueryDefs.Count - 1
        oApp.SaveAsText acQuery, dbs.QueryDefs(i).Name, prefix & dbs.QueryDefs(i).Name & ".txt"
        dctDelete.Add "qry_" & dbs.QueryDefs(i).Name, acQuery
    Next

    WScript.Echo "deleting " & dctDelete.Count & " objects."
    For Each docName In dctDelete
        WScript.Echo "  " & Mid(docName, 5)
        oApp.DoCmd.DeleteObject dctDelete(docName), Mid(docName, 5)
    Next

    Set doc = Nothing
    Set cnt = Nothing
    Set dbs = Nothing
    Set dctDelete = Nothing

End Function

1
+1 pour inclure les requêtes. Il suffit maintenant d'inclure les schémas de table.
Marc Stober

La réponse approuvée ne fonctionne pas pour Access 97, mais cette réponse m'a aidé à la modifier pour mes propres utilisations. Merci d'avoir posté ceci!
CTristan

2
Je vous encourage vivement à placer l'enregistrement de la requête avant l'enregistrement des formulaires pour changer l'ordre de suppression ultérieurement. J'ai eu des problèmes avec DeleteObject dans la dernière instruction For Each lorsque j'ai essayé de supprimer des requêtes qui ont déjà été supprimées automatiquement lorsque leurs formulaires correspondants ont été supprimés auparavant. De plus, si vous avez des formulaires qui s'ouvrent au démarrage et que vous ne voulez pas maintenir F11 (ou le désactiver), insérez simplement oApp.DoCmd.Close acForm, "formName" après votre exécution à travers cnt.Documents
Anton Kaiser

@Cunso Pouvez-vous poster votre code compatible avec Access 97. Je n'ai donc pas besoin de le redévelopper.
Lorenz Meyer

comment utiliser ceci? Appelez-le d'un sous-marin?
kevinykuo

11

Nous avons développé notre propre outil interne, où:

  1. Modules: sont exportés sous forme de fichiers txt puis comparés avec "file compare tool" (freeware)
  2. Formulaires: sont exportés via la commande undocument application.saveAsText. Il est alors possible de voir les différences entre 2 versions différentes (encore une fois "file compare tool").
  3. Macros: nous n'avons aucune macro à comparer, car nous n'avons que la macro "autoexec" avec une ligne de lancement de la procédure VBA principale
  4. Requêtes: ne sont que des chaînes de texte stockées dans une table: voir infra
  5. tables: nous avons écrit notre propre comparateur de tables, répertoriant les différences dans les enregistrements ET la structure des tables.

L'ensemble du système est suffisamment intelligent pour nous permettre de produire des versions "runtime" de notre application Access, générées automatiquement à partir de fichiers txt (modules et formulaires recréés avec la commande undocument application.loadFromText) et de fichiers mdb (tables).

Cela peut sembler étrange mais cela fonctionne.


8
J'adorerais voir cet outil open-source!
Todd Owen

Sera-ce une bonne idée de télécharger ces fichiers texte exportés sur GitHub?
Santosh

9

Sur la base des idées de cet article et d'entrées similaires dans certains blogs, j'ai écrit une application qui fonctionne avec les formats de fichiers mdb et adp. Il importe / exporte tous les objets de la base de données (y compris les tables, les références, les relations et les propriétés de la base de données) vers des fichiers de texte brut. Avec ces fichiers, vous pouvez travailler avec n'importe quel contrôle de version source. La prochaine version permettra de réimporter les fichiers texte brut dans la base de données. Il y aura aussi un outil de ligne de commande

Vous pouvez télécharger l'application ou le code source sur: http://accesssvn.codeplex.com/

Cordialement


Nous l'utilisons depuis presque deux ans maintenant et c'est génial. Je vous remercie!
mcfea

5

Ressusciter un vieux fil mais celui-ci est bon. J'ai implémenté les deux scripts (compose.vbs / decompose.vbs) pour mon propre projet et j'ai rencontré un problème avec les anciens fichiers .mdb:

Il se bloque lorsqu'il atteint une forme qui inclut le code:

NoSaveCTIWhenDisabled =1

Access dit qu'il a un problème et c'est la fin de l'histoire. J'ai couru quelques tests et essayé de contourner ce problème et j'ai trouvé ce fil avec un travail à la fin:

Impossible de créer la base de données

Fondamentalement (au cas où le thread serait mort), vous prenez le .mdb et faites un "Enregistrer sous" au nouveau format .accdb. Ensuite, le coffre-fort de la source ou le contenu de composition / décomposition fonctionnera. J'ai également dû jouer pendant 10 minutes pour obtenir la bonne syntaxe de ligne de commande pour que les scripts (de) composer fonctionnent correctement, alors voici également cette information:

Pour composer (disons que vos trucs se trouvent dans C: \ SControl (créez un sous-dossier nommé Source pour stocker les fichiers extraits):

'(to extract for importing to source control)
cscript compose.vbs database.accdb     

'(to rebuild from extracted files saved from an earlier date)
cscript decompose.vbs database.accdb C:\SControl\Source\

C'est tout!

Les versions d'Access où j'ai rencontré le problème ci-dessus incluent les bases de données Access 2000-2003 ".mdb" et ont résolu le problème en les enregistrant dans les formats ".accdb" 2007-2010 avant d'exécuter les scripts de composition / décomposition. Après la conversion, les scripts fonctionnent très bien!


Pouvez-vous modifier cela pour inclure vos versions d'Access où vous rencontrez ce problème?
Nathan DeWitt

Pas de problème, faites-vous toujours du développement d'accès Nathan? Si tel est le cas, vous avez réussi à l'intégrer au contrôle de version?
JKK

Je ne fais plus de développement Access. J'avais un projet sur lequel j'ai utilisé cela au retour lorsque j'ai posé la question, et je n'ai jamais eu à faire autre chose avec.
Nathan DeWitt

Cool, je pense que la plupart des entreprises utilisent une sorte de serveur SQL dédié. La situation dans laquelle je suis maintenant, il y a un mélange de MS SQL Server, Oracle et un tas de bases de données Access qui extraient les données des serveurs vers les tables locales et les exportent vers Excel. C'est un mélange assez compliqué. Je pense que je vais commencer une nouvelle question sur quelques suggestions pour la mise en place d'un nouveau projet sur lequel je serai bientôt, voyez ce que les gens peuvent suggérer pour réduire la complexité
JKK

4

Solution de fichier texte uniquement (requêtes, tables et relations incluses)

J'ai modifié la paire de scripts d'Oliver afin qu'ils exportent / importent des relations, des tables et des requêtes en plus des modules, des classes, des formulaires et des macros. Tout est enregistré dans des fichiers en clair, il n'y a donc pas de fichier de base de données créé pour être stocké avec les fichiers texte dans le contrôle de version.

Exporter dans des fichiers texte (decompose.vbs)

' Usage:
'  cscript decompose.vbs <input file> <path>

' Converts all modules, classes, forms and macros from an Access Project file (.adp) <input file> to
' text and saves the results in separate files to <path>.  Requires Microsoft Access.
Option Explicit

Const acForm = 2
Const acModule = 5
Const acMacro = 4
Const acReport = 3
Const acQuery = 1
Const acExportTable = 0

' BEGIN CODE
Dim fso, relDoc, ACCDBFilename, sExportpath
Set fso = CreateObject("Scripting.FileSystemObject")
Set relDoc = CreateObject("Microsoft.XMLDOM")

If (Wscript.Arguments.Count = 0) Then
    MsgBox "Please provide the .accdb database file", vbExclamation, "Error"
    Wscript.Quit()
End If
ACCDBFilename = fso.GetAbsolutePathName(Wscript.Arguments(0))

If (Wscript.Arguments.Count = 1) Then
 sExportpath = ""
Else
 sExportpath = Wscript.Arguments(1)
End If


exportModulesTxt ACCDBFilename, sExportpath

If (Err <> 0) And (Err.Description <> Null) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function exportModulesTxt(ACCDBFilename, sExportpath)
    Dim myComponent, sModuleType, sTempname, sOutstring
    Dim myType, myName, myPath, hasRelations
    myType = fso.GetExtensionName(ACCDBFilename)
    myName = fso.GetBaseName(ACCDBFilename)
    myPath = fso.GetParentFolderName(ACCDBFilename)

    'if no path was given as argument, use a relative directory
    If (sExportpath = "") Then
        sExportpath = myPath & "\Source"
    End If
    'On Error Resume Next
    fso.DeleteFolder (sExportpath)
    fso.CreateFolder (sExportpath)
    On Error GoTo 0

    Wscript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    Wscript.Echo "Opening " & ACCDBFilename & " ..."
    If (Right(ACCDBFilename, 4) = ".adp") Then
     oApplication.OpenAccessProject ACCDBFilename
    Else
     oApplication.OpenCurrentDatabase ACCDBFilename
    End If
    oApplication.Visible = False

    Wscript.Echo "exporting..."
    Dim myObj
    For Each myObj In oApplication.CurrentProject.AllForms
        Wscript.Echo "Exporting FORM " & myObj.FullName
        oApplication.SaveAsText acForm, myObj.FullName, sExportpath & "\" & myObj.FullName & ".form.txt"
        oApplication.DoCmd.Close acForm, myObj.FullName
    Next
    For Each myObj In oApplication.CurrentProject.AllModules
        Wscript.Echo "Exporting MODULE " & myObj.FullName
        oApplication.SaveAsText acModule, myObj.FullName, sExportpath & "\" & myObj.FullName & ".module.txt"
    Next
    For Each myObj In oApplication.CurrentProject.AllMacros
        Wscript.Echo "Exporting MACRO " & myObj.FullName
        oApplication.SaveAsText acMacro, myObj.FullName, sExportpath & "\" & myObj.FullName & ".macro.txt"
    Next
    For Each myObj In oApplication.CurrentProject.AllReports
        Wscript.Echo "Exporting REPORT " & myObj.FullName
        oApplication.SaveAsText acReport, myObj.FullName, sExportpath & "\" & myObj.FullName & ".report.txt"
    Next
    For Each myObj In oApplication.CurrentDb.QueryDefs
        Wscript.Echo "Exporting QUERY " & myObj.Name
        oApplication.SaveAsText acQuery, myObj.Name, sExportpath & "\" & myObj.Name & ".query.txt"
    Next
    For Each myObj In oApplication.CurrentDb.TableDefs
     If Not Left(myObj.Name, 4) = "MSys" Then
      Wscript.Echo "Exporting TABLE " & myObj.Name
      oApplication.ExportXml acExportTable, myObj.Name, , sExportpath & "\" & myObj.Name & ".table.txt"
      'put the file path as a second parameter if you want to export the table data as well, instead of ommiting it and passing it into a third parameter for structure only
     End If
    Next

    hasRelations = False
    relDoc.appendChild relDoc.createElement("Relations")
    For Each myObj In oApplication.CurrentDb.Relations  'loop though all the relations
    If Not Left(myObj.Name, 4) = "MSys" Then
     Dim relName, relAttrib, relTable, relFoTable, fld
     hasRelations = True

     relDoc.ChildNodes(0).appendChild relDoc.createElement("Relation")
     Set relName = relDoc.createElement("Name")
     relName.Text = myObj.Name
     relDoc.ChildNodes(0).LastChild.appendChild relName

     Set relAttrib = relDoc.createElement("Attributes")
     relAttrib.Text = myObj.Attributes
     relDoc.ChildNodes(0).LastChild.appendChild relAttrib

     Set relTable = relDoc.createElement("Table")
     relTable.Text = myObj.Table
     relDoc.ChildNodes(0).LastChild.appendChild relTable

     Set relFoTable = relDoc.createElement("ForeignTable")
     relFoTable.Text = myObj.ForeignTable
     relDoc.ChildNodes(0).LastChild.appendChild relFoTable

     Wscript.Echo "Exporting relation " & myObj.Name & " between tables " & myObj.Table & " -> " & myObj.ForeignTable

     For Each fld In myObj.Fields   'in case the relationship works with more fields
      Dim lf, ff
      relDoc.ChildNodes(0).LastChild.appendChild relDoc.createElement("Field")

      Set lf = relDoc.createElement("Name")
      lf.Text = fld.Name
      relDoc.ChildNodes(0).LastChild.LastChild.appendChild lf

      Set ff = relDoc.createElement("ForeignName")
      ff.Text = fld.ForeignName
      relDoc.ChildNodes(0).LastChild.LastChild.appendChild ff

      Wscript.Echo "  Involving fields " & fld.Name & " -> " & fld.ForeignName
     Next
    End If
    Next
    If hasRelations Then
     relDoc.InsertBefore relDoc.createProcessingInstruction("xml", "version='1.0'"), relDoc.ChildNodes(0)
     relDoc.Save sExportpath & "\relations.rel.txt"
     Wscript.Echo "Relations successfuly saved in file relations.rel.txt"
    End If

    oApplication.CloseCurrentDatabase
    oApplication.Quit

End Function

Vous pouvez exécuter ce script en appelant cscript decompose.vbs <path to file to decompose> <folder to store text files>. Si vous omettez le deuxième paramètre, cela créera le dossier «Source» où se trouve la base de données. Veuillez noter que le dossier de destination sera effacé s'il existe déjà.

Inclure les données dans les tables exportées

Remplacez la ligne 93: oApplication.ExportXML acExportTable, myObj.Name, , sExportpath & "\" & myObj.Name & ".table.txt"

avec ligne oApplication.ExportXML acExportTable, myObj.Name, sExportpath & "\" & myObj.Name & ".table.txt"

Importer dans un fichier de base de données (compose.vbs)

' Usage:
'  cscript compose.vbs <file> <path>

' Reads all modules, classes, forms, macros, queries, tables and their relationships in a directory created by "decompose.vbs"
' and composes then into an Access Database file (.accdb).
' Requires Microsoft Access.
Option Explicit

Const acForm = 2
Const acModule = 5
Const acMacro = 4
Const acReport = 3
Const acQuery = 1
Const acStructureOnly = 0   'change 0 to 1 if you want import StructureAndData instead of StructureOnly
Const acCmdCompileAndSaveAllModules = &H7E

Dim fso, relDoc, ACCDBFilename, sPath
Set fso = CreateObject("Scripting.FileSystemObject")
Set relDoc = CreateObject("Microsoft.XMLDOM")

If (Wscript.Arguments.Count = 0) Then
 MsgBox "Please provide the .accdb database file", vbExclamation, "Error"
 Wscript.Quit()
End If

ACCDBFilename = fso.GetAbsolutePathName(Wscript.Arguments(0))
If (Wscript.Arguments.Count = 1) Then
 sPath = ""
Else
 sPath = Wscript.Arguments(1)
End If


importModulesTxt ACCDBFilename, sPath

If (Err <> 0) And (Err.Description <> Null) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If


Function importModulesTxt(ACCDBFilename, sImportpath)
    Dim myComponent, sModuleType, sTempname, sOutstring

    ' Build file and pathnames
    Dim myType, myName, myPath
    myType = fso.GetExtensionName(ACCDBFilename)
    myName = fso.GetBaseName(ACCDBFilename)
    myPath = fso.GetParentFolderName(ACCDBFilename)

    ' if no path was given as argument, use a relative directory
    If (sImportpath = "") Then
        sImportpath = myPath & "\Source\"
    End If

    ' check for existing file and ask to overwrite with the stub
    If fso.FileExists(ACCDBFilename) Then
     Wscript.StdOut.Write ACCDBFilename & " already exists. Overwrite? (y/n) "
     Dim sInput
     sInput = Wscript.StdIn.Read(1)
     If (sInput <> "y") Then
      Wscript.Quit
     Else
      If fso.FileExists(ACCDBFilename & ".bak") Then
       fso.DeleteFile (ACCDBFilename & ".bak")
      End If
      fso.MoveFile ACCDBFilename, ACCDBFilename & ".bak"
     End If
    End If

    Wscript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    Wscript.Echo "Opening " & ACCDBFilename
    If (Right(ACCDBFilename, 4) = ".adp") Then
        oApplication.CreateAccessProject ACCDBFilename
    Else
        oApplication.NewCurrentDatabase ACCDBFilename
    End If
    oApplication.Visible = False

    Dim folder
    Set folder = fso.GetFolder(sImportpath)

    'load each file from the import path into the stub
    Dim myFile, objectname, objecttype
    For Each myFile In folder.Files
     objectname = fso.GetBaseName(myFile.Name)  'get rid of .txt extension
     objecttype = fso.GetExtensionName(objectname)
     objectname = fso.GetBaseName(objectname)

     Select Case objecttype
      Case "form"
       Wscript.Echo "Importing FORM from file " & myFile.Name
       oApplication.LoadFromText acForm, objectname, myFile.Path
      Case "module"
       Wscript.Echo "Importing MODULE from file " & myFile.Name
       oApplication.LoadFromText acModule, objectname, myFile.Path
      Case "macro"
       Wscript.Echo "Importing MACRO from file " & myFile.Name
       oApplication.LoadFromText acMacro, objectname, myFile.Path
      Case "report"
       Wscript.Echo "Importing REPORT from file " & myFile.Name
       oApplication.LoadFromText acReport, objectname, myFile.Path
      Case "query"
       Wscript.Echo "Importing QUERY from file " & myFile.Name
       oApplication.LoadFromText acQuery, objectname, myFile.Path
      Case "table"
       Wscript.Echo "Importing TABLE from file " & myFile.Name
       oApplication.ImportXml myFile.Path, acStructureOnly
      Case "rel"
       Wscript.Echo "Found RELATIONSHIPS file " & myFile.Name & " ... opening, it will be processed after everything else has been imported"
       relDoc.Load (myFile.Path)
     End Select
    Next

    If relDoc.readyState Then
     Wscript.Echo "Preparing to build table dependencies..."
     Dim xmlRel, xmlField, accessRel, relTable, relName, relFTable, relAttr, i
     For Each xmlRel In relDoc.SelectNodes("/Relations/Relation")   'loop through every Relation node inside .xml file
      relName = xmlRel.SelectSingleNode("Name").Text
      relTable = xmlRel.SelectSingleNode("Table").Text
      relFTable = xmlRel.SelectSingleNode("ForeignTable").Text
      relAttr = xmlRel.SelectSingleNode("Attributes").Text

      'remove any possible conflicting relations or indexes
      On Error Resume Next
      oApplication.CurrentDb.Relations.Delete (relName)
      oApplication.CurrentDb.TableDefs(relTable).Indexes.Delete (relName)
      oApplication.CurrentDb.TableDefs(relFTable).Indexes.Delete (relName)
      On Error GoTo 0

      Wscript.Echo "Creating relation " & relName & " between tables " & relTable & " -> " & relFTable
      Set accessRel = oApplication.CurrentDb.CreateRelation(relName, relTable, relFTable, relAttr)  'create the relationship object

      For Each xmlField In xmlRel.SelectNodes("Field")  'in case the relationship works with more fields
       accessRel.Fields.Append accessRel.CreateField(xmlField.SelectSingleNode("Name").Text)
       accessRel.Fields(xmlField.SelectSingleNode("Name").Text).ForeignName = xmlField.SelectSingleNode("ForeignName").Text
       Wscript.Echo "  Involving fields " & xmlField.SelectSingleNode("Name").Text & " -> " & xmlField.SelectSingleNode("ForeignName").Text
      Next

      oApplication.CurrentDb.Relations.Append accessRel 'append the newly created relationship to the database
      Wscript.Echo "  Relationship added"
     Next
    End If

    oApplication.RunCommand acCmdCompileAndSaveAllModules
    oApplication.Quit
End Function

Vous pouvez exécuter ce script en appelant cscript compose.vbs <path to file which should be created> <folder with text files>. Si vous omettez le deuxième paramètre, il cherchera dans le dossier «Source» où la base de données doit être créée.

Importer des données à partir d'un fichier texte

Remplacez la ligne 14: const acStructureOnly = 0par const acStructureOnly = 1. Cela ne fonctionnera que si vous avez inclus les données dans la table exportée.

Choses qui ne sont pas couvertes

  1. Je n'ai testé cela qu'avec des fichiers .accdb, donc avec tout le reste, il peut y avoir des bogues.
  2. Les paramètres ne sont pas exportés, je recommanderais de créer la macro qui appliquera le paramètre au démarrage de la base de données.
  3. Certaines requêtes inconnues sont parfois exportées précédées de «~». Je ne sais pas s'ils sont nécessaires.
  4. Les noms d'objet MSAccess peuvent contenir des caractères qui ne sont pas valides pour les noms de fichiers - le script échouera lors de la tentative d'écriture. Vous pouvez normaliser tous les noms de fichiers , mais vous ne pouvez pas les réimporter.

Une de mes autres ressources tout en travaillant sur ce script était cette réponse , qui m'a aidé à comprendre comment exporter des relations.


Cela semble fonctionner, mais ne comprend pas les tables liées
Lord Darth Vader

2

Il y a un piège - VSS 6.0 ne peut accepter que les MDB utilisant le complément sous un certain nombre d'objets, qui comprend toutes les tables, requêtes, modules et formulaires locaux. Je ne connais pas la limite d'objet exacte.

Pour créer notre application de plancher de production vieille de 10 ans, qui est énorme, nous sommes obligés de combiner 3 ou 4 MDB séparées à partir de SS en une seule MDB, ce qui complique les constructions automatisées au point que nous ne perdons pas de temps à le faire.

Je pense que je vais essayer le script ci-dessus pour cracher ce MDb dans SVN et simplifier les versions pour tout le monde.


2

Pour ceux qui utilisent Access 2010, SaveAsText n'est pas une méthode visible dans Intellisense mais cela semble être une méthode valide, comme le script d'Arvin Meyer l'a mentionné précédemment a bien fonctionné pour moi.

Fait intéressant, SaveAsAXL est une nouveauté de 2010 et possède la même signature que SaveAsText, même s'il semble qu'il ne fonctionnera qu'avec les bases de données Web, qui nécessitent SharePoint Server 2010.


SaveAsText n'est pas non plus visible dans A2003, sauf si vous avez activé Afficher les membres masqués dans l'Explorateur d'objets. Bonnes informations sur SaveAsAXL.
David-W-Fenton

2

Nous avons eu le même problème il y a quelque temps.

Notre premier essai était un outil tiers qui offre un proxy de l'API SourceSafe pour Subversion à utiliser avec MS Access et VB 6. L'outil peut être trouvé ici .

Comme nous n'étions pas très satisfaits de cet outil, nous sommes passés à Visual SourceSafe et au plug-in d'accès VSS.


2

J'utilise Oasis-Svn http://dev2dev.de/

Je peux juste dire que cela m'a sauvé au moins une fois. Mon mdb augmentait au-delà de 2 Go et cela l'a cassé. Je pourrais revenir à une ancienne version et importer les formulaires et perdre un jour ou deux de travail.


1

J'ai trouvé cet outil sur SourceForge: http://sourceforge.net/projects/avc/

Je ne l'ai pas utilisé, mais c'est peut-être un début pour vous. Il peut y avoir d'autres outils tiers qui s'intègrent à VSS ou SVN qui font ce dont vous avez besoin.

Personnellement, je garde juste un fichier texte à portée de main pour garder un journal des modifications. Lorsque je valide la MDB binaire, j'utilise les entrées du journal des modifications comme commentaire de validation.


Vous avez un lien pour le télécharger? Suis-je aveugle? Je n'arrive pas à le trouver.
BIBD


1

Par souci d'exhaustivité ...

Il existe toujours des «outils Visual Studio [YEAR] pour Microsoft Office System» ( http://msdn.microsoft.com/en-us/vs2005/aa718673.aspx ) mais cela semble nécessiter VSS. Pour moi, VSS (corruption automatique) est pire que mes 347 points de sauvegarde sur mon partage réseau sauvegardé uber.


1

J'utilise le complément Access 2003: contrôle de code source . Ça fonctionne bien. Un problème sont des caractères non valides comme un ":".

Je suis arrivée et départ. En interne, le complément fait la même chose que le code là-haut, mais avec plus de support d'outils. Je peux voir si un objet est extrait et actualiser les objets.



1

La réponse d'Oliver fonctionne très bien. Veuillez trouver ma version étendue ci-dessous qui ajoute la prise en charge des requêtes Access.

(Veuillez consulter la réponse d'Oliver pour plus d'informations / utilisation)

decompose.vbs:

' Usage:
'  CScript decompose.vbs <input file> <path>

' Converts all modules, classes, forms and macros from an Access Project file (.adp) <input file> to
' text and saves the results in separate files to <path>.  Requires Microsoft Access.
'
Option Explicit

const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3
const acQuery = 1

' BEGIN CODE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim sADPFilename
If (WScript.Arguments.Count = 0) then
    MsgBox "Bitte den Dateinamen angeben!", vbExclamation, "Error"
    Wscript.Quit()
End if
sADPFilename = fso.GetAbsolutePathName(WScript.Arguments(0))

Dim sExportpath
If (WScript.Arguments.Count = 1) then
    sExportpath = ""
else
    sExportpath = WScript.Arguments(1)
End If


exportModulesTxt sADPFilename, sExportpath

If (Err <> 0) and (Err.Description <> NULL) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function exportModulesTxt(sADPFilename, sExportpath)
    Dim myComponent
    Dim sModuleType
    Dim sTempname
    Dim sOutstring

    dim myType, myName, myPath, sStubADPFilename
    myType = fso.GetExtensionName(sADPFilename)
    myName = fso.GetBaseName(sADPFilename)
    myPath = fso.GetParentFolderName(sADPFilename)

    If (sExportpath = "") then
        sExportpath = myPath & "\Source\"
    End If
    sStubADPFilename = sExportpath & myName & "_stub." & myType

    WScript.Echo "copy stub to " & sStubADPFilename & "..."
    On Error Resume Next
        fso.CreateFolder(sExportpath)
    On Error Goto 0
    fso.CopyFile sADPFilename, sStubADPFilename

    WScript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    WScript.Echo "opening " & sStubADPFilename & " ..."
    If (Right(sStubADPFilename,4) = ".adp") Then
        oApplication.OpenAccessProject sStubADPFilename
    Else
        oApplication.OpenCurrentDatabase sStubADPFilename
    End If

    oApplication.Visible = false

    dim dctDelete
    Set dctDelete = CreateObject("Scripting.Dictionary")
    WScript.Echo "exporting..."
    Dim myObj

    For Each myObj In oApplication.CurrentProject.AllForms
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acForm, myObj.fullname, sExportpath & "\" & myObj.fullname & ".form"
        oApplication.DoCmd.Close acForm, myObj.fullname
        dctDelete.Add "FO" & myObj.fullname, acForm
    Next
    For Each myObj In oApplication.CurrentProject.AllModules
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acModule, myObj.fullname, sExportpath & "\" & myObj.fullname & ".bas"
        dctDelete.Add "MO" & myObj.fullname, acModule
    Next
    For Each myObj In oApplication.CurrentProject.AllMacros
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acMacro, myObj.fullname, sExportpath & "\" & myObj.fullname & ".mac"
        dctDelete.Add "MA" & myObj.fullname, acMacro
    Next
    For Each myObj In oApplication.CurrentProject.AllReports
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acReport, myObj.fullname, sExportpath & "\" & myObj.fullname & ".report"
        dctDelete.Add "RE" & myObj.fullname, acReport
    Next
    For Each myObj In oApplication.CurrentDb.QueryDefs
        if not left(myObj.name,3) = "~sq" then 'exclude queries defined by the forms. Already included in the form itself
            WScript.Echo "  " & myObj.name
            oApplication.SaveAsText acQuery, myObj.name, sExportpath & "\" & myObj.name & ".query"
            oApplication.DoCmd.Close acQuery, myObj.name
            dctDelete.Add "FO" & myObj.name, acQuery
        end if
    Next

    WScript.Echo "deleting..."
    dim sObjectname
    For Each sObjectname In dctDelete
        WScript.Echo "  " & Mid(sObjectname, 3)
        oApplication.DoCmd.DeleteObject dctDelete(sObjectname), Mid(sObjectname, 3)
    Next

    oApplication.CloseCurrentDatabase
    oApplication.CompactRepair sStubADPFilename, sStubADPFilename & "_"
    oApplication.Quit

    fso.CopyFile sStubADPFilename & "_", sStubADPFilename
    fso.DeleteFile sStubADPFilename & "_"


End Function

Public Function getErr()
    Dim strError
    strError = vbCrLf & "----------------------------------------------------------------------------------------------------------------------------------------" & vbCrLf & _
               "From " & Err.source & ":" & vbCrLf & _
               "    Description: " & Err.Description & vbCrLf & _
               "    Code: " & Err.Number & vbCrLf
    getErr = strError
End Function

compose.vbs:

' Usage:
'  WScript compose.vbs <file> <path>

' Converts all modules, classes, forms and macros in a directory created by "decompose.vbs"
' and composes then into an Access Project file (.adp). This overwrites any existing Modules with the
' same names without warning!!!
' Requires Microsoft Access.

Option Explicit

const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3
const acQuery = 1

Const acCmdCompileAndSaveAllModules = &H7E

' BEGIN CODE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim sADPFilename
If (WScript.Arguments.Count = 0) then
    MsgBox "Bitte den Dateinamen angeben!", vbExclamation, "Error"
    Wscript.Quit()
End if
sADPFilename = fso.GetAbsolutePathName(WScript.Arguments(0))

Dim sPath
If (WScript.Arguments.Count = 1) then
    sPath = ""
else
    sPath = WScript.Arguments(1)
End If


importModulesTxt sADPFilename, sPath

If (Err <> 0) and (Err.Description <> NULL) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function importModulesTxt(sADPFilename, sImportpath)
    Dim myComponent
    Dim sModuleType
    Dim sTempname
    Dim sOutstring

    ' Build file and pathnames
    dim myType, myName, myPath, sStubADPFilename
    myType = fso.GetExtensionName(sADPFilename)
    myName = fso.GetBaseName(sADPFilename)
    myPath = fso.GetParentFolderName(sADPFilename)

    ' if no path was given as argument, use a relative directory
    If (sImportpath = "") then
        sImportpath = myPath & "\Source\"
    End If
    sStubADPFilename = sImportpath & myName & "_stub." & myType

    ' check for existing file and ask to overwrite with the stub
    if (fso.FileExists(sADPFilename)) Then
        WScript.StdOut.Write sADPFilename & " existiert bereits. Überschreiben? (j/n) "
        dim sInput
        sInput = WScript.StdIn.Read(1)
        if (sInput <> "j") Then
            WScript.Quit
        end if

        fso.CopyFile sADPFilename, sADPFilename & ".bak"
    end if

    fso.CopyFile sStubADPFilename, sADPFilename

    ' launch MSAccess
    WScript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    WScript.Echo "opening " & sADPFilename & " ..."
    If (Right(sStubADPFilename,4) = ".adp") Then
        oApplication.OpenAccessProject sADPFilename
    Else
        oApplication.OpenCurrentDatabase sADPFilename
    End If
    oApplication.Visible = false

    Dim folder
    Set folder = fso.GetFolder(sImportpath)

    ' load each file from the import path into the stub
    Dim myFile, objectname, objecttype
    for each myFile in folder.Files
        objecttype = fso.GetExtensionName(myFile.Name)
        objectname = fso.GetBaseName(myFile.Name)
        WScript.Echo "  " & objectname & " (" & objecttype & ")"

        if (objecttype = "form") then
            oApplication.LoadFromText acForm, objectname, myFile.Path
        elseif (objecttype = "bas") then
            oApplication.LoadFromText acModule, objectname, myFile.Path
        elseif (objecttype = "mac") then
            oApplication.LoadFromText acMacro, objectname, myFile.Path
        elseif (objecttype = "report") then
            oApplication.LoadFromText acReport, objectname, myFile.Path
        elseif (objecttype = "query") then
           oApplication.LoadFromText acQuery, objectname, myFile.Path
        end if

    next

    oApplication.RunCommand acCmdCompileAndSaveAllModules
    oApplication.Quit
End Function

Public Function getErr()
    Dim strError
    strError = vbCrLf & "----------------------------------------------------------------------------------------------------------------------------------------" & vbCrLf & _
               "From " & Err.source & ":" & vbCrLf & _
               "    Description: " & Err.Description & vbCrLf & _
               "    Code: " & Err.Number & vbCrLf
    getErr = strError
End Function

0

J'ai essayé de contribuer à sa réponse en ajoutant une option d'exportation pour les requêtes dans la base de données d'accès. (Avec l'aide d' autres réponses SO )

Dim def
Set stream = fso.CreateTextFile(sExportpath & "\" & myName & ".queries.txt")
  For Each def In oApplication.CurrentDb.QueryDefs

    WScript.Echo "  Exporting Queries to Text..."
    stream.WriteLine("Name: " & def.Name)
    stream.WriteLine(def.SQL)
    stream.writeline "--------------------------"
    stream.writeline " "

  Next
stream.Close

Je ne suis pas en mesure de travailler cela dans la fonction «composer», mais ce n'est pas ce dont j'ai besoin pour le moment.

Remarque: j'ai également ajouté ".txt" à chacun des noms de fichiers exportés dans decompose.vbs afin que le contrôle de source me montre immédiatement les fichiers diffs.

J'espère que cela pourra aider!



0

Cette entrée décrit une approche totalement différente des autres entrées et peut ne pas être ce que vous recherchez. Je ne serai donc pas offensé si vous l'ignorez. Mais au moins, c'est matière à réflexion.

Dans certains environnements de développement de logiciels commerciaux professionnels, la gestion de la configuration (CM) des livrables logiciels n'est normalement pas effectuée dans l'application logicielle elle-même ou dans le projet logiciel lui-même. CM est imposé aux produits livrables finaux, en enregistrant le logiciel dans un dossier CM spécial, où le fichier et son dossier sont marqués avec l'identification de la version. Par exemple, Clearcase permet au gestionnaire de données «d'archiver» un fichier logiciel, de lui attribuer une «branche», de lui attribuer une «bulle» et d'appliquer des «étiquettes». Lorsque vous voulez voir et télécharger un fichier, vous devez configurer votre "config spec" pour pointer vers la version que vous voulez, puis cd dans le dossier et le voilà.

Juste une idée.


0

Pour toute personne coincée avec Access 97, je n'ai pas été en mesure de faire fonctionner les autres réponses. En combinant les excellentes réponses d' Oliver et DaveParillo et en apportant quelques modifications, j'ai pu faire fonctionner les scripts avec nos bases de données Access 97. C'est aussi un peu plus convivial car il demande dans quel dossier placer les fichiers.

AccessExport.vbs:

' Converts all modules, classes, forms and macros from an Access file (.mdb) <input file> to
' text and saves the results in separate files to <path>.  Requires Microsoft Access.
Option Explicit

Const acQuery = 1
Const acForm = 2
Const acModule = 5
Const acMacro = 4
Const acReport = 3
Const acCmdCompactDatabase = 4
Const TemporaryFolder = 2

Dim strMDBFileName : strMDBFileName = SelectDatabaseFile
Dim strExportPath : strExportPath = SelectExportFolder
CreateExportFolders(strExportPath)
Dim objProgressWindow
Dim strOverallProgress
CreateProgressWindow objProgressWindow
Dim strTempMDBFileName
CopyToTempDatabase strMDBFileName, strTempMDBFileName, strOverallProgress
Dim objAccess
Dim objDatabase
OpenAccessDatabase objAccess, objDatabase, strTempMDBFileName, strOverallProgress
ExportQueries objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
ExportForms objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
ExportReports objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
ExportMacros objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
ExportModules objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
objAccess.CloseCurrentDatabase
objAccess.Quit
DeleteTempDatabase strTempMDBFileName, strOverallProgress
objProgressWindow.Quit
MsgBox "Successfully exported database."

Private Function SelectDatabaseFile()
    MsgBox "Please select the Access database to export."
    Dim objFileOpen : Set objFileOpen = CreateObject("SAFRCFileDlg.FileOpen")
    If objFileOpen.OpenFileOpenDlg Then
        SelectDatabaseFile = objFileOpen.FileName
    Else
        WScript.Quit()
    End If
End Function

Private Function SelectExportFolder()
    Dim objShell : Set objShell = CreateObject("Shell.Application")
    SelectExportFolder = objShell.BrowseForFolder(0, "Select folder to export the database to:", 0, "").self.path & "\"
End Function

Private Sub CreateExportFolders(strExportPath)
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    MsgBox "Existing folders from a previous Access export under " & strExportPath & " will be deleted!"
    If objFileSystem.FolderExists(strExportPath & "Queries\") Then
        objFileSystem.DeleteFolder strExportPath & "Queries", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Queries\")
    If objFileSystem.FolderExists(strExportPath & "Forms\") Then
        objFileSystem.DeleteFolder strExportPath & "Forms", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Forms\")
    If objFileSystem.FolderExists(strExportPath & "Reports\") Then
        objFileSystem.DeleteFolder strExportPath & "Reports", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Reports\")
    If objFileSystem.FolderExists(strExportPath & "Macros\") Then
        objFileSystem.DeleteFolder strExportPath & "Macros", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Macros\")
    If objFileSystem.FolderExists(strExportPath & "Modules\") Then
        objFileSystem.DeleteFolder strExportPath & "Modules", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Modules\")
End Sub

Private Sub CreateProgressWindow(objProgressWindow)
    Set objProgressWindow = CreateObject ("InternetExplorer.Application")
    objProgressWindow.Navigate "about:blank"
    objProgressWindow.ToolBar = 0
    objProgressWindow.StatusBar = 0
    objProgressWindow.Width = 320
    objProgressWindow.Height = 240
    objProgressWindow.Visible = 1
    objProgressWindow.Document.Title = "Access export in progress"
End Sub

Private Sub CopyToTempDatabase(strMDBFileName, strTempMDBFileName, strOverallProgress)
    strOverallProgress = strOverallProgress & "Copying to temporary database...<br/>"
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    strTempMDBFileName = objFileSystem.GetSpecialFolder(TemporaryFolder) & "\" & objFileSystem.GetBaseName(strMDBFileName) & "_temp.mdb"
    objFileSystem.CopyFile strMDBFileName, strTempMDBFileName
End Sub

Private Sub OpenAccessDatabase(objAccess, objDatabase, strTempMDBFileName, strOverallProgress)
    strOverallProgress = strOverallProgress & "Compacting temporary database...<br/>"
    Set objAccess = CreateObject("Access.Application")
    objAccess.Visible = false
    CompactAccessDatabase objAccess, strTempMDBFileName
    strOverallProgress = strOverallProgress & "Opening temporary database...<br/>"
    objAccess.OpenCurrentDatabase strTempMDBFileName
    Set objDatabase = objAccess.CurrentDb
End Sub

' Sometimes the Compact Database command errors out, and it's not serious if the database isn't compacted first.
Private Sub CompactAccessDatabase(objAccess, strTempMDBFileName)
    On Error Resume Next
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    objAccess.DbEngine.CompactDatabase strTempMDBFileName, strTempMDBFileName & "_"
    objFileSystem.CopyFile strTempMDBFileName & "_", strTempMDBFileName
    objFileSystem.DeleteFile strTempMDBFileName & "_"
End Sub

Private Sub ExportQueries(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Queries (Step 1 of 5)...<br/>"
    Dim counter
    For counter = 0 To objDatabase.QueryDefs.Count - 1
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & objDatabase.QueryDefs.Count
        objAccess.SaveAsText acQuery, objDatabase.QueryDefs(counter).Name, strExportPath & "Queries\" & Clean(objDatabase.QueryDefs(counter).Name) & ".sql"
    Next
End Sub

Private Sub ExportForms(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Forms (Step 2 of 5)...<br/>"
    Dim counter : counter = 1
    Dim objContainer : Set objContainer = objDatabase.Containers("Forms")
    Dim objDocument
    For Each objDocument In objContainer.Documents
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter & " of " & objContainer.Documents.Count
        counter = counter + 1
        objAccess.SaveAsText acForm, objDocument.Name, strExportPath & "Forms\" & Clean(objDocument.Name) & ".form"
        objAccess.DoCmd.Close acForm, objDocument.Name
    Next
End Sub

Private Sub ExportReports(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Reports (Step 3 of 5)...<br/>"
    Dim counter : counter = 1
    Dim objContainer : Set objContainer = objDatabase.Containers("Reports")
    Dim objDocument
    For Each objDocument In objContainer.Documents
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter & " of " & objContainer.Documents.Count
        counter = counter + 1
        objAccess.SaveAsText acReport, objDocument.Name, strExportPath & "Reports\" & Clean(objDocument.Name) & ".report"
    Next
End Sub

Private Sub ExportMacros(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Macros (Step 4 of 5)...<br/>"
    Dim counter : counter = 1
    Dim objContainer : Set objContainer = objDatabase.Containers("Scripts")
    Dim objDocument
    For Each objDocument In objContainer.Documents
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter & " of " & objContainer.Documents.Count
        counter = counter + 1
        objAccess.SaveAsText acMacro, objDocument.Name, strExportPath & "Macros\" & Clean(objDocument.Name) & ".macro"
    Next
End Sub

Private Sub ExportModules(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Modules (Step 5 of 5)...<br/>"
    Dim counter : counter = 1
    Dim objContainer : Set objContainer = objDatabase.Containers("Modules")
    Dim objDocument
    For Each objDocument In objContainer.Documents
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter & " of " & objContainer.Documents.Count
        counter = counter + 1
        objAccess.SaveAsText acModule, objDocument.Name, strExportPath & "Modules\" & Clean(objDocument.Name) & ".module"
    Next
End Sub

Private Sub DeleteTempDatabase(strTempMDBFileName, strOverallProgress)
    On Error Resume Next
    strOverallProgress = strOverallProgress & "Deleting temporary database...<br/>"
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    objFileSystem.DeleteFile strTempMDBFileName, true
End Sub

' Windows doesn't like certain characters, so we have to filter those out of the name when exporting
Private Function Clean(strInput)
    Dim objRegexp : Set objRegexp = New RegExp
    objRegexp.IgnoreCase = True
    objRegexp.Global = True
    objRegexp.Pattern = "[\\/:*?""<>|]"
    Dim strOutput
    If objRegexp.Test(strInput) Then
        strOutput = objRegexp.Replace(strInput, "")
        MsgBox strInput & " is being exported as " & strOutput
    Else
        strOutput = strInput
    End If
    Clean = strOutput
End Function

Et pour importer des fichiers dans la base de données, si vous devez recréer la base de données à partir de zéro ou si vous souhaitez modifier des fichiers en dehors d'Access pour une raison quelconque.

AccessImport.vbs:

' Imports all of the queries, forms, reports, macros, and modules from text
' files to an Access file (.mdb).  Requires Microsoft Access.
Option Explicit

const acQuery = 1
const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3
const acCmdCompileAndSaveAllModules = &H7E

Dim strMDBFilename : strMDBFilename = SelectDatabaseFile
CreateBackup strMDBFilename
Dim strImportPath : strImportPath = SelectImportFolder
Dim objAccess
Dim objDatabase
OpenAccessDatabase objAccess, objDatabase, strMDBFilename
Dim objProgressWindow
Dim strOverallProgress
CreateProgressWindow objProgressWindow
ImportQueries objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
ImportForms objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
ImportReports objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
ImportMacros objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
ImportModules objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
objAccess.CloseCurrentDatabase
objAccess.Quit
objProgressWindow.Quit
MsgBox "Successfully imported objects into the database."

Private Function SelectDatabaseFile()
    MsgBox "Please select the Access database to import the objects from.  ALL EXISTING OBJECTS WITH THE SAME NAME WILL BE OVERWRITTEN!"
    Dim objFileOpen : Set objFileOpen = CreateObject( "SAFRCFileDlg.FileOpen" )
    If objFileOpen.OpenFileOpenDlg Then
        SelectDatabaseFile = objFileOpen.FileName
    Else
        WScript.Quit()
    End If
End Function

Private Function SelectImportFolder()
    Dim objShell : Set objShell = WScript.CreateObject("Shell.Application")
    SelectImportFolder = objShell.BrowseForFolder(0, "Select folder to import the database objects from:", 0, "").self.path & "\"
End Function

Private Sub CreateBackup(strMDBFilename)
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    objFileSystem.CopyFile strMDBFilename, strMDBFilename & ".bak"
End Sub

Private Sub OpenAccessDatabase(objAccess, objDatabase, strMDBFileName)
    Set objAccess = CreateObject("Access.Application")
    objAccess.OpenCurrentDatabase strMDBFilename
    objAccess.Visible = false
    Set objDatabase = objAccess.CurrentDb
End Sub

Private Sub CreateProgressWindow(ByRef objProgressWindow)
    Set objProgressWindow = CreateObject ("InternetExplorer.Application")
    objProgressWindow.Navigate "about:blank"
    objProgressWindow.ToolBar = 0
    objProgressWindow.StatusBar = 0
    objProgressWindow.Width = 320
    objProgressWindow.Height = 240
    objProgressWindow.Visible = 1
    objProgressWindow.Document.Title = "Access import in progress"
End Sub

Private Sub ImportQueries(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = "Importing Queries (Step 1 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Queries\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strQueryName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strQueryName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acQuery, strQueryName, file.Path
        counter = counter + 1
    Next
End Sub

Private Sub ImportForms(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Importing Forms (Step 2 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Forms\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strFormName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strFormName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acForm, strFormName, file.Path
        counter = counter + 1
    Next
End Sub

Private Sub ImportReports(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Importing Reports (Step 3 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Reports\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strReportName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strReportName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acReport, strReportName, file.Path
        counter = counter + 1
    Next
End Sub

Private Sub ImportMacros(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Importing Macros (Step 4 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Macros\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strMacroName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strMacroName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acMacro, strMacroName, file.Path
        counter = counter + 1
    Next
End Sub

Private Sub ImportModules(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Importing Modules (Step 5 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Modules\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strModuleName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strModuleName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acModule, strModuleName, file.Path
        counter = counter + 1
    Next

    ' We need to compile the database whenever any module code changes.
    If Not objAccess.IsCompiled Then
        objAccess.RunCommand acCmdCompileAndSaveAllModules
    End If
End Sub
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.