Як ви користуєтесь керуванням версіями при розробці Access?


163

Я займаюся оновленням рішення Access. Він має велику кількість VBA, ряд запитів, невелику кількість таблиць та кілька форм для введення даних та створення звітів. Це ідеальний кандидат для доступу.

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

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


1
Перехресне посилання цього рішення на відповідне питання експорту схеми доступу db.
Ерік Г

1
Access підтримує інтерфейс SCC, тому будь-яке управління версіями, сумісне з цим інтерфейсом, готове до доступу. Відмова: Я працюю на plasticscm.com, і у нас є кілька клієнтів, які використовують це з Access.
пабло

8
Спробуйте цей модуль vba github.com/timabell/msaccess-vcs-integration
Tim Abell

Відповіді:


180

Ми написали свій власний сценарій у 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

Якщо вам потрібна команда, яку можна натиснути, замість того, щоб використовувати командний рядок, створіть файл під назвою "decompose.cmd" з

cscript decompose.vbs youraccessapplication.adp

За замовчуванням всі експортовані файли переходять у підпапку "Сценарії" вашої програми Access. Файл .adp / mdb також копіюється в це місце (із суфіксом "заглушка") та позбавляється всіх експортованих модулів, що робить його дійсно невеликим.

Ви ПОВИННЕ перевірити цю заглушку з вихідними файлами, оскільки більшість параметрів доступу та користувацькі панелі меню неможливо експортувати іншим способом. Просто не забудьте внести зміни до цього файлу лише в тому випадку, якщо ви дійсно змінили якесь налаштування чи меню.

Примітка. Якщо у вашій програмі визначено якийсь Autoexec-Makros, можливо, вам доведеться утримувати клавішу Shift, коли ви викликаєте розкласти, щоб запобігти виконанню та перешкоді експорту!

Звичайно, існує також зворотний скрипт для створення програми з "Джерела" -Директорія:

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 повинен бути нечутливим до регістру. Доступ робить це, навіть якщо елементи керування у різних формах! Проблема стає більшою, якщо у вас навіть є кілька елементів одного і того ж імені в різних випадках у різних формах.
Олівер

3
Єдине рішення - знайти кожну змінну / контроль-ім'я та змінити правопис на загальну форму. Після експорту та внесення змін зміни назви повинні бути стабільними. Префіксація імен керування до їх типів значною мірою забезпечує шляхом узгодження імен, щоб імена не стикалися зі змінними. (наприклад, txtTitle для текстового поля, що містить поле заголовка, або cmbUsers для комбінованої скриньки тощо)
Олівер

Забув додати, що для отримання цієї роботи з mdb мені довелося змінити OpenAccessProject на OpenCurrentDatabase .
DaveParillo

19

Здається, це щось досить доступне в Access:

Це посилання з msdn пояснює, як встановити надбудову управління джерелом для Microsoft Access. Ця програма постачається як безкоштовне завантаження як частина розширень для розробників Access для Access 2007 та як окрема безкоштовна надбудова для Access 2003.

Я радий, що ви задали це запитання, і я зайняв час, щоб розглянути його, як і я хотів би цієї здатності. Посилання вгорі містить більше інформації про це та посилання на додатки.

Оновлення:
я встановив надбудову для Access 2003. Він буде працювати лише з VSS, але він дозволяє мені розміщувати в сховищі об’єкти Access (форми, запити, таблиці, модулі, ect). Коли ви переходите до редагування будь-якого елемента в репо, вас просять перевірити, але цього не потрібно. Далі я хочу перевірити, як він обробляє відкриття та зміну в системах без надбудови. Я не прихильник VSS, але мені дуже подобається думка про збереження об'єктів доступу в репо.

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

Я виявив, що запуск бази даних "компактний і ремонт" підкаже, якщо ви хочете видалити базу даних з управління джерелами. Я вибрав "так" і зміг редагувати базу даних без надбудови. У статті за посиланням вище наведено вказівки щодо налаштування Access 2003 та 2007 для використання Team Team. Якщо ви можете знайти постачальника MSSCCI для SVN, є хороший шанс, що ви зможете це зробити.


