В процессе разработки на платформе 1С:Предприятие 8 часто возникает задача по поддержанию целостности данных. Типичный пример: документ хранит ссылку на элемент справочника, который был создан специально для этого документа и не используется в других местах. При удалении документа такой элемент справочника становится «мусором» в базе данных. В данной статье мы подробно разберем, как реализовать механизм автоматического удаления связанных объектов, проанализируем различные подходы и выберем наиболее надежные методы.
Рассмотрим ситуацию: у нас есть форма списка документов. Пользователь может удалять одну или сразу несколько строк. Требуется, чтобы вместе с документами из базы исчезали и объекты справочника, ссылки на которые содержатся в реквизитах этих документов. Нам предстоит выяснить, где лучше разместить программный код, как правильно получить ссылки и как обеспечить безопасность этой операции.
Прежде всего, нам необходимо определиться, на каком уровне будет исполняться код удаления. Существует два основных подхода:
ПередУдалением. Это позволит нам выполнить действия именно тогда, когда пользователь нажимает кнопку «Удалить» в интерфейсе. Однако этот метод ненадежен: если документ будет удален программно (например, через внешнюю обработку) или из другой формы, связанный справочник останется в базе.ПередУдалением внутри модуля самого документа. В этом случае код сработает всегда, независимо от способа удаления объекта.Рассмотрим подробнее реализацию через модуль объекта. Проанализируем пример кода, который необходимо разместить в модуле документа:
Процедура ПередУдалением(Отказ)
// Проверим, заполнена ли ссылка на связанный справочник
Если ЗначениеЗаполнено(ЭтотОбъект.СвязанныйОбъектСправочника) Тогда
Попытка
// Получаем объект справочника для удаления
ОбъектСправочника = ЭтотОбъект.СвязанныйОбъектСправочника.ПолучитьОбъект();
Если ОбъектСправочника <> Неопределено Тогда
// Выполняем непосредственное удаление
ОбъектСправочника.Удалить();
КонецЕсли;
Исключение
// Если возникла ошибка (например, нарушение прав или ссылочной целостности)
ТекстОшибки = КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Не удалось удалить связанный элемент справочника: " + ТекстОшибки);
// При необходимости можно отменить удаление самого документа
// Отказ = Истина;
КонецПопытки;
КонецЕсли;
КонецПроцедуры
Если же стоит задача реализовать логику именно в форме списка (например, чтобы запросить подтверждение у пользователя), нам потребуется работать с выделенными строками динамического списка. Выясним, как получить ссылки на объекты в этом случае. Разберем пример для управляемых форм:
&НаКлиенте
Процедура СписокПередУдалением(Элемент, Отказ)
// Отменяем стандартное удаление, чтобы выполнить его программно с нашей логикой
Отказ = Истина;
МассивВыделенныхСтрок = Элементы.Список.ВыделенныеСтроки;
Если МассивВыделенныхСтрок.Количество() = 0 Тогда
Возврат;
КонецЕсли;
ТекстВопроса = "Будут удалены выбранные документы и связанные с ними элементы справочника. Продолжить?";
// Здесь должен быть вызов описания оповещения для вопроса пользователю
// ...
УдалитьДокументыНаСервере(МассивВыделенныхСтрок);
КонецПроцедуры
На стороне сервера нам необходимо будет обойти массив ссылок и выполнить удаление. Рассмотрим, как правильно извлечь данные из реквизитов:
&НаСервере
Процедура УдалитьДокументыНаСервере(МассивСсылок)
Для Каждого СсылкаДокумента Из МассивСсылок Цикл
// Получаем объект документа для доступа к его данным
ДокументОбъект = СсылкаДокумента.ПолучитьОбъект();
// Получаем ссылку на справочник из реквизита
СсылкаНаСправочник = ДокументОбъект.РеквизитСправочник;
НачатьТранзакцию();
Попытка
// Сначала удаляем справочник
Если ЗначениеЗаполнено(СсылкаНаСправочник) Тогда
ОбъектСправочника = СсылкаНаСправочник.ПолучитьОбъект();
Если ОбъектСправочника <> Неопределено Тогда
ОбъектСправочника.Удалить();
КонецЕсли;
КонецЕсли;
// Затем удаляем сам документ
ДокументОбъект.Удалить();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ЗаписьЖурналаРегистрации("УдалениеОбъектов", УровеньЖурналаРегистрации.Ошибка, , , КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецЦикла;
КонецПроцедуры
Важно понимать последствия непосредственного удаления объектов методом Удалить(). Если на удаляемый элемент справочника ссылаются другие документы или отчеты, в системе появятся битые ссылки с текстом «Объект не найден». Проанализируем, как этого избежать.
В стандартах разработки 1С рекомендуется использовать пометку на удаление вместо физического стирания данных. Разберем, как изменить наш код для более безопасной работы:
// Вместо ОбъектСправочника.Удалить() используем:
ОбъектСправочника.УстановитьПометкуУдаления(Истина, Истина);
Это позволит администратору системы запустить стандартную обработку «Удаление помеченных объектов», которая автоматически проверит, не используется ли этот справочник где-то еще, прежде чем окончательно удалить его из базы.
Если вы работаете в типовой конфигурации и не хотите менять модуль объекта документа (чтобы облегчить будущие обновления), мы рекомендуем использовать Подписки на события. Посмотрим, как это настроить:
ПодпискаНаСобытие.ПередУдалением.Код в общем модуле будет выглядеть идентично коду из модуля объекта, за исключением того, что в процедуру первым параметром будет передаваться сам Источник (объект документа).
Проанализируем ситуацию, описанную в сообщениях форума: «В справочнике хранятся данные, которых нет в документе». Если эти данные жестко привязаны к документу по принципу «один к одному», то использование справочника может быть избыточным.
Регистры сведений — это более эффективный инструмент для хранения дополнительных сведений. Выясним преимущества этого подхода:
ДокументСсылка и поставить свойство «Ведущее», то при удалении документа записи в регистре будут удалены платформой автоматически.ПередУдалением.Подводя итог, мы можем выделить следующие шаги для успешной реализации задачи:
УстановитьПометкуУдаления().НачатьТранзакцию() / ЗафиксироватьТранзакцию(). Это гарантирует, что не возникнет ситуации, когда документ удален, а справочник остался из-за ошибки (или наоборот).УстановитьПривилегированныйРежим(Истина) в серверном коде.Мы рассмотрели все основные аспекты удаления связанных объектов. Выбор конкретного метода зависит от ваших требований к производительности и строгости контроля ссылочной целостности в вашей информационной базе.