Как автоматически обновлять макет многопользовательской базы?

dkny
Дата: 08.06.2004 10:58:18
В поиск свой вопрос даже и не знаю, как искать, поэтому пойдем, так сказать, нахрапом :)

Суть идеи вот в чем. С моей базой работает 8 человек. На рабочей базе я эксперименты не ставлю, а использую для этого копию с рабочим названием. То, что нормально работает (запросы/формы и т.д.) переносится в рабочую базу с помощью экспорта. Разумеется, экспорт можно сделать только имея монопольный доступ к базе, а вот этого-то и нет. Работают (менеджеры) с базой с самого утра (с 09:00) и бывает что до полуночи, так что незаметно для всех экспорт сделать не получается. Приходится просить всех закрыть базу и вносить изменения.

Как можно это дело улучшить или автоматизировать. Скажем, создав новую базу, содержащую только то, что нужно экспортировать (т.е. временная база) и потом с помощью макроса кидать эти объекты в рабочую базу. Такой вариант возможен и правильный ли он с точки зрения здравого смысла?

Дело в том, что репликация нежелательна по той причине, что в моей рабочей базе очень часто появляются неработающие/глючащие вещи, которые крайне не желательно переносить в базу рабочую.

That's all folks...
Hummer
Дата: 08.06.2004 11:07:41
1. Выложить на сервер клиентскую часть.
2. У всех менеджеров и пользователей ярлык на батник в дир-ии на сервере, который копирует архив с клиентом на локальную машину, разархивирует и запускает.
3. Всё.
Latuk
Дата: 08.06.2004 11:44:31
У меня п2 зашит в программу
и обновление происходит как по кнопочке так и при открытии
после обнаружения новой версии.
Yanis
Дата: 08.06.2004 11:49:41
Из личного опыта: когда-то у меня была подобная проблема, только она еще усугублялась глюками в базе при интенсивном вводе данных всеми юзерами одновременно.
В общем, рецепт Hummer однозначен
lobodava
Дата: 08.06.2004 12:55:06
Можно сохранять номер версии клиентской части в свойстах самой клиентской части, и всякий раз при запуске сверять этот номер у базы на сервере и у локальной базы. Запускать клиентское приложение придется через скрипт с расширением .vbs, либо через другую "Стартовую" базу, прописав запускающую функцию в макрос AutoExec .

Как установить и сверить версии баз можно посмотреть здесь
А вот этим кодом у меня происходит открытие основной клиетской части из "стартовой" базы

Private Const constrApplication As String = """C:\\Program Files\\Microsoft Office\\Office\\MSAccess.exe"""\nPrivate Const constrWorkGroupFile As String = "\\\\Server\\MyDB_WGF.mdw"\nPrivate Const constrOriginMDB As String = "\\\\Server\\MyDB.mdb"\nPrivate Const constrLocalMDB As String = "C:\\MyDB.mdb"\n\nPublic Function StartApplication()\nDim strUserName As String\n\'Dim strUserPassword As String\n\'Dim strCommand As String\nDim RetVal\n\n\'find if local folder exists\'\nIf Len(constrOriginMDB) > 0 Then\n    CheckLocalFolders constrLocalMDB\nEnd If\n\nOn Error Resume Next\n    If Dir(constrLocalMDB, vbNormal) = "" Then \'if file does not exist\'\n        FileCopy constrOriginMDB, constrLocalMDB\n    Else\n        If HasToBeRefreshed Then \'check if there is new version on the server\'\n            FileCopy constrOriginMDB, constrLocalMDB\n        End If\n    End If\n    \n    If Err.Number > 0 And Err.Number <> 70 Then\n        Beep\n        MsgBox Err.Number & vbCrLf & Err.Description\n    End If\nOn Error GoTo 0\n\nstrUserName = GetUserLogOnName\n\nIf Len(constrApplication) > 0 Then\n    strCommand = constrApplication\n\n    If Len(constrLocalMDB) > 0 Then strCommand = strCommand & " " & constrLocalMDB\n    If Len(constrWorkGroupFile) > 0 Then strCommand = strCommand & " /wrkgrp " & constrWorkGroupFile\n    If Len(strUserName) > 0 Then strCommand = strCommand & " /user " & strUserName\n\n    RetVal = Shell(strCommand, 3)\nEnd If\n\nApplication.Quit\nExit Function\n\nErrorLabel:\n    DoCmd.Hourglass False\n    DoCmd.Maximize\n    Beep\n    MsgBox "Something wrong with Database," & vbCrLf & "Ask DB developer to fix it@" & vbCrLf & _\n            Err.Number & "@" & Err.Description & "@", vbCritical\n    \n    Application.Quit\nEnd Function

