Как вы используете контроль версий при разработке Access?

163

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

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

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

Натан Девитт
источник
1
Перекрестное размещение этого решения к связанному вопросу экспорта схемы БД Access.
Eric G
1
Access поддерживает интерфейс SCC, поэтому любой контроль версий, совместимый с этим интерфейсом, готов к Access. Отказ от ответственности: я работаю на plasticscm.com, и у нас есть несколько клиентов, использующих его с Access.
Пабло
8
Попробуйте этот модуль VBA github.com/timabell/msaccess-vcs-integration
Тим Абелл

Ответы:

180

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

РЕДАКТИРОВАТЬ: резюмировать различные комментарии ниже: Наш проект предполагает .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 и повторно вставляет их в заглушку.

Радоваться, веселиться!

Оливер
источник
1
Мне нравится этот код Я обнаружил, что oApplication.OpenAccessProject не будет работать с файлом .accdb (или, может быть, это Access 2007), и вместо этого мне пришлось использовать oApplication.OpenCurrentDatabase.
hughdbrown
1
Я делаю нечто подобное (SaveAsText, но в VBA и с файлом MDB вместо ADP), но у меня осталась одна большая проблема: после каждого экспорта Subversion распознает около 100 файлов как измененных (даже если я изменил только один или два ). когда я смотрю на изменения, я вижу, что некоторые имена переменных или имена элементов управления изменили свое прописное / строчное написание. Например: каждый файл, который когда-то содержал «OrderNumber», теперь содержит «Ordernumber» в экспорте и поэтому помечен как «измененный» (по крайней мере SVN, еще не пробовал другой SCM). Есть идеи, как мне этого избежать? Большое спасибо!
Кристиан Шпехт
3
Да, это постоянное раздражение и в нашем проекте. Насколько мы определили, проблема в том, что переменные в вашем проекте имеют те же имена, что и элементы управления, только в разных случаях (вверх / вниз). Теперь, в зависимости от порядка составления модулей, кажется, что Access принимает одну орфографию и «корригирует» все остальные, поскольку предполагается, что VBA нечувствителен к регистру. Access делает это, хотя элементы управления находятся в разных формах! Проблема становится больше, если у вас есть несколько элементов управления с одним и тем же именем в разных случаях в разных формах.
Оливер
3
Единственное решение - выследить каждую переменную / имя элемента управления и изменить орфографию до обычной формы. После экспорта и фиксации изменений имена должны быть стабильными. Префикс имен элементов управления к их типам в значительной степени гарантирует соглашение об именах, что имена не конфликтуют с переменными. (например, txtTitle для текстового поля, содержащего поле Title или cmbUsers для комбинированного списка и т. д.)
Оливер
Забыл добавить, что для работы с mdb мне пришлось изменить OpenAccessProject на OpenCurrentDatabase .
DaveParillo
19

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

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

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

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

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

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

Brettski
источник
Обратите внимание, что у нас было довольно много проблем с невозможностью проверить ADP из VSS, если его редактировали несколько человек. Для этого у нас была отдельная резервная копия!
Симон
Я играл с этим подходом (используя Vault, поскольку я не знаю ни одного бесплатного MSSCCI-провайдера для SVN ... TortoiseSVNSCC не поддерживается и не работает для меня, а два или три варианта являются коммерческими). Это работает, но заставляет вас использовать архаичный подход с эксклюзивной блокировкой к управлению исходным кодом, и по этой причине я планирую отказаться от него и использовать решение @ Oliver.
Тодд Оуэн
14

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

  • Файлы кодируются как 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 для экспортированных файлов.

hansfn
источник
Похоже, форк ArminBra сейчас впереди ( по взгляду на график сети ). Matonb не ответил на единственный запрос на удаление, так что я думаю, что они, по крайней мере, пока отказались от него.
Тим Абелл
1
А теперь еще и мой форк github.com/timabell/msaccess-vcs-integration - исправляет поломку экспорта таблицы составных ключей. Два других выглядят немного заброшенными, поэтому я рад получать отчеты об ошибках в запросах на включение и т.д.
Тим Абелл
Я бы вежливо предложил отредактировать этот ответ, чтобы он указывал на мой ответвление, поскольку сейчас это наиболее активно поддерживаемая версия.
Тим Эбелл
2
@TimAbell: я обновил свой ответ, чтобы отразить тот факт, что проект был передан вам. PS! Я надеюсь, что мы сможем получить некоторые голоса, так как считаю, что это лучшее решение.
Hansfn
2
хорошо, навигация по веткам проекта github, кажется, самая последняя проблема, которую мы сами для себя придумали :-)
Тим Абелл
14

