Como você usa o controle de versão no desenvolvimento do Access?


163

Estou envolvido na atualização de uma solução do Access. Possui uma boa quantidade de VBA, várias consultas, uma pequena quantidade de tabelas e alguns formulários para entrada de dados e geração de relatórios. É um candidato ideal para o Access.

Quero fazer alterações no design da tabela, no VBA, nas consultas e nos formulários. Como posso acompanhar minhas alterações com o controle de versão? (usamos o Subversion, mas isso vale para qualquer sabor). Posso colocar o mdb inteiro no subversion, mas isso armazenará um arquivo binário e não poderei dizer que mudei apenas uma linha do código VBA.

Pensei em copiar o código VBA para separar arquivos e salvá-los, mas pude ver aqueles ficando rapidamente fora de sincronia com o conteúdo do banco de dados.


1
Cruzando esta solução para a questão relacionada da exportação do esquema do Access db.
Eric G

1
O Access suporta a interface SCC, portanto, qualquer controle de versão compatível com esta interface está pronto para o Access. Isenção de responsabilidade: trabalho para plasticscm.com e vários clientes o utilizam com o Access.
pablo

Respostas:


180

Escrevemos nosso próprio script no VBScript, que usa o Application.SaveAsText () não documentado no Access para exportar todos os módulos de código, formulário, macro e relatório. Aqui está, ele deve fornecer algumas dicas. (Cuidado: algumas das mensagens estão em alemão, mas você pode facilmente mudar isso.)

