Как вы используете контроль версий при разработке Access? - PullRequest
154 голосов
/ 09 октября 2008

Я занимаюсь обновлением решения Access. Он имеет хорошее количество VBA, несколько запросов, небольшое количество таблиц и несколько форм для ввода данных и генерации отчетов. Это идеальный кандидат на доступ.

Я хочу внести изменения в дизайн таблицы, VBA, запросы и формы. Как я могу отслеживать свои изменения с помощью контроля версий? (мы используем Subversion, но это подходит для любого варианта) Я могу вставить всю mdb в Subversion, но это будет хранение двоичного файла, и я не смогу сказать, что я только что изменил одну строку кода VBA. 1003 *

Я думал о копировании кода VBA в отдельные файлы и сохранении их, но я мог видеть, что они быстро не синхронизируются с тем, что находится в базе данных.

Ответы [ 20 ]

172 голосов
/ 17 октября 2008

Мы написали наш собственный скрипт на VBScript, который использует недокументированный Application.SaveAsText () в Access для экспорта всех модулей кода, форм, макросов и отчетов. Вот оно, оно должно дать вам несколько советов. (Осторожно: некоторые сообщения на немецком языке, но вы можете легко это изменить.)

EDIT: Чтобы суммировать различные комментарии ниже: Наш проект предполагает .adp-файл. Чтобы получить эту работу с .mdb / .accdb, вы должны изменить OpenAccessProject () на OpenCurrentDatabase () . (Обновлен для использования OpenAccessProject(), если он видит расширение .adp, иначе используйте 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

Если вам нужна интерактивная команда, вместо использования командной строки, создайте файл с именем "degpose.cmd" с

cscript decompose.vbs youraccessapplication.adp

По умолчанию все экспортируемые файлы помещаются в подпапку «Сценарии» вашего Access-приложения. Файл .adp / mdb также копируется в это место (с суффиксом «заглушка») и удаляется из всех экспортируемых модулей, что делает его действительно маленьким.

Вы ДОЛЖНЫ проверить эту заглушку с исходными файлами, поскольку большинство настроек доступа и пользовательских строк меню не могут быть экспортированы другим способом. Обязательно внесите изменения только в этот файл, если вы действительно изменили какой-либо параметр или меню.

Примечание. Если в вашем Приложении определен Autoexec-Makros, возможно, вам придется удерживать клавишу Shift при вызове декомпозиции, чтобы предотвратить выполнение и вмешательство в экспорт!

Конечно, есть и обратный скрипт для сборки приложения из "Source" -Directory:

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

Опять же, это идет с компаньоном "compose.cmd", содержащим:

cscript compose.vbs youraccessapplication.adp

Он попросит вас подтвердить перезапись текущего приложения и сначала создаст резервную копию, если вы это сделаете. Затем он собирает все исходные файлы в Source-Directory и повторно вставляет их в заглушку.

Веселись!

19 голосов
/ 09 октября 2008

Похоже, что-то вполне доступно в Access:

Эта ссылка от msdn объясняет, как установить надстройку контроля версий для Microsoft Access. Он поставляется бесплатно как часть расширений Access Developer для Access 2007 и как отдельная бесплатная надстройка для Access 2003.

Я рад, что вы задали этот вопрос, и я нашел время, чтобы найти его, так как мне бы тоже понравилась эта способность. Ссылка выше содержит больше информации об этом и ссылки на надстройки.

Обновление:
Я установил надстройку для Access 2003. Она будет работать только с VSS, но она позволяет мне помещать объекты Access (формы, запросы, таблицы, модули и т. Д.) В репозиторий. Когда вы идете отредактировать любой предмет в репо, вас просят проверить его, но это не обязательно. Далее я собираюсь проверить, как он обрабатывает открытие и изменение в системах без надстройки. Я не фанат VSS, но мне действительно нравится мысль о хранении объектов доступа в репозитории.

Update2:
Машины без надстройки не могут вносить какие-либо изменения в структуру базы данных (добавлять поля таблицы, параметры запроса и т. Д.). Сначала я подумал, что это может быть проблемой, если кому-то нужно, поскольку не было никакого очевидного способа удалить базу данных Access из системы контроля версий, если в Access не было загружено дополнение.

Идентификатор обнаружил, что при запуске базы данных «Сжатие и восстановление» вам будет предложено удалить базу данных из системы контроля версий. Я выбрал «да» и смог редактировать базу данных без надстройки. В статье ссылка выше также приведены инструкции по настройке Access 2003 и 2007 для использования Team System. Если вы можете найти поставщика MSSCCI для SVN, есть большая вероятность, что вы сможете заставить его работать.

14 голосов
/ 04 декабря 2009

Оливер отвечает камнями, но ссылка CurrentProject не работает для меня. Я закончил тем, что вырвал кишки из середины его экспорта и заменил его этим, основываясь на подобном решении Арвин Мейер . Имеет преимущество экспорта запросов, если вы используете mdb вместо 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
12 голосов
/ 08 ноября 2014

Решение по компоновке / разложению, опубликованное Оливером, великолепно, но у него есть некоторые проблемы:

  • Файлы кодируются как UCS-2 (UTF-16), что может привести к тому, что системы / инструменты управления версиями будут считать файлы двоичными.
  • В файлах много различий, которые часто меняются - контрольные суммы, информация о принтере и многое другое. Это серьезная проблема, если вам нужны чистые различия или вам нужно сотрудничать в проекте.

Я планировал исправить это сам, но обнаружил, что уже есть хорошее решение: timabell / msaccess-vcs-интеграции на GitHub. Я проверил msaccess-vcs-интеграции, и он отлично работает.

Обновлено 3 марта 2015 года : проект изначально поддерживался / принадлежал bkidwell на Github, но был переведен в timabell - ссылка выше на проект обновлена ​​соответствующим образом. Есть несколько форков из оригинального проекта от bkidwell, например от ArminBra и от matonb , которые AFAICT не следует использовать.

Недостаток использования msaccess-vcs-интеграции по сравнению с разложенным решением Оливера:

  • Это значительно медленнее. Я уверен, что проблема со скоростью может быть исправлена, но мне не нужно экспортировать мой проект в текст, который часто ...
  • Он не создает тупиковый проект Access с удаленным экспортированным материалом. Это также можно исправить (приняв код из скрипта декомпозиции), но опять же - не так важно.

В любом случае, моя четкая рекомендация - msaccess-vcs-интеграции. Это решило все проблемы с использованием Git для экспортированных файлов.

11 голосов
/ 10 октября 2008

Мы разработали наш собственный внутренний инструмент, где:

  1. Модули: экспортируются как текстовые файлы, а затем сравниваются с «инструментом сравнения файлов» (бесплатное программное обеспечение)
  2. Формы: экспортируются с помощью недокументированной команды application.saveAsText. Затем можно увидеть различия между двумя разными версиями («инструмент сравнения файлов»).
  3. Макросы: у нас нет макроса для сравнения, так как у нас есть только макрос «autoexec» с одной строкой, запускающей основную процедуру VBA
  4. Запросы: это просто текстовые строки, хранящиеся в таблице: см. Ниже
  5. таблиц: мы написали наш собственный компаратор таблиц, перечисляющий различия в записях и структуре таблиц.

Вся система достаточно умна, чтобы позволить нам создавать версии нашего приложения Access во время выполнения, автоматически генерируемые из файлов txt (модули и формы, воссозданные с помощью команды undocument application.loadFromText) и файлов mdb (таблицы).

Звучит странно, но работает.

9 голосов
/ 11 июня 2011

Исходя из идей этого поста и похожих записей в некоторых блогах, я написал приложение, которое работает с форматами файлов mdb и adp Он импортирует / экспортирует все объекты базы данных (включая таблицы, ссылки, отношения и свойства базы данных) в простые текстовые файлы. С этими файлами вы можете работать с любым источником контроля версий. Следующая версия позволит импортировать обратно текстовые файлы в базу данных. Там будет также инструмент командной строки

Вы можете скачать приложение или исходный код с: http://accesssvn.codeplex.com/

привет

5 голосов
/ 16 марта 2012

Воскрешение старого потока, но это хороший. Я реализовал два скрипта (compose.vbs / degpose.vbs) для моего собственного проекта и столкнулся с проблемой со старыми файлами .mdb:

Он останавливается, когда попадает в форму, содержащую код:

NoSaveCTIWhenDisabled =1

Access говорит, что у него есть проблема, и это конец истории. Я выполнил несколько тестов и попытался обойти эту проблему и нашел эту тему с обходом в конце:

Невозможно создать базу данных

В основном (в случае, если поток не работает), вы берете .mdb и делаете «Сохранить как» в новом формате .accdb. Тогда исходный код будет безопасным или составить / разложить материал. Мне также пришлось потратить 10 минут, чтобы получить правильный синтаксис командной строки, чтобы скрипты (de) compose работали правильно, поэтому вот эта информация:

Чтобы составить (скажем, ваш материал находится в C: \ SControl (создайте подпапку с именем Source для хранения извлеченных файлов):

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

Вот и все!

Версии Access, в которых я сталкивался с вышеуказанной проблемой, включают базы данных Access. 2000-2003 гг. , После конвертации скрипты работают просто отлично!

3 голосов
/ 19 февраля 2016

Решение только для текстовых файлов (включая запросы, таблицы и отношения)

Я изменил пару сценариев Оливера, чтобы они экспортировали / импортировали отношения, таблицы и запросы в дополнение к модулям, классам, формам и макросам. Все сохраняется в виде текстовых файлов, поэтому файл базы данных не создан для хранения вместе с текстовыми файлами в системе управления версиями.

Экспорт в текстовые файлы (degpose.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

Вы можете выполнить этот скрипт, вызвав cscript decompose.vbs <path to file to decompose> <folder to store text files>. Если вы пропустите второй параметр, он создаст папку «Source», в которой находится база данных. Обратите внимание, что папка назначения будет удалена, если она уже существует.

Включить данные в экспортируемые таблицы

Заменить строку 93: oApplication.ExportXML acExportTable, myObj.Name, , sExportpath & "\" & myObj.Name & ".table.txt"

со строкой oApplication.ExportXML acExportTable, myObj.Name, sExportpath & "\" & myObj.Name & ".table.txt"

Импорт в Создание файла базы данных (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

Вы можете выполнить этот скрипт, вызвав cscript compose.vbs <path to file which should be created> <folder with text files>. Если вы пропустите второй параметр, он заглянет в папку «Source», в которой должна быть создана база данных.

Импорт данных из текстового файла

Заменить строку 14: const acStructureOnly = 0 на const acStructureOnly = 1. Это будет работать, только если вы включили данные в экспортированную таблицу.

Вещи, которые не охвачены

  1. Я проверял это только с файлами .accdb, так что с чем-то еще могут быть некоторые ошибки.
  2. Настройки не экспортируются, я бы порекомендовал создать макрос, который будет применять настройки при запуске базы данных.
  3. Некоторые неизвестные запросы иногда экспортируются, которым предшествует '~'. Я не знаю, нужны ли они.

Одним из моих других ресурсов при работе над этим сценарием был этот ответ , который помог мне понять, как экспортировать отношения.

2 голосов
/ 17 августа 2010

У нас была такая же проблема некоторое время назад.

Нашей первой попыткой был сторонний инструмент, который предлагает прокси API-интерфейса SourceSafe для Subversion для использования с MS Access и VB 6. Инструмент можно найти здесь .

Поскольку мы не были удовлетворены этим инструментом, мы переключились на Visual SourceSafe и плагин VSS Acces.

2 голосов
/ 15 августа 2010

Для тех, кто использует Access 2010, SaveAsText не является видимым методом в Intellisense, но, по-видимому, является допустимым методом, так как сценарий Арвина Майера , упомянутый ранее , работал нормально для меня.

Интересно, что SaveAsAXL является новым для 2010 года и имеет ту же подпись, что и SaveAsText, хотя, похоже, он будет работать только с веб-базами данных, для которых требуется SharePoint Server 2010.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...