ИИмитация табличных триггеров
Включение в приложения Access возможностей, схожих с имеющимися в SQL Server
или Oracle.
Ни Access 2003, ни более ранние версии не поддерживают события в таблица*.
Триггер представляет собой событие в таблице, возникающее при операциях встав -
ки, редактирования или удаления, которое можно обработать с помощью собственной
функции. Примером полезного применения может послужить обработка
события редактирования до сохранения его результатов с целью организации
хранения прежнего состояния данных, то есть для помещения прежней версии
записи в резервную таблицу. Таким образом, сохранится возможность провести
ревизию изменения данных. Если по каким-то причинам возникнут проблемь,
связанные с изменением данных, всегда можно будет вернуться к их первоначальному
варианту.
Та же логика применима и к удалениям. Используя триггеры, вы можете вклиниться
в процесс удаления и поместить данные в архив, вместо того чтобы потерять
их безвозвратно. В случае вставок (когда в таблицу добавляется новая
запись) вы можете перепроверить данные, прежде чем позволить им попасть
в таблицу.
К сожалению, Access не позволяет совершать подобные действия напрямую, при
работе непосредственно с таблицами. Но вы можете проделывать то же самое,
работая с таблицами из форм. В формах можно обрабатывать множество событий,
получая тот же результат, что и при использовании настоящих триггеров, но
работая при этом вместо таблиц с формами.
Ведение контрольного журнала
Чтобы показать этот механизм в действии, создадим в базе данных еще одну таблицу
для зеркального отображения существующей таблицы данных и веденил
контрольного журнала изменений, вносимых в таблицу. Осуществим задуманное,
добавив два дополнительных поля: одного — для хранения типа операции, а другого
— для хранения времени ее проведения. На рис. 2.17 показаны две таблиць :
таблица данных (1Ы_Клиенты) и таблица, предназначенная для хранения записе \
первой таблицы в том состоянии, в котором они находились до внесения изменений
или удаления (т. Ы_Клиенты_контрольный_журнал).
Обратите внимание на следующие особенности:
• Таблица журнала содержит два дополнительных поля: Операция и Время_опе-
рации.
• Если для таблицы данных поле КлиентЮ является первичным ключом, то длл
таблицы журнала оно преднамеренно таким ключом не является. Так сделан э
потому, что в таблице журнала может содержаться несколько записей, относящихся
к одному и тому же клиенту (и с одним и тем же значением
поля КлиентID.
Отслеживание событий формы
Теперь вы можете воспользоваться стандартной формой для просмотра записей,
их добавления, редактирования и удаления из таблицы данных.
На рис. 2.17 показаны две таблиць :
таблица данных (1Ы_Клиенты) и таблица, предназначенная для хранения записе \
первой таблицы в том состоянии, в котором они находились до внесения изменений
или удаления (т. Ы_Клиенты_контрольный_журнал).
Обратите внимание на следующие особенности:
• Таблица журнала содержит два дополнительных поля: Операция и Время_опе-
рации.
• Если для таблицы данных поле КлиентЮ является первичным ключом, то длл
таблицы журнала оно преднамеренно таким ключом не является. Так сделан э
потому, что в таблице журнала может содержаться несколько записей, относящихся
к одному и тому же клиенту (и с одним и тем же значением
поля КлиентID).
Отслеживание событий формы
Теперь вы можете воспользоваться стандартной формой для просмотра записей,
их добавления, редактирования и удаления из таблицы данных. На рис. 2.18 показана
обычная форма, имеющая в качестве источника записей таблицу tbL
Клиенты.
Разумеется, форма содержит встроенный программный модуль, обрабатывающий
два события: До обновления и Удаление. Обработчиком события До обновления обслуживаются
и вставки, и обновления, а обработчик события Удаление работает
только по прямому предназначению. В частности, при вставке новых данных обработчик
события До обновления проверяет приемлемость данных (то есть, скажем,
наличие фамилии). Если данные не пройдут проверку, свойство Cancel будет
установлено в True, что приведет к отмене события.
В процессе обновления (редактирования) запись, подвергаемая изменениям, сначала
копируется в таблицу журнала, то есть сохраняется в нем в своем прежнем
виде. Перед удалением запись также попадает в таблицу журнала.
Код
Этот код должен быть помещен во встроенный программный модуль формы.
Поле Операция таблицы журнала получает одно из двух значений: Обновленке
или Удаление. Оба обработчика событий используют одну общую функцио
(build_sql):
Private Sub Form_Beforellpdate(Cancel As Integer)
On Error GoTo err_end
Dim ssql As String
Dim conn As ADODB. Connection
Set conn = CurrentProject. Connection
I f NewRecord = False Then
ssql = bui ld_sql (КлиентЮ, "Обновление")
conn. Execute ssql
conn. Close
Set conn = Nothing
Else
I f IsNull(ClientLastName) Or ClientLastName = "" Then
MsgBox "Нужно ввести фамилию"
Cancel = True
End If
End If
Exit Sub
err_end:
MsgBox Err. Description
End Sub
Private Sub Form_Delete(Cancel As Integer)
On Error GoTo err_end
Dim ssql As String
Dim conn As ADODB. Connection
Set conn = CurrentProject. Connection
ssql = build_sql(KnneHTlD, "Удаление")
conn. Execute ssql
Exit Sub
err_end:
MsgBox E r r. D e s c r i p t i on
End Sub
Function b u i l d _ s q l ( c l i e n t _ i d As Long, operation As
build_sql • "Insert Into 1Ы_Клиенты_контрольный
build_sql = build_sql & КлиентЮ & ", "
build_sql = build_sql & & _
String) As String
журнал Values ("
DLookup("Фамилия" , " 1Ы_Клиенты" , "КлиентЮ=" &_
c l i e n t _ i d ) & " " , "
build_sql = build_sql & & _
DLookup ("Имя " , 'ЧЫ_Клиенты" , "КлиентЮ=" &_
c l i e n t _ i d ) & " " , "
build_sql = build_sql & & _
DLookup ("Отчество", 'ЧЫ_Клиенты", "КлиентЮ=" &_
c l i e n t _ i d ) & " " , "
build_sql = build_sql & " " " & _
DLookupC'Aflpec", 'ЧЫ_Клиенты", "КлиентЮ=" &_
c l i e n t _ i d ) & " " , "
build_sql = build_sql & " " " & _
DLookup( "Город", " 1Ы._Клиенты", "КлиентЮ=" &_
c l i e n t _ i d ) & " " , "
build_sql = build_sql & & _
DLookup ("Почтовый_индекс", " 1Ы_Клиенты", "КлиентЮ=" &_
c l i e n t _ i d ) & " " , "
build_sql = build_sqi & & _
DLookup ("Телефон", 'ЧЫ_Клиенты", "КлиентЮ=" &_
c l i e n t _ i d ) & " " , "
build_sql = build_sql & & operation & " " , "
build_sql = build_sql & "#" & Now( ) & "#)"
End Function
Выполнение кода
Код выполняется в том случае, когда в форме совершаются операции вставки,
обновления и удаления. При этом никаких особых дополнительных действий —
скажем, щелчков на кнопке — не требуется. Журнал ведется во время работы
пользователей. В журнальной таблице регистрируются все изменения и даже хранятся
многократные изменения, произведенные в записи клиента. Функция
build_sql формирует команду SQL Insert. В эту команду, в зависимости от функции,
осуществившей вызов (и передавшей в виде аргумента слово «Обновление»
или «Уда-ление»), включается в качестве одного из регистрируемых параметров
либо Обновление, либо Удаление. Строка, содержащая команду SQL, возвращается
в функцию, осуществившую вызов, а затем эта функция выполняет
команду на вставку данных.
Все это может пригодиться на практике. Например, клиент переехал (изменился
адрес) или вступил в брак (изменилась фамилия), переметнулся к конкуренту (его
запись нужно удалять) и т. д. На рис. 2.19 показана таблица регистрационного
журнала, содержащая несколько записей. В каждой записи отражена операция
и время ее проведения.
Метод, применяемый в данном трюке, имитирует все то же самое, что предоставляется
SQL Server, Oracle и другими системами управления базами данных при
использовании триггеров. Не стоит позволять элите мира баз данных считать, что
Access в чем-то им уступает!
В таблице клиентов и таблице регистрационного журнала содержится множество
записей и благодаря замечательному свойству регистрации времени сохраняете ч
вся последовательность их изменений.


