Come si utilizza il controllo versione con lo sviluppo di Access?


163

Sono coinvolto con l'aggiornamento di una soluzione di Access. Ha una buona quantità di VBA, un numero di query, una piccola quantità di tabelle e alcuni moduli per l'immissione dei dati e la generazione di report. È un candidato ideale per l'accesso.

Voglio apportare modifiche al design della tabella, al VBA, alle query e ai moduli. Come posso tenere traccia delle mie modifiche con il controllo versione? (usiamo Subversion, ma questo vale per qualsiasi gusto) Posso attaccare l'intero mdb in sovversione, ma questo memorizzerà un file binario e non sarò in grado di dire che ho appena cambiato una riga di codice VBA.

Ho pensato di copiare il codice VBA per separare i file e salvarli, ma ho potuto vedere quelli che rapidamente si sincronizzavano con ciò che era nel database.


1
Crossposting di questa soluzione alla relativa domanda di esportazione dello schema db di Access.
Eric G,

1
Access supporta l'interfaccia SCC, quindi qualsiasi controllo di versione compatibile con questa interfaccia è pronto per l'accesso. Dichiarazione di non responsabilità: lavoro per plasticscm.com e molti clienti lo utilizzano con Access.
pablo,

Risposte:


180

Abbiamo scritto il nostro script in VBScript, che utilizza Application.SaveAsText () non accessibile in Access per esportare tutti i moduli di codice, modulo, macro e report. Eccolo, dovrebbe darti alcuni suggerimenti. (Attenzione: alcuni dei messaggi sono in tedesco, ma puoi facilmente cambiarlo.)

