Удаление записей из таблиц БД
Структура
Иерархия наследования и структура данных
Бизнес-классы – это сущность, предназначенная для решения различных бизнес-задач. Бизнес-классы используются для описания структуры данных и/или функциональной части бизнес-задач. Каждый экземпляр каждого класса уникально идентифицируется.
Каждому бизнес-классу, состояния экземпляров которого хранятся в базе данных, соответствует таблица. Уникальный идентификатор экземпляра класса используется для формирования первичного ключа таблицы и состоит из двух полей id и tid. Поле id содержит глобально уникальный идентификатор (guid) объекта, а поле tid – целочисленный идентификатор типа объекта. Эти целочисленные идентификаторы формируются на этапе развертывания и могут отличаться в разных базах, но каждому типу соответствует единый для всех баз уникальный идентификатор, задаваемый на этапе разработки класса программистом. Информация об развернутых типах хранится в служебной таблице realtypes.
Бизнес-классы могут наследоваться от других бизнес-классов. При этом в таблице, хранящей данные класса-наследника, размещаются только поля, соответствующие объявленным в этом классе свойствам. Все хранящиеся в базе данных классы наследуются от класса PersistedObjectBase, которому соответствует таблица object. При сохранении экземпляра класса записи создаются во всех таблицах по всей цепочке наследования, начиная с таблицы object. Важно, что при чтении объекта система ожидает, что соответствующая запись есть в каждой таблице по цепочке наследования.
Имена всех объектов базы данных (таблиц, полей таблиц, индексов, триггеров и пр.) формируются системой автоматически. В следующих версиях правила именования могут быть изменены, никакие имена объектов базы данных не являются частью публичного программного интерфейса системы.
Поля таблиц
Для определения набора данных, которые хранятся в объекте бизнес-класса используются атрибуты. Атрибуты подразделяются на два вида: физические и ссылочные. Физические атрибуты используются для хранения конкретных значений (физических величин), в то время как ссылочные хранят ссылки на другие экземпляры бизнес-классов.
Каждому физическому атрибуту соответствует свое поле таблицы, а ссылочному – два поля, содержащие идентификатор используемого объекта.
Если ссылка делается на тип, отличный от PersistedObjectBase, то для колонок, содержащих идентификатор используемого объекта, создается внешний ключ (foreign key) для обеспечения ссылочной целостности.
Для ссылок на самый базовый тип (PersistedObjectBase) вместо внешнего ключа используются специальные служебные таблицы.
Ограничения
В базе данных создаются ограничения трех видов: обязательность (not null), уникальность (unique), ссылочная целостность (reference). В зависимости от используемой СУБД реализация ограничений вида уникальность может отличаться: используются уникальные индексы (unique index) или ограничения таблиц (unique constraint).
Спецификации
Отдельный вид отношений между классами – отношения часть-целое. Типичный пример таких отношений – декомпозиция документа на «заголовок документа» и «спецификация документа». Для удобства работы с такими классами в классе «заголовок» создаются коллекции объектов типа «спецификация», а в классе «спецификация» создается свойство с предопределенным именем Master типа «заголовок».
В таблице, соответствующей классу-спецификации, есть поля, содержащие идентификатор объекта-владельца коллекции. Эти поля соответствуют свойству Master класса-спецификации, но именуются системой автоматически по имени класса-владельца спецификации.
Пример
Рассмотрим простую модель, которая содержит:
- класс с именем DictClass, у которого есть: физический атрибут с именем Code
- класс с именем BaseClass, у которого есть: физический атрибут с именем Attrib1
- класс с именем MasterClass, наследуемый от класса BaseClass, у которого есть: физические атрибуты с именами Attrib2 и Attrib3, ссылочный атрибут с именем Dict и спецификация типа DetailClass с именем Spec
- класс с именем DetailClass, у которого есть физический атрибут с именем Attrib4
Для рассмотренного примера будут созданы три таблицы:
- таблица DictClass c полями id, tid, Code
- таблица BaseClass c полями id, tid, Attrib1
- таблица MasterClass c полями id, tid, Attrib2, Attrib3, Dict_id, Dict_tid
- таблица DetailClass c полями id, tid, Attrib4, MasterClass_id, MasterClass_tid
Поля id и tid в каждой таблице входят в первичный ключ.
Возможные проблемы при неполном удалении данных
Платформа создавалась в предположении, что только сервер приложений будет формировать схему данных и менять записи в таблицах. Поэтому некорректное с точки зрения сервера приложений изменение данных или схемы базы данных может привести к серьезным ошибкам или полной неработоспособности системы. Рассмотрим на примерах некоторые наиболее частые проблемы, возникающие в том случае, когда данные удаляются не из всех таблиц по цепочке наследования. Оставшиеся в каких-то таблицах записи, которые не имеют всех продолжения в других таблицах по цепочке наследования, будем называть дефективными.
Дефективные записи не отображаются в пользовательском интерфейсе
Когда система строит запросы для показа объектов или их обработки, в запросы включаются все таблицы объекта, которые связываются по первичному ключу. Запросы имеет примерно такой вид:
SELECT a.id, a.tid, b.Attrib1, c.Attrib2, c.Attrib3
FROM objects a
JOIN BaseClass b ON a.id=b.id AND a.tid=b.tid
JOIN MasterClass c ON a.id=c.id AND a.tid=c.tid
WHERE
. . .
Поэтому если в какой-то из таблиц нет записи, то в результирующую выборку объект не попадет.
Ограничения уникальности
Если не удалена запись из таблицы, в которой определено ограничение уникальности, то может возникнуть ошибка при попытке создать новую запись, содержащую такой же набор полей, как у дефективной записи. Пользователь получит сообщение о нарушенном ограничении, но не сможет найти существующую запись, поскольку она не отображается в интерфейсе.
Агрегирующие запросы
Дефективные записи не отображаются в пользовательском интерфейсе, но могут оказывать влияние на результаты запросов, в которых используются агрегирующие функции (SUM, MIN, MAX и пр.). Это происходит потому, что для выполнения таких запросов система не пытается поднять объект в память из базы данных.
В результате часть расчетных данных будет не соответствовать объектам, которые пользователь может увидеть в интерфейсе. Например, сумма в строке оборотной ведомости может не соответствовать сумме проводок, которые формируют эту строку.
Ссылки на несуществующие объекты
Система не использует внешние ключи (foreign key) для контроля ссылочной целостности с таблицей object и некоторых служебных таблиц. Это сделано потому, что в некоторых СУБД есть ограничение на количество внешних ключей у таблицы.
Если в служебных таблицах останутся записи, соответствующие несуществующим объектам, возможны разнообразные ошибки, например, невозможно снять отработку документа.
Разрастание базы данных
В некоторых случаях для хранения больших двоичных данных (BLOB) система использует выделенную таблицу streams. Записи из этой таблицы автоматически удаляются в тот момент, когда удаляется соответствующий объект. При некорректном ручном удалении записей в этой таблице могут остаться мусорные записи, занимающие большой объём.
Особенности дизайна конкретного раздела
Описанные выше проблемы можно назвать системными, потому что они могут возникнуть вне зависимости от конкретного использования данных в прикладном решении. Однако, возможны и специфические проблемы конкретного раздела, спроектированного так, что для корректной работы ожидается существование какой-либо записи. Да, это может быть не лучшим дизайном, и его следовало бы изменить, но до этих изменений система окажется неработоспособной из-за ручного удаления записей.
Почему не рекомендуем использовать скрипты, опубликованные на форуме техподдержки
Во-первых, не все эти скрипты разработаны с учетом описанных выше особенностей системы. Во-вторых, они разработаны для конкретной версии, а с течением времени структура данных может меняться. Поэтому корректно работающий в версии 1 скрипт может некорректно работать в версии 2.
Почему возникает необходимость удалять данные
Неудачный импорт
Типичный сценарий такой: специалисты импортировали какие-то данные, а потом поняли, что часть информации содержит ошибки. Чтобы сэкономить время решают удалить данные, содержащие ошибки.
Настоятельно рекомендуем полностью повторить импорт в пустую базу. Настоятельно рекомендуем делать промежуточные резервные копии перед выполнением очередного этапа импорта. Из практики известно, что экономия нескольких часов на этапе импорта может обернуться существенно большими потерями на устранение ошибок в рабочей базе. Помните, что после начала регулярной работы в базе поиск и устранение ошибок осложняется!
В базе развёрнуты модули, на которые нет лицензии
Необходимость удаления данных возникает потому, что при неполном обновлении базы данных до новой версии могут возникать ошибки вида «класс ХХХ не зарегистрирован».
Такое случается по следующим причинам:
- в рабочую систему разворачивается какой-то новый модуль «просто посмотреть»;
- при начальной установке системы у заказчика за основу взята готовая база из дистрибутива, содержащая модули, на которые у заказчика нет лицензии;
- заказчик решил не продлевать лицензию на какой-то модуль.
Важно отметить, что первые два случая – это грубая ошибка специалиста, ответственного за обслуживание системы. При этом совершенно неважна его мотивация или логика принятия им решения.
Если заказчик отказывается от покупки модуля, то правильным выходом из сложившейся ситуации является полное удаление данных, которые относятся к модулям, на которые нет лицензии. Эта операция выполняется при помощи утилиты dbinfo, включённой в поставку системы. Отдельно следует объяснить заказчику, что он может продолжить использование системы в прежней конфигурации, но не сможет устанавливать новые версии. Поэтому для случая, когда заказчик не хочет продлевать лицензию на модуль, мы рекомендуем оставить одну базу данных со всеми развёрнутыми модулями и экземпляром системы той версии, для которой действует лицензия. Это позволит обрабатывать накопленные данные. Второй экземпляр системы должен быть настроен на новую базу, из которой нелицензированные модули будут удалены. Этот экземпляр можно будет обновлять в ручном или автоматическом режиме до окончания срока лицензионного обслуживания.