Вот ещё две функции, которые используются вверху. Первая функция определяет сущестует ли папка на локальном диске где должна лежать клиентская часть, и ,если такой папки нет, то создаёт её. Вторая - определяет имя пользователя в сети - это на случай если это имя совпадает с именем пользователя в базе (что я везде практикую).

Public Function CheckLocalFolders(strFilePath)\nDim strCurrPath As String\nDim strCurrFolder As String\nDim intPos As Integer\n\nIf Left$(strFilePath, 3) <> "C:\\" Then\n    MsgBox "Wrong Path Argument in CheckLocalFolders Function", vbCritical\n    Exit Function\nEnd If\n\nstrCurrPath = "C:\\"\nintPos = 3\n\nDo Until intPos = 0\n    intPos = InStr(intPos + 1, strFilePath, "\\")\n    If intPos > 0 Then\n        strCurrPath = Left$(strFilePath, intPos - 1)\n        If Dir(strCurrPath, vbDirectory) = "" Then\n            MkDir strCurrPath\n        End If\n    End If\nLoop\nEnd Function\n\'*************************************************\'\nPrivate Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" _\n    (ByVal lpBuffer As String, nSize As Long) As Long\n\nPublic Function GetUserLogOnName() As String\nDim strBuffer As String\nDim lngBufferLength As Long\n\nlngBufferLength = 25\nstrBuffer = Space(lngBufferLength)\n\nIf GetUserName(strBuffer, lngBufferLength) > 0 Then\n    strBuffer = Trim$(strBuffer)\n    GetUserLogOnName = Left$(strBuffer, Len(strBuffer) - 1)\nElse\n    GetUserLogOnName = vbNullString\nEnd If\nEnd Function\n

Код, как всегда, на скорую руку. Так что, после сборки обработать напильником :)
dkny
Дата: 09.06.2004 14:29:05
Спасибо Hummer огромное за интересное и простое решение.

Проблема только в том, что моя база не разделена на клиентскую и серверную часть, наверное, вы об этом догадались по характеру вопроса. Формы и данные пока (?) вместе, потому что даже все алгоритмы не до конца разработаны, в связи с тем, что фирме только 5 месяцев. Пока еще не понятно что вообще нам нужно из автоматизации. Отсюда же и развитие базы с частым внесением изменений и проблемами их внедрения.

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

Отдельная просьба к Latuk. Нельзя ли посмотреть на код реализации проверки новых версий? И что значит "новой версии" в данном случае?

lobodava спасибо за код. Сейчас разбираюсь, что из этого мне понадобится. Скорее всего, для начала, остановлюсь на варианте сравнения текущего файла базы и лежащего на сервере по дате создания в *.bat файле.
Идея хранить номер в самой базе хорошая, отсюда несколько вопросов:

1. Что значит эта строка (в коде по ссылке): HasToBeRefreshed = (lngVersionOnServer > lngVersionOnC). И что значит If HasToBeRefresh? Т.е. в процедуре проверки если версия новее, то True, если нет, то False. И эту же конструкцию можно ставить как If HasToBeRefresh, в смысле, если в проверке возвращается True, то If HasToBeRefresh выполняется, если же это False, то идет в Else?
2. Куда вставить код проверки и копирования? (на пальцах)
3. Папка для базы это "рюшечки"? :)) И зачем она, если путь базы "C:\"?
4. А зачем нужна проверка пользователя по сетевому имени? Для того, чтобы запустить главную базу с требуемым именем пользователя, на случай, если он его забыл? :) Смайл, потому что у меня на машинах работают несколько менеджеров (точнее, своих машин нет ни у кого, пользуются свободной), поэтому имя вводят всякий раз самостоятельно. Зы: но это шикарно, конечно :)
Yanis
Дата: 09.06.2004 14:40:52
dkny
то получен сильнейший аргумент для разделения базы (скорости сети хватает для работы со всей базой, но время выполнения операций постепенно увеличивается


Дело не столько во времени, сколько в глюках мдб. А они при неразделенной базе скоро появятся, будь уверен. Вообще ИМХО одну мдб должен держать открытой только один юзер. Да и с интерфейсом работать гораздо проще...
Latuk
Дата: 09.06.2004 14:49:03
>А они при неразделенной базе скоро появятся
Неужели до сих пор кто-то работает с неразделенными(формы,запросы - таблицы) базами ?!
lobodava
Дата: 09.06.2004 15:34:31
Да! Многопользовательскую базу ДЕЛИТЬ НЕМЕДЛЯ - и думать по другому не мочь!!!
Всё написаное далее относится только к клиетской части, т.е. части с запросами, отчётами, формами, макросами и модулями.


dkny
1. Что значит эта строка (в коде по ссылке): HasToBeRefreshed = (lngVersionOnServer > lngVersionOnC). И что значит If HasToBeRefresh? Т.е. в процедуре проверки если версия новее, то True, если нет, то False. И эту же конструкцию можно ставить как If HasToBeRefresh, в смысле, если в проверке возвращается True, то If HasToBeRefresh выполняется, если же это False, то идет в Else?


HasToBeRefreshed - это функция, которая лежит по ссылке
/topic/46825&hl=#323443.
Функция возвращает True если версии на сервере и на компьютере пользователя отличаются, и False, если одинаковы. Причем если в момент запроса база на сервере открыта монопольно, т.е. разработчик копается в ейных нутрях, то функция тоже вернет False и, соответственно, не будет предпринята попытка копирования с сервера... А так всё правильно понимается: HasToBeRefresh возвращает True - выполняется If , возвращает False - выполняется Else

dkny
2. Куда вставить код проверки и копирования? (на пальцах)

Господа офицеры, Молчать!!!
В совершенно новый и отдельный файл аксесной базы. В модуль всталяется код, создаётся макрос с именем AutoExec, в этом макросе выбирается команда RunCode и в свойстах команды указывается имя функции StartApplication().
Эта "Стартовая База" открывается, AutoExec автоматически запускает функцию, функция сравнивает версии, при необходимости копирует новую версию на компьютер пользователя, открывает рабочую базу и закрывает саму Стартовую Базу, т.е. саму себя.

dkny
3. Папка для базы это "рюшечки"? :)) И зачем она, если путь базы "C:\\"?

На самом деле, вряд ли кто хранит свои базы на "C:\\". Обычно это некая папка на локальном диске, которая назначается Админом базы (читай "тобой"), и для простоты администрирования эта папка лежит и называется одинаково. Так вот, представим - папку переименовали, снесли или вообще заменили комп, а положить копию рабочей базы на локальный диск надо... Вот тут и треба проверить весь путь на существование и, при его отсутствии, воссоздать.

dkny
4. А зачем нужна проверка пользователя по сетевому имени? Для того, чтобы запустить главную базу с требуемым именем пользователя, на случай, если он его забыл? :) Смайл, потому что у меня на машинах работают несколько менеджеров (точнее, своих машин нет ни у кого, пользуются свободной), поэтому имя вводят всякий раз самостоятельно. Зы: но это шикарно, конечно :)

Не на случай "если забыл", а для того чтоб вообще не запоминал :)
У нас каждый пользователь входит в Windows под своим логином, и нет смысла просить вводить логин ещё и на базу (своего рода "Аутентификация на уровне Windows")... но это вопрос организации безопастности.
Если используется файл рабочей группы, то имя пользователя в командной строке можно не указывать - Access сам спросит.
lobodava
Дата: 09.06.2004 15:48:42
dkny
Что значит эта строка (в коде по ссылке): HasToBeRefreshed = (lngVersionOnServer > lngVersionOnC).

Виноват, читал невнимательно.
Это значит, что значение возращаемое функцией есть результат выражения (lngVersionOnServer > lngVersionOnC) - это выражение вернёт True если выражение истинно, и False если нет.

Эту строчку можно бало бы переписать так
If lngVersionOnServer > lngVersionOnC Then
    HasToBeRefreshed = True
Else
    HasToBeRefreshed = False 
End If