Зауважте, що у нас було досить багато проблем з тим, що не вдалося перевірити ADP від ​​VSS, якщо його редагувало більше однієї людини. Ми врешті-решт мали мати для цього окрему резервну копію!
Simon Simon

Я грав з таким підходом (використовуючи Vault, оскільки я не знаю жодних безкоштовних MSSCCI-провайдерів для SVN ... TortoiseSVNSCC не підтримується і не працює для мене, а інші два-три варіанти є комерційними). Це працює, але це змушує вас використовувати архаїчний ексклюзивно-блокуючий підхід до управління джерелами, і саме тому я планую відмовитися від нього та використовувати рішення @ Олівера.
Тодд Оуен

14

Розробка композиції / розкладання, розміщена Олівером, чудова, але у неї є деякі проблеми:

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

Я планував це виправити самостійно, але виявив, що вже є хороше рішення: timabell / msaccess-vcs-інтеграція на GitHub. Я перевірив msaccess-vcs-інтеграцію, і вона чудово працює.

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

Мінус використання msaccess-vcs-інтеграції порівняно з розкладом рішення Оліверса:

  • Це значно повільніше. Я впевнений, що проблему зі швидкістю можна виправити, але мені не потрібно експортувати свій проект у текст, який часто ...
  • Він не створює проект доступу до заглушки з видаленими експортованими матеріалами. Це також можна виправити (прийнявши код із розкладеного сценарію), але знову ж таки - не так важливо.

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


Схоже, вилка ArminBra зараз попереду (зрозуміло, якщо дивитися на мережевий графік ). Matonb не відповів на єдиний запит на притягнення, тому, мабуть, вони поки що відмовилися від нього.
Тім Абелл

1
А тепер є також мій fork 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

1
+1 для включення запитів. Тепер просто потрібно включити схеми таблиці.
Марк Стобер

Затверджена відповідь не працює для Access 97, але ця відповідь допомогла мені змінити її для власного використання. Дякуємо, що опублікували це!
CTristan

2
Я наполегливо рекомендую поставити збереження запитів перед збереженням форм, щоб згодом змінити порядок видалення. Я мав деякі проблеми з DeleteObject в останньому для кожного оператора, коли я намагався видалити запити, які вже були видалені автоматично, коли їх відповідні форми були видалені раніше. Крім того, якщо у вас під час запуску відкриваються форми, і ви не хочете утримувати F11 (або деактивувати його), просто вставте oApp.DoCmd.Close acForm, "formName" після запуску через cnt.Documents
Anton Kaiser

@Cunso Будь ласка, можете опублікувати свій код, сумісний із Access 97. Тому мені не потрібно його переробляти.
Лоренц Мейєр

як я цим користуюся? Зателефонувати йому з підрозділу?
kevinykuo

11

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

  1. Модулі: експортуються у вигляді файлів txt, а потім порівнюються з "інструментом порівняння файлів" (безкоштовна програма)
  2. Форми: експортуються за допомогою команди недокументації application.saveAsText. Потім можна побачити відмінності між двома різними версіями ("інструмент порівняння файлів" ще раз).
  3. Макроси: у нас немає жодного макросу для порівняння, оскільки у нас є лише макрос "autoexec" з одним рядком, який запускає основну процедуру VBA
  4. Запити: це лише текстові рядки, що зберігаються в таблиці: див. Далі
  5. таблиці: ми написали власний порівняльник таблиць, перелічивши відмінності в записах І структурі таблиць.

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

Це може здатися дивним, але це працює.


8
Раді бачити цей інструмент з відкритими джерелами!
Тодд Оуен

Чи буде гарною ідеєю завантажувати ці експортовані текстові файли на GitHub?
Сантош

9

На основі ідей цієї публікації та подібних записів у деяких блогах я написав програму, яка працює з форматами mdb та adp. Він імпортує / експортує всі об'єкти бази даних (включаючи таблиці, посилання, відносини та властивості бази даних) до звичайних текстових файлів. З цими файлами ви можете працювати з будь-яким контролем версії джерела. Наступна версія дозволить імпортувати звичайні текстові файли до бази даних. Буде також інструмент командного рядка