EDIT: Para resumir vários comentários abaixo: Nosso projeto assume um arquivo .adp. Para obter esse trabalho com .mdb / .accdb, você deve alterar o OpenAccessProject () para OpenCurrentDatabase (). (Atualizado para usar OpenAccessProject()se houver uma extensão .adp, use outra 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 você precisar de um comando clicável, em vez de usar a linha de comando, crie um arquivo chamado "decompose.cmd" com

cscript decompose.vbs youraccessapplication.adp

Por padrão, todos os arquivos exportados entram em uma subpasta "Scripts" do seu aplicativo Access. O arquivo .adp / mdb também é copiado para esse local (com um sufixo "stub") e removido de todos os módulos exportados, tornando-o muito pequeno.

Você DEVE verificar este esboço com os arquivos de origem, porque a maioria das configurações de acesso e barras de menus personalizadas não podem ser exportadas de nenhuma outra maneira. Apenas certifique-se de confirmar as alterações neste arquivo apenas se você realmente alterou alguma configuração ou menu.

Nota: Se você tiver qualquer Autoexec-Makros definido em seu Aplicativo, poderá ser necessário manter a tecla Shift pressionada ao chamar a decomposição para impedir que seja executada e interfira na exportação!

Obviamente, também existe o script reverso, para criar o Aplicativo no Diretório "Origem":

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

Novamente, isso acompanha um companheiro "compose.cmd" que contém:

cscript compose.vbs youraccessapplication.adp

Ele solicita que você confirme a substituição do aplicativo atual e primeiro crie um backup, se o fizer. Em seguida, ele coleta todos os arquivos de origem no Diretório de origem e os reinsere no stub.

Diverta-se!


1
Eu amo esse código. Eu descobri que o oApplication.OpenAccessProject não funcionaria em um arquivo .accdb (ou talvez seja uma coisa do Access 2007) e eu tive que usar oApplication.OpenCurrentDatabase.
hughdbrown 4/08/09

1
Estou fazendo algo semelhante (SaveAsText, mas no VBA e com um arquivo MDB em vez do ADP), mas ainda tenho um grande problema: após cada exportação, o Subversion reconhece cerca de 100 arquivos alterados (mesmo que eu tenha alterado apenas um ou dois ) Quando olho para as alterações, vejo que alguns nomes de variáveis ​​ou nomes de controle alteraram a ortografia em maiúsculas / minúsculas. Por exemplo: todo arquivo que já continha "OrderNumber" agora contém "Ordernumber" na exportação e, portanto, é marcado como "alterado" (pelo menos pelo SVN, ainda não tentou outro SCM). Alguma idéia de como posso evitar isso? Muito obrigado!
11119 Christian Specht

3
Sim, isso também é um aborrecimento constante em nosso projeto. Até onde determinamos, o problema é que variáveis ​​em seu projeto têm os mesmos nomes que controles, apenas em casos diferentes (acima / baixo). Agora, dependendo da ordem dos módulos que estão sendo compostos, o Access parece ter uma ortografia e "corrigir" todos os outros, já que o VBA não diferencia maiúsculas de minúsculas. O Access faz isso, mesmo que os controles estejam em formas diferentes! O problema aumenta se você tiver vários controles com o mesmo nome em casos diferentes, em formas diferentes.
1113 Oliver Oliver

3
A única solução é procurar cada nome de variável / controle e alterar a ortografia para um formulário comum. Após uma exportação e confirmação das alterações, os nomes devem ser estáveis. A prefixação dos nomes de controle com seus tipos garante, por convenção de nomenclatura, que os nomes não colidem com variáveis. (por exemplo txtTitle para uma caixa de texto contendo o campo Título ou cmbUsers para uma caixa de combinação e assim por diante)
Oliver

Esqueci de adicionar que, para obter esse trabalho com o mdb, eu tive que mudar o OpenAccessProject para OpenCurrentDatabase .
DaveParillo 4/12/2009

19

Parece ser algo bastante disponível no Access:

Este link do msdn explica como instalar um suplemento de controle de origem para o Microsoft Access. Ele foi enviado como um download gratuito como parte das Extensões de Desenvolvedor do Access para Access 2007 e como um suplemento gratuito separado para o Access 2003.

Fico feliz que você tenha feito essa pergunta e dediquei um tempo para procurá-la, pois também gostaria dessa capacidade. O link acima tem mais informações sobre isso e links para os suplementos.

Atualizar:
instalei o suplemento para o Access 2003. Ele funcionará apenas com o VSS, mas me permite colocar objetos do Access (formulários, consultas, tabelas, módulos, ect) no repositório. Ao editar qualquer item no repositório, você é solicitado a fazer o check-out, mas não precisa. Em seguida, vou verificar como ele lida com a abertura e alteração de sistemas sem o suplemento. Não sou fã do VSS, mas realmente gosto do pensamento de armazenar objetos de acesso em um repositório.

Atualização 2:
Máquinas sem o suplemento não podem fazer alterações na estrutura do banco de dados (adicionar campos da tabela, parâmetros de consulta, etc.). No começo, pensei que isso poderia ser um problema se alguém precisasse, pois não havia uma maneira aparente de remover o banco de dados do Access do controle de origem se o Access não tivesse o suplemento carregado.

O ID descobriu que a execução do banco de dados "compactar e reparar" solicita que você deseje remover o banco de dados do controle de origem. Optei sim e consegui editar o banco de dados sem o suplemento. O artigo no link acima também fornece instruções sobre como configurar o Access 2003 e 2007 para usar o Team System. Se você puder encontrar um provedor MSSCCI para SVN, há uma boa chance de fazê-lo funcionar.


Observe que tivemos alguns problemas em não poder verificar um ADP do VSS se mais de uma pessoa o editou. Acabamos precisando ter um backup separado para isso!
22710 Simon

Eu brinquei com essa abordagem (usando o Vault, já que não conheço nenhum provedor MSSCCI gratuito para SVN ... O TortoiseSVNSCC não é mantido e não funcionou para mim, e as outras duas ou três opções são comerciais). Funciona, mas obriga a usar a abordagem arcaica de bloqueio exclusivo para o controle de origem e, por esse motivo, pretendo abandoná-lo e usar a solução do @ Oliver.
Todd Owen

14

A solução de composição / decomposição postada por Oliver é ótima, mas tem alguns problemas:

  • Os arquivos são codificados como UCS-2 (UTF-16), o que pode fazer com que os sistemas / ferramentas de controle de versão considerem os arquivos binários.
  • Os arquivos contêm muitas informações que são alteradas com frequência - somas de verificação, informações da impressora e muito mais. Esse é um problema sério se você quiser diferenças limpas ou precisar cooperar no projeto.

Eu estava planejando consertar isso sozinho, mas descobri que já existe uma boa solução disponível: timabell / msaccess-vcs-integration no GitHub. Eu testei a integração msaccess-vcs-e funciona muito bem.

Atualizado em 3 de março de 2015 : o projeto foi originalmente mantido / de propriedade da bkidwell no Github, mas foi transferido para timabell - o link acima para o projeto é atualizado de acordo. Existem alguns garfos do projeto original da bkidwell, por exemplo, da ArminBra e da matonb , que o AFAICT não deve ser usado.

A desvantagem de usar a integração msaccess-vcs-comparado à solução de decomposição da Olivers:

  • É significativamente mais lento. Tenho certeza de que o problema de velocidade pode ser corrigido, mas não preciso exportar meu projeto para texto com tanta frequência ...
  • Ele não cria um projeto de stub Access com o material exportado removido. Isso também pode ser corrigido (adotando o código do script de decomposição), mas novamente - não é tão importante.

De qualquer forma, minha recomendação clara é msaccess-vcs-integration. Resolveu todos os problemas que tive ao usar o Git nos arquivos exportados.


Parece que o garfo ArminBra está à frente agora (calculado olhando para o gráfico da rede ). Matonb não respondeu à única solicitação pull, então acho que eles a abandonaram por agora, pelo menos.
precisa

1
E agora também há meu garfo github.com/timabell/msaccess-vcs-integration - corrige a quebra de exportação de tabela de chaves composta. Os outros dois parecem um pouco abandonados, por isso estou feliz em receber solicitações de pull, relatórios de bugs etc. no meu fork.
precisa

Eu sugeriria educadamente editar esta resposta para apontar para o meu fork, pois agora é a versão mais ativamente mantida.
precisa

2
@ TimAbell: Atualizei minha resposta para refletir o fato de que o projeto foi transferido para você. PS! Espero que possamos obter alguns votos positivos, pois acho que essa é a melhor solução.
hansfn #

2
nice one, navegando os garfos de um projeto github parece ser o mais recente problema que inventamos para nós mesmos :-)
Tim Abell

