В процессе разработки и администрирования баз данных на платформе 1С:Предприятие (начиная с классической версии 7.7 и заканчивая современными редакциями 8.3) одной из наиболее важных тем является сохранение ссылочной целостности данных. Часто у начинающих разработчиков возникает вопрос: что произойдет с элементами подчиненного справочника «Б», если физически удалить его владельца — элемент справочника «А»?
В этой статье мы подробно разберем внутренние механизмы работы платформы 1С при удалении связанных данных, выясним причину появления так называемых «битых ссылок», научимся правильно писать код для каскадного удаления и рассмотрим способы исправления уже возникших ошибок в базе данных.
Для того чтобы понять последствия удаления, давайте заглянем на уровень СУБД. В среде 1С:Предприятие каждый справочник представляет собой отдельную таблицу. Например, в файловой версии 1С 7.7 (DBF) справочник «А» хранится в файле вида SC*.dbf, а подчиненный справочник «Б» — в другом файле. В SQL-версиях это будут две отдельные таблицы базы данных.
В таблице подчиненного справочника «Б» для каждой строки существует специальное служебное поле Владелец (в базе данных оно хранит уникальный внутренний идентификатор (ID) элемента-владельца из справочника «А»).
Когда мы выполняем программный код непосредственного удаления:
спрА = СоздатьОбъект("Справочник.А");
спрА.НайтиПоКоду(123);
спрА.Удалить(1);
Платформа выполняет прямую команду удаления записи из таблицы справочника «А». При этом:
Владелец в подчиненных элементах по-прежнему содержит ID удаленного элемента «А», но в таблице «А» такой записи больше нет. Ссылка становится «битой» (неразрешенной).<Объект не найден> (ID объекта).Давайте проанализировать ситуацию, почему поведение системы отличается в зависимости от способа удаления. Разработчики платформы заложили различную логику для действий пользователя в интерфейсе и для действий программиста в коде:
Удалить(0) (пометка на удаление): Помечается только сам элемент «А». Его подчиненные элементы «Б» автоматически пометку на удаление не получают! Это ключевое отличие от интерактивного режима.Удалить(1) (непосредственное удаление): Элемент «А» стирается из базы данных мгновенно. Подчиненные элементы «Б» остаются сиротами с битыми ссылками.Чтобы избежать появления в информационной базе «мусора» и неразрешенных ссылок, разработчик обязан самостоятельно позаботиться об очистке подчиненных данных перед удалением владельца.
Рассмотрим подробнее правильный алгоритм непосредственного удаления элементов в 1С 7.7:
ИспользоватьВладельца().Посмотрим на пример реализации этого алгоритма в коде:
спрА = СоздатьОбъект("Справочник.А");
спрБ = СоздатьОбъект("Справочник.Б");
Если спрА.НайтиПоКоду(123) = 1 Тогда
// Шаг 1. Позиционируемся на подчиненных элементах конкретного владельца
спрБ.ИспользоватьВладельца(спрА.ТекущийЭлемент());
спрБ.ВыбратьЭлементы();
// Шаг 2. Удаляем все подчиненные элементы в цикле
Пока спрБ.ПолучитьЭлемент() = 1 Цикл
спрБ.Удалить(1); // Параметр 1 означает непосредственное удаление
КонецЦикла;
// Шаг 3. Теперь, когда подчиненные элементы удалены, удаляем самого владельца
спрА.Удалить(1);
КонецЕсли;
Важное замечание по оптимизации: Если подчиненных элементов очень много или удаление происходит в высоконагруженной базе данных, удаление каждого элемента по одному в цикле может работать медленно. В таких случаях рекомендуется оборачивать процесс в транзакцию с помощью операторов НачатьТранзакцию() и ЗафиксироватьТранзакцию().
Если из-за ошибок в коде сторонних обработок или некорректных обменов данными в вашей базе уже образовались «сироты» без владельцев, их необходимо выявить и устранить. Для этого в платформе 1С предусмотрен штатный механизм — Тестирование и исправление информационной базы (ТИИ), доступный в режиме Конфигуратора.
Разберем по шагам, как настроить ТИИ для решения этой проблемы:
Владелец у подчиненных объектов будет очищено. Для подчиненных справочников этот вариант малопригоден, так как они не могут полноценно существовать без владельца.<Объект не найден>.... После этого вы сможете вручную перепривязать или корректно удалить эти объекты.Проанализируем, как изменилось поведение платформы при переходе на современные версии 1С 8. Общие принципы СУБД остались прежними, однако разработчики получили более удобные инструменты автоматизации контроля:
Объект.Удалить() в 1С 8 ведет себя точно так же, как и в 1С 7.7 — он стирает запись без проверки зависимостей, порождая битые ссылки.УстановитьПометкуУдаления(). У этого метода появился второй полезный параметр: УстановитьПометкуУдаления(Истина, Истина). Второй параметр (ВключаяПодчиненные) берет на себя всю рутину по автоматической каскадной пометке подчиненных элементов во всех подчиненных справочниках.НайтиПомеченныеНаУдаление() и встроенной функции УдалитьОбъекты() система проверяет, используются ли удаляемые элементы где-либо еще в базе данных (в документах, регистрах или других справочниках), и блокирует удаление при обнаружении связей.Таким образом, золотое правило разработчика 1С при работе с удалением данных звучит так: никогда не удаляйте объекты непосредственно через код без предварительной проверки и удаления связанных с ними подчиненных данных. Используйте для этого штатные механизмы пометки на удаление и последующее интерактивное удаление помеченных объектов, либо тщательно пишите код каскадной очистки таблиц.