Ви можете завантажити програму або вихідний код з: http://accesssvn.codeplex.com/

з повагою


Ми використовуємо це вже майже два роки, і це чудово. Дякую!
mcfea

5

Відродження старої нитки, але це добре. Я реалізував два сценарії (compose.vbs / decompose.vbs) для власного проекту і зіткнувся з проблемою зі старими .mdb файлами:

Він зупиняється, коли переходить до форми, що включає код:

NoSaveCTIWhenDisabled =1

Access каже, що у нього є проблеми, і ось це кінець історії. Я провів декілька тестів і пограв, намагаючись обійти цю проблему, і знайшов цю тему з вирішенням наприкінці:

Неможливо створити базу даних

В основному (у випадку, якщо нитка загине), ви приймаєте .mdb і виконуєте "Зберегти як" у новому форматі .accdb. Тоді джерело збереже або складе / розкладе матеріал. Я також повинен був пограти протягом 10 хвилин, щоб отримати правильний синтаксис командного рядка для (de) складених сценаріїв, щоб правильно працювати, ось ось і ця інформація:

Щоб скласти композицію (скажімо, ваш матеріал розташований у 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. Після перетворення сценарії працюють просто чудово!


Чи можете ви відредагувати це так, щоб включити свої версії Access, де ви зіткнулися з цією проблемою?
Натан Девітт

Немає проблем, ти все ще займаєшся розробкою доступу Натане? Якщо так, будь-який успіх інтегруючи його з контролем версій?
JKK

Я вже не займаюся розробкою доступу. У мене був один проект, який я використовував це на зворотному шляху, коли я задавав питання, і ніколи нічого з цим не робив.
Натан Де Вітт

Класно, я думаю, що більшість підприємств використовують якийсь виділений сервер SQL. У ситуації, в якій я зараз перебуваю, є суміш MS SQL Server, Oracle та купа баз даних Access, які перетягують дані з серверів на локальні таблиці та експортують у excel. Це досить складна суміш. Я думаю, я розпочну нове запитання щодо деяких пропозицій щодо створення нового проекту, про який я буду найближчим часом, подивіться, що люди можуть запропонувати зменшити складність
JKK

4

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

Я змінив пару сценаріїв Олівера, щоб вони експортували / імпортували відносини, таблиці та запити на додаток до модулів, класів, форм та макросів. Все зберігається у файлах простого тексту, тому немає файлу бази даних, який би зберігався разом із текстовими файлами в контролі версій.

Експорт у текстові файли (decompose.vbs)

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

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

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

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

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

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


exportModulesTxt ACCDBFilename, sExportpath

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    oApplication.CloseCurrentDatabase
    oApplication.Quit

End Function

Ви можете виконати цей скрипт, зателефонувавши cscript decompose.vbs <path to file to decompose> <folder to store text files>. Якщо ви опустите другий параметр, він створить папку "Джерело", де знаходиться база даних. Зверніть увагу, що папка призначення буде стерта, якщо вона вже існує.

Включіть дані в експортовані таблиці

Замініть рядок 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>. Якщо ви опустите другий параметр, він перегляне папку "Джерело", де повинна бути створена база даних.

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

Замініть рядок 14: const acStructureOnly = 0на const acStructureOnly = 1. Це буде працювати лише в тому випадку, якщо ви включили дані в експортовану таблицю.

Речі, які не висвітлюються

  1. Я протестував це лише з файлами .accdb, тому з будь-чим іншим можуть бути помилки.
  2. Налаштування не експортуються, я б рекомендував створити Макрос, який застосує налаштування на початку бази даних.
  3. Деякі невідомі запити іноді експортуються, яким передує '~'. Я не знаю, чи потрібні вони.
  4. Імена об'єктів MSAccess можуть містити символи, недійсні для імен файлів, - сценарій не вдасться при спробі їх запису. Ви можете нормалізувати всі назви файлів , але потім не зможете їх імпортувати назад.

Одним із інших моїх ресурсів під час роботи над цим сценарієм була ця відповідь , яка допомогла мені зрозуміти, як експортувати відносини.


Це, здається, працює, але не розуміє пов'язаних таблиць
лорд Дарт Вейдер,

2

Існує gotcha - VSS 6.0 може приймати MDB лише за допомогою надбудови під певною кількістю об'єктів, що включає всі локальні таблиці, запити, модулі та форми. Не знаю точну межу об'єкта.

Щоб створити наш 10-річний додаток prod, який є величезним, ми змушені поєднувати 3 або 4 окремих MDB з SS в один MDB, що ускладнює автоматизовані побудови до того, що ми не витрачаємо час на це.

Думаю, я спробую описати вище сценарій, щоб перевести цей MDb у SVN та спростити складання для всіх.


2

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

Цікаво те, що SaveAsAXL є новим у 2010 році та має такий же підпис, як SaveAsText, хоча, здається, він працюватиме лише з веб-базами даних, для яких потрібен SharePoint Server 2010.


SaveAsText також не відображається в A2003, якщо ви не ввімкнули Показ прихованих членів у браузері об’єктів. Хороша інформація про SaveAsAXL.
David-W-Fenton

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


1

Для повноти ...

Завжди є "Інструменти Visual Studio [YEAR] для системи Microsoft Office" ( http://msdn.microsoft.com/en-us/vs2005/aa718673.aspx ), але, схоже, потрібна VSS. Для мене VSS (автоматичне пошкодження) гірше, ніж мої 347 ощадних заощаджень на моїй частці резервної копії мережі uber.


1

Я використовую надбудову Access 2003: Контроль вихідного коду . Це чудово працює. Одна проблема - це недійсні символи типу ":".

Я заїжджаю та виїжджаю. Внутрішні надбудови роблять те саме, що і код вище, але з більшою підтримкою інструментів. Я можу побачити, чи перевіряється об'єкт та оновлювати його.



1

Відповідь Олівера чудово працює. Нижче ви знайдете мою розширену версію, яка додає підтримку для запитів доступу.

( див. відповідь від Oliver для отримання додаткової інформації / використання)

decompose.vbs:

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

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

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

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

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

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


exportModulesTxt sADPFilename, sExportpath

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

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

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

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

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

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

    oApplication.Visible = false

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

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

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

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

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


End Function

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

compose.vbs:

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

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

Option Explicit

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

Const acCmdCompileAndSaveAllModules = &H7E

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

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

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


importModulesTxt sADPFilename, sPath

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

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

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

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

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

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

    fso.CopyFile sStubADPFilename, sADPFilename

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

    Dim folder
    Set folder = fso.GetFolder(sImportpath)

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

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

    next

    oApplication.RunCommand acCmdCompileAndSaveAllModules
    oApplication.Quit
End Function

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

0

Я намагався допомогти йому відповісти, додавши опцію експорту для запитів у базі даних доступу. (За достатньою допомогою інших відповідей ТА )

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" до кожного експортованого імені файлу в decompose.vbs, щоб джерело управління негайно показало мені, що файл відрізняється.

Сподіваюся, що це допомагає!



0

Ця запис описує абсолютно інший підхід від інших записів, і може бути не тим, що ви шукаєте. Тож я не буду ображатися, якщо ви проігноруєте це. Але принаймні це їжа для роздумів.

У деяких професійних середовищах розробки комерційного програмного забезпечення управління конфігурацією (CM) результатів програмного забезпечення, як правило, не здійснюється в межах самого програмного забезпечення або самого проекту програмного забезпечення. CM накладається на остаточну продукцію, зберігаючи програмне забезпечення у спеціальній папці CM, де і файл, і його папка позначені ідентифікацією версії. Наприклад, Clearcase дозволяє менеджеру даних "перевірити" програмний файл, призначити йому "гілку", призначити йому "бульбашку" та застосувати "мітки". Коли ви хочете побачити і завантажити файл, вам доведеться налаштувати свою "специфікацію config", щоб вказати на потрібну версію, потім введіть CD у папку і там вона є.

Просто ідея.


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.