14

Os olivers respondem rochas, mas a CurrentProjectreferência não estava funcionando para mim. Acabei arrancando as tripas do meio de suas exportações e substituindo-as por isso, com base em uma solução semelhante de Arvin Meyer . Tem a vantagem de exportar consultas se você estiver usando um mdb em vez de um 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 para incluir consultas. Agora só precisa incluir esquemas de tabela.
Marc Stober

A resposta aprovada não funciona para o Access 97, mas essa resposta me ajudou a modificá-la para meus próprios usos. Obrigado por postar isso!
precisa saber é o seguinte

2
Eu recomendo fortemente que a consulta seja salva antes dos formulários, para alterar a ordem de exclusão posteriormente. Eu tive alguns problemas com o DeleteObject na última instrução For Each quando tentei excluir as consultas que já foram excluídas automaticamente quando os formulários correspondentes foram excluídos anteriormente. Além disso, se você tiver alguns formulários abrindo na inicialização e não quiser segurar o F11 (ou desativá-lo), basta inserir oApp.DoCmd.Close acForm, "formName" após a execução através do cnt.Documents
Anton Kaiser

@ Cunso Por favor, você pode postar seu código que seja compatível com o Access 97. Portanto, não preciso revitalizá-lo.
Lorenz Meyer

como eu uso isso? Chamá-lo de um sub?
Kevinykuo

11

Desenvolvemos nossa própria ferramenta interna, onde:

  1. Módulos: são exportados como arquivos txt e comparados com a "ferramenta de comparação de arquivos" (freeware)
  2. Formulários: são exportados pelo comando undocument application.saveAsText. É então possível ver as diferenças entre duas versões diferentes ("ferramenta de comparação de arquivos" mais uma vez).
  3. Macros: não temos nenhuma macro para comparar, pois só temos a macro "autoexec" com uma linha iniciando o procedimento principal do VBA
  4. Consultas: são apenas cadeias de texto armazenadas em uma tabela: consulte infra
  5. tabelas: escrevemos nosso próprio comparador de tabelas, listando as diferenças nos registros E na estrutura da tabela.

Todo o sistema é inteligente o suficiente para permitir a produção de versões em "tempo de execução" do aplicativo Access, geradas automaticamente a partir de arquivos txt (módulos e formulários sendo recriados com o comando application.loadFromText) e arquivos mdb (tabelas).

Pode parecer estranho, mas funciona.


8
Adoraria ver esta ferramenta de código aberto!
Todd Owen

Será uma boa ideia fazer upload desses arquivos de texto exportados no GitHub?
Santosh

9

Com base nas idéias deste post e em entradas semelhantes em alguns blogs, escrevi um aplicativo que funciona com os formatos de arquivo mdb e adp. Ele importa / exporta todos os objetos do banco de dados (incluindo tabelas, referências, relações e propriedades do banco de dados) para arquivos de texto sem formatação. Com esses arquivos, você pode trabalhar com qualquer controle de versão de origem. A próxima versão permitirá importar de volta os arquivos de texto sem formatação para o banco de dados. Também haverá uma ferramenta de linha de comando

Você pode baixar o aplicativo ou o código-fonte em: http://accesssvn.codeplex.com/

Saudações


Estamos usando isso há quase dois anos e é ótimo. Obrigado!
Mcfea 06/06

5

Ressuscitando um thread antigo, mas este é um bom. Eu implementei os dois scripts (compose.vbs / decompose.vbs) para o meu próprio projeto e tive um problema com arquivos .mdb antigos:

Ele pára quando chega a um formulário que inclui o código:

NoSaveCTIWhenDisabled =1

O Access diz que tem um problema e esse é o fim da história. Fiz alguns testes e tentei contornar esse problema e encontrei esse tópico com uma solução alternativa no final:

Não é possível criar o banco de dados

Basicamente (caso o encadeamento fique inoperante), você pega o .mdb e faz um "Salvar como" no novo formato .accdb. Então a fonte segura ou o material de composição / decomposição funcionará. Eu também tive que brincar por 10 minutos para obter a sintaxe correta da linha de comando para que os scripts (de) compor funcionassem corretamente, então aqui estão essas informações:

Para compor (diga que seu material está localizado em C: \ SControl (crie uma subpasta chamada Origem para armazenar os arquivos extraídos):

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

É isso aí!

As versões do Access em que eu tive o problema acima incluem os bancos de dados ".mdb" do Access 2000-2003 e corrigimos o problema, salvando-os nos formatos ".accdb" 2007-2010 antes de executar os scripts de composição / decomposição. Após a conversão, os scripts funcionam muito bem!


Você pode editar isso para incluir suas versões do Access, onde você encontra esse problema?
Nathan DeWitt

Não tem problema, você ainda está fazendo o desenvolvimento de acesso Nathan? Em caso afirmativo, algum sucesso ao integrá-lo ao controle de versão?
JKK

Não estou mais desenvolvendo o Access. Eu tinha um projeto que usei no caminho de volta quando fiz a pergunta e nunca precisei fazer mais nada com ela.
Nathan DeWitt

Legal, acho que a maioria das empresas usa algum tipo de servidor SQL dedicado. A situação em que estou agora é uma mistura de MS SQL Server, Oracle e um monte de bancos de dados do Access que extraem dados dos servidores para as tabelas locais e exportam para o Excel. É uma mistura bastante complicada. Acho que vou começar uma nova pergunta sobre algumas sugestões para a criação de um novo projeto que estará em breve, ver o que as pessoas podem sugerir para reduzir a complexidade
JKK

4

Solução apenas de arquivo de texto (consultas, tabelas e relacionamentos incluídos)

Alterei o par de scripts do Oliver para que eles exportem / importem relacionamentos, tabelas e consultas , além de módulos, classes, formulários e macros. Tudo é salvo em arquivos de texto sem formatação, portanto, não há arquivo de banco de dados criado para ser armazenado com os arquivos de texto no controle de versão.

Exportar para arquivos de texto (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

Você pode executar esse script chamando cscript decompose.vbs <path to file to decompose> <folder to store text files>. Caso você omita o segundo parâmetro, ele criará a pasta 'Source' onde o banco de dados está localizado. Observe que a pasta de destino será apagada se já existir.

Incluir dados nas tabelas exportadas

Substitua a linha 93: oApplication.ExportXML acExportTable, myObj.Name, , sExportpath & "\" & myObj.Name & ".table.txt"

com linha oApplication.ExportXML acExportTable, myObj.Name, sExportpath & "\" & myObj.Name & ".table.txt"

Importar para Criar arquivo de banco de dados (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

Você pode executar esse script chamando cscript compose.vbs <path to file which should be created> <folder with text files>. Caso você omita o segundo parâmetro, ele procurará na pasta 'Source' onde o banco de dados deve ser criado.

Importar dados do arquivo de texto

Substitua a linha 14: const acStructureOnly = 0por const acStructureOnly = 1. Isso funcionará apenas se você tiver incluído os dados na tabela exportada.

Coisas que não são cobertas

  1. Eu testei isso apenas com arquivos .accdb, portanto, com qualquer outra coisa, pode haver alguns erros.
  2. A configuração não é exportada, eu recomendaria criar a Macro que aplicará a configuração no início do banco de dados.
  3. Algumas consultas desconhecidas às vezes são exportadas e precedidas por '~'. Não sei se são necessárias.
  4. Os nomes de objetos do MSAccess podem conter caracteres inválidos para nomes de arquivos - o script falhará ao tentar gravá-los. Você pode normalizar todos os nomes de arquivos , mas não pode importá-los de volta.

Um dos meus outros recursos enquanto trabalhava nesse script era essa resposta , que me ajudou a descobrir como exportar relacionamentos.


Isso parece funcionar, mas não entende tabelas vinculadas
Lord Darth Vader

2

Há um problema: o VSS 6.0 só pode aceitar MDBs usando o suplemento em um certo número de objetos, o que inclui todas as tabelas, consultas, módulos e formulários locais. Não sabe o limite exato do objeto.

Para criar nosso aplicativo de produto de 10 anos, que é enorme, somos obrigados a combinar 3 ou 4 MDBs separados do SS em um MDB, o que complica as compilações automatizadas a ponto de não perdermos tempo fazendo isso.

Acho que vou tentar o script acima para espalhar esse MDb no SVN e simplificar as compilações para todos.


2

Para aqueles que usam o Access 2010, o SaveAsText não é um método visível no Intellisense, mas parece ser um método válido, pois o script de Arvin Meyer mencionado anteriormente funcionou bem para mim.

Curiosamente, SaveAsAXL é novo em 2010 e tem a mesma assinatura que SaveAsText, embora pareça que funcionará apenas com bancos de dados da Web, que exigem o SharePoint Server 2010.


SaveAsText também não está visível no A2003, a menos que você tenha Mostrar Membros Ocultos ativados no Pesquisador de Objetos. Boas informações sobre o SaveAsAXL.
David-W-Fenton

2

Tivemos o mesmo problema há um tempo atrás.

Nossa primeira tentativa foi uma ferramenta de terceiros que oferece um proxy da API SourceSafe para Subversion a ser usado com o MS Access e o VB 6. A ferramenta pode ser encontrada aqui .

Como não estávamos tão satisfeitos com essa ferramenta, passamos para o Visual SourceSafe e o VSS Acces Plugin.


2

Estou usando o Oasis-Svn http://dev2dev.de/

Só posso dizer que me salvou pelo menos uma vez. Meu mdb estava crescendo além de 2 GB e isso quebrou. Eu poderia voltar para uma versão antiga e importar os formulários e apenas perdi um dia de trabalho.


1

Encontrei esta ferramenta no SourceForge: http://sourceforge.net/projects/avc/

Eu não o usei, mas pode ser um começo para você. Pode haver outras ferramentas de terceiros integradas ao VSS ou SVN que fazem o que você precisa.

Pessoalmente, apenas mantenho um arquivo de texto simples à mão para manter um registro de alterações. Quando confirmo o MDB binário, uso as entradas no log de alterações como meu comentário de confirmação.


Tem um link para fazer o download? Eu sou cego? Eu não consigo encontrá-lo.
BIBD 09/10/08


1

Para completar...

Sempre há "Ferramentas do Visual Studio [YEAR] para o Microsoft Office System" ( http://msdn.microsoft.com/en-us/vs2005/aa718673.aspx ), mas isso parece exigir o VSS. Para mim, o VSS (auto-corrompimento) é pior do que os meus 347 pontos de salvamento no meu compartilhamento de rede com backup superior.




1

A resposta de Oliver funciona muito bem. Encontre minha versão estendida abaixo que adiciona suporte para consultas do Access.

( consulte a resposta de Oliver para obter mais informações / uso)

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

Tentei ajudar a contribuir com sua resposta adicionando uma opção de exportação para consultas no banco de dados de acesso. (Com ampla ajuda de outras respostas do 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

Não consigo trabalhar com isso de volta no recurso 'compor', mas não é isso que eu preciso fazer agora.

Nota: Também adicionei ".txt" a cada um dos nomes de arquivo exportados em decompose.vbs para que o controle de origem me mostrasse imediatamente as diferenças de arquivo.

Espero que ajude!



0

Esta entrada descreve uma abordagem totalmente diferente das outras entradas e pode não ser o que você está procurando. Portanto, não ficarei ofendido se você ignorar isso. Mas pelo menos é alimento para reflexão.

Em alguns ambientes profissionais de desenvolvimento de software comercial, o gerenciamento de configuração (CM) das entregas de software normalmente não é feito dentro próprio aplicativo ou no próprio projeto de software. O CM é imposto aos produtos finais a serem entregues, salvando o software em uma pasta especial do CM, onde o arquivo e sua pasta são marcados com a identificação da versão. Por exemplo, o Clearcase permite que o gerenciador de dados "faça check-in" de um arquivo de software, atribua a ele uma "ramificação", atribua a ele uma "bolha" e aplique "rótulos". Quando você deseja ver e baixar um arquivo, é necessário configurar sua "config spec" para apontar para a versão desejada e, em seguida, colocar o CD na pasta e pronto.

Apenas uma ideia.


0

Para quem ficou com o Access 97, não consegui que as outras respostas funcionassem. Usando uma combinação das excelentes respostas de Oliver e DaveParillo e fazendo algumas modificações, consegui que os scripts funcionassem com nossos bancos de dados do Access 97. Também é um pouco mais amigável, pois pergunta qual pasta colocar os arquivos.

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 para importar arquivos para o banco de dados, você deve recriá-lo do zero ou deseja modificar os arquivos fora do Access por algum 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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.