Оливерс отвечает на вопросы, но 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
DaveParillo
источник
1
+1 за включение запросов. Теперь просто нужно включить схемы таблиц.
Марк Стобер
Утвержденный ответ не работает для Access 97, но этот ответ помог мне изменить его для своих собственных нужд. Спасибо за публикацию!
CTristan
2
Я настоятельно рекомендую сохранить сохранение запроса перед сохранением форм, чтобы впоследствии изменить порядок удаления. У меня были некоторые проблемы с DeleteObject в последнем операторе For Each, когда я пытался удалить запросы, которые уже были удалены автоматически, когда их соответствующие формы были удалены ранее. Кроме того, если у вас есть некоторые формы, открывающиеся при запуске, и вы не хотите удерживать F11 (или отключили его), просто вставьте oApp.DoCmd.Close acForm, "formName" после запуска через cnt.Documents
Anton Kaiser
@Cunso Пожалуйста, не могли бы вы опубликовать свой код, совместимый с Access 97. Поэтому мне не нужно его перерабатывать.
Лоренц Мейер
как мне это использовать? Называть это из сабвуфера?
kevinykuo
11

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

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

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

Это может звучать странно, но это работает.

Филипп Грондиер
источник
8
Хотелось бы увидеть этот инструмент с открытым исходным кодом!
Тодд Оуэн
Будет ли хорошей идеей загрузить эти экспортированные текстовые файлы на GitHub?
Сантош
9

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

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

С уважением

mnieto
источник
Мы использовали это в течение почти двух лет, и это здорово. Спасибо!
mcfea
5