EDIT: per riassumere i vari commenti qui sotto: Il nostro progetto assume un file .adp. Per farlo funzionare con .mdb / .accdb, devi cambiare OpenAccessProject () in OpenCurrentDatabase (). (Aggiornato per usare OpenAccessProject()se vede un'estensione .adp, altrimenti usa 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

Se è necessario un comando selezionabile, anziché utilizzare la riga di comando, creare un file denominato "decompose.cmd" con

cscript decompose.vbs youraccessapplication.adp

Per impostazione predefinita, tutti i file esportati vanno in una sottocartella "Script" dell'applicazione Access. Il file .adp / mdb viene anche copiato in questa posizione (con un suffisso "stub") e rimosso da tutti i moduli esportati, rendendolo davvero piccolo.

DEVI controllare questo stub con i file di origine, poiché la maggior parte delle impostazioni di accesso e delle barre dei menu personalizzate non possono essere esportate in altro modo. Assicurati di eseguire il commit delle modifiche solo a questo file, se hai davvero modificato alcune impostazioni o menu.

Nota: se nella propria applicazione sono stati definiti Autoexec-Makros, potrebbe essere necessario tenere premuto il tasto Maiusc quando si richiama la decomposizione per impedirne l'esecuzione e l'interferenza con l'esportazione!

Naturalmente, c'è anche lo script inverso, per creare l'applicazione dalla directory "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

Ancora una volta, questo si accompagna a un compagno "compose.cmd" contenente:

cscript compose.vbs youraccessapplication.adp

Ti chiede di confermare la sovrascrittura della tua attuale applicazione e prima crea un backup, se lo fai. Quindi raccoglie tutti i file di origine nella directory di origine e li reinserisce nello stub.

Divertiti!


1
Adoro questo codice. Ho scoperto che oApplication.OpenAccessProject non avrebbe funzionato su un file .accdb (o forse è una cosa di Access 2007) e invece ho dovuto usare oApplication.OpenCurrentDatabase.
hughdbrown,

1
Sto facendo qualcosa di simile (SaveAsText, ma in VBA e con un file MDB anziché ADP), ma ho ancora un grosso problema: dopo ogni esportazione, Subversion riconosce circa 100 file come modificati (anche se ho cambiato solo uno o due ). quando guardo le modifiche, vedo che alcuni nomi di variabili o nomi di controllo hanno cambiato l'ortografia maiuscola / minuscola. Ad esempio: ogni file che una volta conteneva "OrderNumber" ora contiene "Ordernumber" nell'esportazione ed è quindi contrassegnato come "modificato" (almeno da SVN, non ho ancora provato altri SCM). Qualche idea su come posso evitarlo? Molte grazie!
Christian Specht,

3
Sì, questo è un fastidio costante anche nel nostro progetto. Per quanto abbiamo determinato, il problema è che le variabili nel tuo progetto hanno gli stessi nomi dei controlli, solo in casi diversi (alto / basso). Ora, a seconda dell'ordine dei moduli che vengono composti, Access sembra richiedere uno spelling e "correggere" tutti gli altri, poiché si suppone che VBA non faccia distinzione tra maiuscole e minuscole. Access fa questo, anche se i controlli sono in forme diverse! Il problema diventa più grande se hai anche più controlli con lo stesso nome in casi diversi su moduli diversi.
Oliver,

3
L'unica soluzione è quella di dare la caccia a ogni variabile / nome-controllo e cambiare l'ortografia in una forma comune. Dopo un'esportazione e il commit delle modifiche, i nomi dovrebbero essere stabili. Il prefisso dei nomi dei controlli con i loro tipi garantisce praticamente attraverso la convenzione di denominazione che i nomi non si scontrano con le variabili. (ad es. txtTitle per una casella di testo contenente il campo Titolo o gli utenti cmb per una casella combinata e così via)
Oliver,

Ho dimenticato di aggiungere che per ottenere questo lavoro con mdb ho dovuto cambiare OpenAccessProject in OpenCurrentDatabase .
DaveParillo,

19

Sembra essere qualcosa di abbastanza disponibile in Access:

Questo collegamento da msdn spiega come installare un componente aggiuntivo di controllo del codice sorgente per Microsoft Access. Questo è stato fornito come download gratuito come parte delle Access Developer Extensions per Access 2007 e come componente aggiuntivo gratuito separato per Access 2003.

Sono contento che tu abbia posto questa domanda e mi sono preso il tempo di cercarla, perché anch'io vorrei questa capacità. Il link sopra ha maggiori informazioni su questo e link ai componenti aggiuntivi.

Aggiornamento:
ho installato il componente aggiuntivo per Access 2003. Funzionerà solo con VSS, ma mi consente di inserire oggetti di Access (moduli, query, tabelle, moduli, ecc.) Nel repository. Quando vai a modificare qualsiasi elemento nel repository ti viene chiesto di verificarlo, ma non è necessario. Ora vado a controllare come gestisce l'apertura e la modifica su un sistema senza il componente aggiuntivo. Non sono un fan di VSS, ma mi piace molto l'idea di archiviare oggetti di accesso in un repository.

Aggiornamento2: i
computer senza il componente aggiuntivo non sono in grado di apportare modifiche alla struttura del database (aggiungere campi tabella, parametri query, ecc.). All'inizio ho pensato che questo potesse essere un problema se qualcuno lo avesse dovuto, poiché non c'era modo apparente per rimuovere il database di Access dal controllo del codice sorgente se Access non avesse caricato il componente aggiuntivo.

Ho scoperto che l'esecuzione del database "compatto e riparatore" richiede se si desidera rimuovere il database dal controllo del codice sorgente. Ho scelto Sì e sono stato in grado di modificare il database senza il componente aggiuntivo. L'articolo nel link sopra fornisce anche istruzioni sull'installazione di Access 2003 e 2007 per l'utilizzo di Team System. Se riesci a trovare un provider MSSCCI per SVN, ci sono buone probabilità che riesca a farlo funzionare.


Si noti che abbiamo avuto alcuni problemi con l'impossibilità di estrarre un ADP da VSS se più di una persona lo aveva modificato. Alla fine abbiamo dovuto disporre di un backup separato per questo!
Simon,

Ho giocato con questo approccio (usando Vault, poiché non conosco provider MSSCCI gratuiti per SVN ... TortoiseSVNSCC non è mantenuto e non ha funzionato per me, e le altre due o tre opzioni sono commerciali). Funziona, ma ti costringe a utilizzare l'approccio arcaico di esclusione esclusiva al controllo del codice sorgente, e per questo motivo ho intenzione di abbandonarlo e utilizzare la soluzione di @ Oliver.
Todd Owen,

14

La soluzione di composizione / decomposizione pubblicata da Oliver è eccezionale, ma presenta alcuni problemi:

  • I file sono codificati come UCS-2 (UTF-16) che può far sì che i sistemi / strumenti di controllo della versione considerino i file binari.
  • I file contengono molte cruft che cambiano spesso: checksum, informazioni sulla stampante e altro. Questo è un grave problema se si desidera avere differenze pulite o se è necessario collaborare al progetto.

Avevo intenzione di risolvere questo problema da solo, ma ho scoperto che esiste già una buona soluzione disponibile: timabell / msaccess-vcs-integrazione su GitHub. Ho testato l'integrazione msaccess-vcs e funziona benissimo.

Aggiornato il 3 marzo 2015 : il progetto era originariamente mantenuto / di proprietà di bkidwell su Github, ma è stato trasferito su timabell - il link sopra al progetto viene aggiornato di conseguenza. Ci sono alcune forcelle del progetto originale di bkidwell, ad esempio da ArminBra e da matonb , che AFAICT non dovrebbe essere usato.

L'aspetto negativo di utilizzare l'integrazione msaccess-vcs rispetto alla soluzione di decomposizione di Olivers:

  • È significativamente più lento. Sono sicuro che il problema di velocità può essere risolto, ma non ho bisogno di esportare il mio progetto in testo che spesso ...
  • Non crea un progetto Accesso stub con le cose esportate rimosse. Questo può anche essere risolto (adottando il codice dallo script di decomposizione), ma ancora una volta - non è così importante.

Ad ogni modo, la mia chiara raccomandazione è msaccess-vcs-integrazione. Ha risolto tutti i problemi che ho avuto con l'uso di Git sui file esportati.


Sembra che il fork di ArminBra sia in vantaggio ora (immaginato guardando il grafico di rete ). Matonb non ha risposto all'unica richiesta pull quindi credo che almeno per ora l'abbia abbandonata.
Tim Abell,

1
E ora c'è anche il mio fork github.com/timabell/msaccess-vcs-integration - corregge la rottura dell'esportazione della tabella delle chiavi composte. Gli altri due sembrano un po 'abbandonati, quindi sono felice di ricevere segnalazioni di bug richieste ecc. Sul mio fork.
Tim Abell,

Suggerirei cortesemente di modificare questa risposta per indicare il mio fork in quanto è ora la versione mantenuta più attivamente.
Tim Abell

2
@TimAbell: ho aggiornato la mia risposta per riflettere il fatto che il progetto è stato trasferito a te. PS! Spero di poter ottenere alcuni voti positivi poiché penso che questa sia la soluzione migliore.
Hansfn,

2
bello, navigare nelle forcelle di un progetto github sembra essere l'ultimo problema che abbiamo inventato per noi stessi :-)
Tim Abell

14

Olivers risponde alle rocce, ma il CurrentProject riferimento non funzionava per me. Ho finito per strappare le viscere dal mezzo della sua esportazione e sostituirlo con questo, basato su una soluzione simile di Arvin Meyer . Ha il vantaggio di esportare query se stai usando un mdb invece di 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 per l'inclusione di query. Ora ho solo bisogno di includere schemi di tabella.
Marc Stober,

La risposta approvata non funziona per Access 97, ma questa risposta mi ha aiutato a modificarla per i miei usi. Grazie per aver postato questo!
CTristan,

2
Consiglio vivamente di inserire il salvataggio della query prima del salvataggio dei moduli per modificare l'ordine di eliminazione in un secondo momento. Ho avuto qualche problema con DeleteObject nell'ultima istruzione For Each quando ho provato a eliminare le query che sono già state eliminate automaticamente quando i loro moduli corrispondenti sono stati eliminati in precedenza. Inoltre, se hai alcuni moduli che si aprono all'avvio e non vuoi tenere F11 (o averlo disattivato), inserisci semplicemente oApp.DoCmd.Chiudi acForm, "formName" dopo la tua corsa in gola
Anton Kaiser

@Cunso Per favore, puoi pubblicare il tuo codice compatibile con Access 97. Quindi non ho bisogno di riqualificarlo.
Lorenz Meyer,

come lo uso? Chiamalo da un sub?
kevinykuo,

11

Abbiamo sviluppato il nostro strumento interno, dove:

  1. Moduli: vengono esportati come file txt e quindi confrontati con "strumento di confronto file" (freeware)
  2. Moduli: vengono esportati tramite il comando application.saveAsText undocument. È quindi possibile vedere le differenze tra 2 diverse versioni ("strumento di confronto file" ancora una volta).
  3. Macro: non abbiamo alcuna macro da confrontare, in quanto abbiamo solo la macro "autoexec" con una riga che avvia la procedura VBA principale
  4. Query: sono solo stringhe di testo memorizzate in una tabella: vedi infra
  5. tabelle: abbiamo scritto il nostro comparatore di tabelle, elencando le differenze nei record E nella struttura delle tabelle.

L'intero sistema è abbastanza intelligente da permetterci di produrre versioni "runtime" della nostra applicazione Access, generate automaticamente da file txt (moduli e moduli ricreati con il comando application.loadFromText non documentato) e file mdb (tabelle).

Potrebbe sembrare strano ma funziona.


8
Mi piacerebbe vedere questo strumento di provenienza aperta!
Todd Owen,

Sarà una buona idea caricare questi file di testo esportati su GitHub?
Santosh,

9

Sulla base delle idee di questo post e di voci simili in alcuni blog, ho scritto un'applicazione che funziona con i formati di file mdb e adp. Importa / esporta tutti gli oggetti del database (inclusi tabelle, riferimenti, relazioni e proprietà del database) in file di testo semplice. Con questi file puoi lavorare con qualsiasi controllo della versione di origine. La prossima versione consentirà di importare nuovamente i file di testo normale nel database. Ci sarà anche uno strumento da riga di comando

È possibile scaricare l'applicazione o il codice sorgente da: http://accesssvn.codeplex.com/

Saluti


Lo usiamo da quasi due anni ed è fantastico. Grazie!
mcfea,

5

Risurrezione di un vecchio thread ma questo è buono. Ho implementato i due script (compose.vbs / decompose.vbs) per il mio progetto e ho riscontrato un problema con i vecchi file .mdb:

Si blocca quando arriva a un modulo che include il codice:

NoSaveCTIWhenDisabled =1

Access dice che ha un problema e questa è la fine della storia. Ho eseguito alcuni test e ho cercato di aggirare questo problema e ho trovato questo thread alla fine con una soluzione:

Impossibile creare il database

Fondamentalmente (nel caso in cui il thread si interrompa), prendi il .mdb e fai un "Salva con nome" nel nuovo formato .accdb. Quindi funzionerà la fonte sicura o comporrà / decomporrà le cose. Ho anche dovuto giocare per 10 minuti per ottenere la giusta sintassi della riga di comando affinché gli script (de) compose funzionino bene, quindi ecco anche queste informazioni:

Per comporre (supponiamo che le tue cose si trovino in C: \ SControl (crea una sottocartella chiamata Source per archiviare i file estratti):

'(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\

Questo è tutto!

Le versioni di Access in cui ho riscontrato il problema sopra includono database ".mdb" di Access 2000-2003 e risolto il problema salvandoli nei formati ".accdb" 2007-2010 prima di eseguire gli script compose / decompose. Dopo la conversione gli script funzionano bene!


È possibile modificarlo per includere le versioni di Access in cui si è verificato questo problema?
Nathan DeWitt,

Nessun problema, stai ancora sviluppando l'accesso Nathan? In tal caso qualche successo integrandolo con il controllo versione?
JKK

Non sto più facendo lo sviluppo di Access. Avevo un progetto che ho usato su questo quando ho fatto la domanda, e non ho mai dovuto fare altro.
Nathan DeWitt,

Bene, penso che la maggior parte delle aziende utilizzi un tipo di server SQL dedicato. La situazione in cui mi trovo ora è un misto di MS SQL Server, Oracle e un mucchio di database Access che tirano giù i dati dai server alle tabelle locali ed esportano in Excel. È una miscela abbastanza complicata. Penso che inizierò una nuova domanda su alcuni suggerimenti per la creazione di un nuovo progetto. Presto, vedrò cosa le persone possono suggerire per ridurre la complessità
JKK

4

Soluzione solo per file di testo (query, tabelle e relazioni incluse)

Ho modificato la coppia di script di Oliver in modo da esportare / importare relazioni, tabelle e query oltre a moduli, classi, moduli e macro. Tutto viene salvato in file di testo normale, quindi non è stato creato alcun file di database da archiviare con i file di testo nel controllo versione.

Esporta in file di testo (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

È possibile eseguire questo script chiamando cscript decompose.vbs <path to file to decompose> <folder to store text files>. Se si omette il secondo parametro, verrà creata la cartella "Origine" in cui si trova il database. Si noti che la cartella di destinazione verrà cancellata se esiste già.

Includi i dati nelle tabelle esportate

Sostituisci riga 93: oApplication.ExportXML acExportTable, myObj.Name, , sExportpath & "\" & myObj.Name & ".table.txt"

con la linea oApplication.ExportXML acExportTable, myObj.Name, sExportpath & "\" & myObj.Name & ".table.txt"

Importa in Crea file di database (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

È possibile eseguire questo script chiamando cscript compose.vbs <path to file which should be created> <folder with text files> . Se si omette il secondo parametro, verrà visualizzata la cartella "Origine" in cui è necessario creare il database.

Importa dati da file di testo

Sostituire la riga 14: const acStructureOnly = 0con const acStructureOnly = 1. Funzionerà solo se hai incluso i dati nella tabella esportata.

Cose che non sono coperte

  1. Ho provato questo solo con file .accdb, quindi con qualsiasi altra cosa potrebbero esserci dei bug.
  2. Le impostazioni non vengono esportate, consiglierei di creare la Macro che applicherà l'impostazione all'avvio del database.
  3. Alcune query sconosciute vengono talvolta esportate e precedute da '~'. Non so se sono necessari.
  4. I nomi degli oggetti MSAccess possono contenere caratteri non validi per i nomi dei file : lo script non riuscirà quando si tenta di scriverli. Puoi normalizzare tutti i nomi di file , ma non puoi reimportarli.

Una delle mie altre risorse mentre lavoravo a questo script era questa risposta , che mi ha aiutato a capire come esportare le relazioni.


Questo sembra funzionare, ma non comprende le tabelle collegate
Lord Darth Vader il

2

C'è un gotcha: VSS 6.0 può accettare solo MDB usando il componente aggiuntivo sotto un certo numero di oggetti, che include tutte le tabelle, query, moduli e moduli locali. Non conosco il limite esatto dell'oggetto.

Per costruire la nostra app di 10 anni prod floor, che è enorme, siamo costretti a combinare 3 o 4 MDB separati da SS in un MDB, il che complica le build automatizzate al punto che non perdiamo tempo a farlo.

Penso che proverò lo script sopra per diffondere questo MDb in SVN e semplificare le build per tutti.


2

Per coloro che utilizzano Access 2010, SaveAsText non è un metodo visibile in Intellisense ma sembra essere un metodo valido, poiché lo script di Arvin Meyer menzionato in precedenza ha funzionato bene per me.

È interessante notare che SaveAsAXL è una novità di 2010 e ha la stessa firma di SaveAsText, anche se sembra che funzionerà solo con database Web, che richiedono SharePoint Server 2010.


Anche SaveAsText non è visibile in A2003, a meno che non sia attivato Show Hidden Members nel browser degli oggetti. Buone informazioni su SaveAsAXL.
David-W-Fenton,

2

Abbiamo avuto lo stesso problema qualche tempo fa.

Il nostro primo tentativo è stato uno strumento di terze parti che offre un proxy dell'API SourceSafe per Subversion da utilizzare con MS Access e VB 6. Lo strumento è disponibile qui .

Dato che non eravamo così soddisfatti di questo strumento, siamo passati a Visual SourceSafe e al plug-in VSS Acces.


2

Sto usando Oasis-Svn http://dev2dev.de/

Posso solo dire che mi ha salvato almeno una volta. Il mio mdb stava crescendo oltre i 2 GB e questo l'ha rotto. Potrei tornare a una versione precedente e importare i moduli e ho perso un giorno o due di lavoro.


1

Ho trovato questo strumento su SourceForge: http://sourceforge.net/projects/avc/

Non l'ho usato, ma potrebbe essere un inizio per te. Potrebbero esserci altri strumenti di terze parti che si integrano con VSS o SVN e che fanno ciò di cui hai bisogno.

Personalmente tengo a portata di mano un semplice file di testo per tenere un registro delle modifiche. Quando eseguo il commit dell'MDB binario, utilizzo le voci nel registro delle modifiche come commento di commit.


Hai effettivamente un link per scaricarlo? Sono cieco? Non riesco a trovarlo.
BIBD


1

Per completezza ...

Esistono sempre "Strumenti di Visual Studio [ANNO] per Microsoft Office System" ( http://msdn.microsoft.com/en-us/vs2005/aa718673.aspx ) ma ciò sembra richiedere VSS. Per me VSS (corruzione automatica) è peggio dei miei 347 punti di salvataggio sulla mia condivisione di rete di cui ho effettuato il backup.


1

sto usando il componente aggiuntivo di Access 2003: controllo del codice sorgente . Funziona bene Un problema sono i caratteri non validi come un ":".

Sto effettuando il check-in e il check-out. Internamente il componente aggiuntivo fa lo stesso del codice lassù, ma con più strumenti di supporto. Posso vedere se un oggetto è stato estratto e aggiornare gli oggetti.



1

La risposta di Oliver funziona alla grande. Di seguito trovi la mia versione estesa che aggiunge il supporto per le query di Access.

( per ulteriori informazioni / utilizzo , consultare la risposta di Oliver )

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

Ho cercato di contribuire alla sua risposta aggiungendo un'opzione di esportazione per le query nel database di accesso. (Con ampio aiuto da altre risposte 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

Non sarò in grado di riportarlo nella funzione "componi", ma non è quello che mi serve per farlo in questo momento.

Nota: ho anche aggiunto ".txt" a ciascuno dei nomi di file esportati in decompose.vbs modo che il controllo del codice sorgente mi mostrasse immediatamente le differenze del file.

Spero che aiuti!



0

Questa voce descrive un approccio totalmente diverso dalle altre voci e potrebbe non essere quello che stai cercando. Quindi non mi offenderò se lo ignori. Ma almeno è uno spunto di riflessione.

In alcuni ambienti di sviluppo software commerciale professionale, la gestione della configurazione (CM) dei prodotti software non viene normalmente eseguita all'interno dell'applicazione software stessa o del progetto software stesso. Il CM viene imposto sui prodotti finali consegnabili, salvando il software in una cartella CM speciale, in cui sia il file che la sua cartella sono contrassegnati con l'identificazione della versione. Ad esempio, Clearcase consente al gestore dati di "archiviare" un file software, assegnargli un "ramo", assegnargli un "fumetto" e applicare "etichette". Quando si desidera visualizzare e scaricare un file, è necessario configurare le "specifiche di configurazione" in modo che puntino alla versione desiderata, quindi cd nella cartella e il gioco è fatto.

Solo un'idea


0

Per chiunque fosse bloccato con Access 97, non ero in grado di far funzionare le altre risposte. Utilizzando una combinazione delle eccellenti risposte di Oliver e DaveParillo e apportando alcune modifiche, sono stato in grado di far funzionare gli script con i nostri database di Access 97. È anche un po 'più user-friendly in quanto chiede quale cartella posizionare i file.

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

E per l'importazione di file nel database, è necessario ricreare il database da zero o se si desidera modificare i file al di fuori di Access per qualche motivo.

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
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.