| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Firebird, Interbase > Версионность записей |
| Автор: Gluttton 28.10.2009, 00:49 |
| Доброго времени суток! Вдохновившись http://rsdn.ru/article/db/dbhistory.xml, решил попробовать реализовать версионность средствами Firebird. Реализовал следующую модель: Две таблицы, первая хранит данные, а вторая хранит предыдущее значение, дату изменения и пользователя, который изменил значение. Мультики начались при попытке осуществить предложенным в статье методом версионирование при удалении данных. Автор статьи предлогает ввести дополнительное поле - флаг удаления и при удалении записи запрещать удаление записи, а вместо этого поднимать флаг (например значением IsDeleted). Проблема в том, что как я не пытался я не смог создать триггер, который одновременно и запрещал удаление и в тоже время вносил какие либо изменения в БД. Т.о. прихожу к выводу, что реализовать в Firebird модель версионирования, при которой бы удаление заменялось на изменение флага (признака) удаления не получится. Вижу несколько вариантов. Например можно все DELET'ы записей заменить на их UPDATE'ы... Но мне это не совсем нравится (почему то). Второй вариант заключается в том, что бы для удаленных записей создать отдельную таблицу, и при удалении переносить запись из таблицы неудаленных данных в таблицу удаленных. Вопросы: хотелось бы услышать, приходилось ли кому сталкиваться с версионированием и как это было реализовано? |
| Автор: Deniz 28.10.2009, 06:45 |
| Один из вариантов, создать вьюшку на таблицу (запретить весь доступ к таблице), на нее триггеры, и в триггере можно делать что угодно. В других СУБД такие триггеры называются "instead of" (вроде пока таких в FB нет, поправьте если не так) Второй вариант, завернуть все операции в хранимые процедуры. |
| Автор: Gluttton 28.10.2009, 18:28 |
Если коротко, то... Что бы отменить удаления я должен сгенерировать исключение, при вызове исключения, если его не обработать, все операции выполненные в триггере откатываются (т.е. нет возможности внести updeate флага признака удаления), а если обработать исключение, то удаление не отменяется (т.е. происходит удаление той(тех) записей для которых вызван delete)... Пытался разнести операции отмены удаления и обновления флага по триггерам before- и after- , но безрезультатно. На сколько я понял, то причина в том, что триггер after- не видит запись, которая удаляется. |
| Автор: Akella 28.10.2009, 21:38 |
| Ну да, я так и предполагал. |
| Автор: Gluttton 28.10.2009, 22:50 | ||||||||||||||
Можно конечно же, но... Точно так же можно заменить удаление обновлением... Не совсем то, что хотелось бы Как
Что не получится Вот как я делал... Пусть есть таблица с исходными данными - SC:
STATE - состояние ('NoD' - не удалено, 'IsD' - удалено). Пусть нам необходимо отслеживать изменения поля FIELD, для этого есть таблица истории - HS:
OWNER - имя пользователя, который внес изменения, D и T дата и время изменения, ACT - действие (удаление, обновление), RECORD - старое значение поля SC.FIELD, а FIELD - внешний ключ SC.ID. Создадим триггер на обновление:
Работает как часики А теперь пробую создать триггеры на удаление, для этого потребуется создать исключение:
Первый триггер:
Второй триггер:
При попытке удалить запись из исходной таблицы отмена удаления срабатывает, а обновления и логгирования не происходит... На всякий случай скрипт тестовой БД. |
| Автор: Deniz 29.10.2009, 07:16 | ||
| Gluttton, вроде уже говорил, но повторюсь. используй одно поле в этом случае
Добавлено через 4 минуты и 30 секунд Gluttton, сделал у себя тест с вьюхой см. вложение. для сервера версии 1.5 Запрос во вьюхе необходимо сделать необновляемым, иначе триггер на удаление удаляет запись в таблице sc |
| Автор: Akella 29.10.2009, 11:43 | ||
так как удаление выполняется в рамках одной транзакции, то при вызове исключения транзакция будет откачена, что повлечёт за собой и откат действий по записи данных в другую таблицу Добавлено через 1 минуту и 31 секунду
и я о том же |
| Автор: Gluttton 29.10.2009, 21:58 |
| Deniz, Спасибо за скрипт! Akella, Т.е. это безисходность? Триггер на уделение, выполняющий любое действие вместе с отменой удаления, никак не создать? Тогда думаю будет симпатичнее создать таблицу для хранения удаленных записей, т.е. триггеру прийдется не отменяя удаление копировать удаленную запись в другую таблицу (в которой хранятся удаленные записи)... |
| Автор: Akella 15.11.2009, 01:30 | ||
Ну в версии 2,5 ввели автономные транзакции.
|
| Автор: Gluttton 16.11.2009, 00:59 | ||||
| Akella, спасибо за ценный совет Используя автономные транзакции сумел одним триггером и внести записть в таблицу истории (логов) и отменить само удаление! Но! Изначально задумывалось так, что при удалении запись в исходной таблице не удаляется, а помечается как удаленная.
Так вот изменить (выполнить UPDATE) с той записью, которая удаляется никак не получается, т.к. до вызова исключения она удалена, а после вызова исключения уже ничего не выполняется... Вот это уже безисходность |
| Автор: Akella 16.11.2009, 12:28 |
| 1. В автономной транзакции помечай запись, как удалённую. 2. Вызывай исключение. В итоге, запись будет помечена, как удалённая. И удалена не будет. |
| Автор: Gluttton 17.11.2009, 00:27 |
| Akella, Ну честное слово вчера пробовал, не получалось! Сегодня, хотел повторить, что бы всё грамотно описать, что не получается, а тут бац - и всё работает! Итак по сути... Тема закрыта Для тех, кого в эту ветку приведет поиск, выкладываю конечный вариант скрипта для Firebird 2.5 (не эталон, но для примера, думаю, сгодится |