Воскрешение старого потока, но это хороший. Я реализовал два сценария (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 ".mdb" и исправляют проблему, сохраняя их в форматах ".accdb" 2007-2010 до запуска сценариев составления / разложения. После конвертации скрипты работают просто отлично!

JKK
источник
Можете ли вы изменить это, чтобы включить ваши версии Access, где вы столкнулись с этой проблемой?
Натан Девитт
Нет проблем, ты все еще занимаешься разработкой доступа, Натан? Если так, то какой-нибудь успех интегрирует его с контролем версий?
JKK
Я больше не занимаюсь разработкой Access. У меня был один проект, который я использовал на обратном пути, когда задавал вопрос, и мне больше никогда не приходилось с ним что-то делать.
Натан Девитт
Круто, я думаю, что большинство компаний используют какой-то выделенный сервер SQL. Ситуация, в которой я сейчас нахожусь, - это смесь MS SQL Server, Oracle и нескольких баз данных Access, которые переносят данные с серверов в локальные таблицы и экспортируют в Excel. Это довольно сложная смесь. Я думаю, что я начну новый вопрос о некоторых предложениях по созданию нового проекта, который скоро будет, посмотрите, что люди могут предложить, чтобы уменьшить сложность
JKK
4

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

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

Экспорт в текстовые файлы (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. Некоторые неизвестные запросы иногда экспортируются, которым предшествует '~'. Я не знаю, если они необходимы.
  4. Имена объектов MSAccess могут содержать символы, которые недопустимы для имен файлов - сценарий завершится ошибкой при попытке их записи. Вы можете нормализовать все имена файлов , но затем вы не сможете импортировать их обратно.

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

Якуб М.
источник
Кажется, это работает, но не понимает связанных таблиц
Лорд Дарт Вейдер,
2

Есть недочёт - VSS 6.0 может принимать MDB только с помощью надстройки под определенным количеством объектов, которое включает все локальные таблицы, запросы, модули и формы. Не знаю точного ограничения объекта.

Чтобы создать наше огромное 10-летнее приложение Prod Floor, мы вынуждены объединить 3 или 4 отдельных MDB из SS в одну MDB, что усложняет автоматизированные сборки до такой степени, что мы не тратим время на это.

Я думаю, что я попробую скрипт выше, чтобы выложить этот MDb в SVN и упростить сборки для всех.

ChuckB
источник
2

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

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

Cory
источник
SaveAsText также не отображается в A2003, если в браузере объектов не включен параметр «Показать скрытых членов». Хорошая информация о SaveAsAXL.
Дэвид-У-Фентон
2

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

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

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

Бенджамин Брауэр
источник
2

Я использую Oasis-Svn http://dev2dev.de/

Я просто могу сказать, что это спасло меня хотя бы один раз. Мой mdb рос больше 2 ГБ, и это сломало его. Я мог бы вернуться к старой версии и импортировать формы и просто потерял день или около того работы.

Фридрих
источник
1

Я нашел этот инструмент на SourceForge: http://sourceforge.net/projects/avc/

Я не использовал его, но это может быть началом для вас. Могут быть и другие сторонние инструменты, которые интегрируются с VSS или SVN и выполняют то, что вам нужно.

Лично я просто держу простой текстовый файл под рукой, чтобы вести журнал изменений. Когда я фиксирую двоичный MDB, я использую записи в журнале изменений в качестве комментария к коммиту.

Патрик Кафф
источник
Есть ссылка на самом деле скачать его? Я слепой? Я не могу найти это.
BIBD
sourceforge.net/project/showfiles.php?group_id=115226 Файловые пакеты не определены. Ура.
Натан Девитт
1

Для полноты ...

Всегда есть «Инструменты Visual Studio [YEAR] для системы Microsoft Office» ( http://msdn.microsoft.com/en-us/vs2005/aa718673.aspx ), но для этого требуется VSS. Для меня VSS (авторазрушение) хуже, чем мои 347 точек сохранения на моем сетевом ресурсе с резервным копированием uber.

BIBD
источник
1

я использую надстройку Access 2003: контроль исходного кода . Работает нормально. Одной из проблем являются недопустимые символы, такие как «:».

Я вхожу и выхожу. Внутренне надстройка делает то же самое, что и код там, но с большей поддержкой инструментов. Я могу видеть, если объект извлечен и обновить объекты.

Лето
источник
1

Вы также можете подключить свой MS Access к Team Foundation Server. Существует также бесплатный экспресс-вариант для до 5 разработчиков. Работает действительно хорошо!

Редактировать: фиксированная ссылка

WolfgangP
источник
1

Ответ от Оливера прекрасно работает. Ниже приведена расширенная версия, в которой добавлена ​​поддержка запросов Access.

( см. ответ от Оливера для получения дополнительной информации / использования)

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

Я попытался внести свой вклад в его ответ, добавив опцию экспорта запросов в базу данных доступа. (С достаточной помощью от других ответов 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

Не смогу вернуть это обратно в функцию «сочинения», но это не то, что мне нужно, чтобы сделать это прямо сейчас.

Примечание. Я также добавил «.txt» к каждому из имен экспортируемых файлов в файле degpose.vbs. чтобы система управления исходным кодом немедленно показывала мне различия в файлах.

Надеюсь, это поможет!


JBickford
источник
0

Эта запись описывает совершенно другой подход, чем другие записи, и может не соответствовать тому, что вы ищете. Так что я не буду обижаться, если вы проигнорируете это. Но, по крайней мере, это пища для размышлений.

В некоторых профессиональных коммерческих средах разработки программного обеспечения управление конфигурацией (CM) результатов поставки программного обеспечения обычно не выполняется в пределах самом программном приложении или самом программном проекте. CM накладывается на конечный продукт, который поставляется, сохраняя программное обеспечение в специальной папке CM, где и файл, и его папка помечены идентификацией версии. Например, Clearcase позволяет менеджеру данных «регистрировать» файл программного обеспечения, назначать ему «ветвь», назначать ему «пузырь» и применять «метки». Если вы хотите просмотреть и загрузить файл, вам необходимо настроить свою «конфигурационную спецификацию» так, чтобы она указывала на нужную версию, затем перейдите в папку cd и там она есть.

Просто идея.

VolleyballAddictSandiego
источник
0

Для тех, кто застрял в Access 97, я не смог заставить другие ответы работать. Используя комбинацию превосходных ответов Оливера и ДэйвПарилло и внеся некоторые изменения, я смог заставить сценарии работать с нашими базами данных Access 97. Это также немного более удобно для пользователя, поскольку спрашивает, в какую папку помещать файлы.

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

А для импорта файлов в базу данных, если вам нужно восстановить базу данных с нуля или по каким-то причинам вы хотите изменить файлы за пределами Access.

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
CTristan
источник