В процессе сопровождения информационных баз 1С часто возникает задача автоматизации очистки системы от неактуальных данных. Простого помечания объектов на удаление бывает недостаточно, так как накопление «мусора» замедляет работу запросов и увеличивает объем базы данных. В этой статье мы подробно разберем, как реализовать программное удаление документов, учитывая все нюансы ссылочной целостности, прав доступа и производительности. Если же стоит задача полностью очистить базу данных от сведений по конкретному юридическому лицу, то для рекурсивного стирания объектов с учётом кольцевых зависимостей применяется выборочное удаление организаций в 1С.
Для начала рассмотрим базовый механизм, который предоставляет платформа 1С. Основным инструментом является метод глобального контекста УдалитьОбъекты. Проанализируем его синтаксис: УдалитьОбъекты(МассивСсылок, ПроверятьСсылочнуюЦелостность, МассивНеудаленныхОбъектов). Процесс удаления обычно начинается с формирования списка объектов, которые мы хотим исключить из базы.
Рассмотрим пример кода, который выбирает помеченные на удаление документы «Приходный кассовый ордер» за определенную дату и пытается их удалить:
Процедура УдалениеДокументовПКО(ДатаВыбора)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПКО.Ссылка КАК Ссылка
|ИЗ
| Документ.ПриходныйКассовыйОрдер КАК ПКО
|ГДЕ
| ПКО.ПометкаУдаления = ИСТИНА
| И ПКО.Дата <= &Дата";
Запрос.УстановитьПараметр("Дата", ДатаВыбора);
РезультатЗапроса = Запрос.Выполнить();
Если РезультатЗапроса.Пустой() Тогда
Возврат;
КонецЕсли;
МассивПомеченных = РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Ссылка");
НеУдаляемые = Неопределено;
Попытка
// Второй параметр ИСТИНА включает контроль ссылок
УдалитьОбъекты(МассивПомеченных, Истина, НеУдаляемые);
Если НеУдаляемые <> Неопределено И НеУдаляемые.Количество() > 0 Тогда
Для Каждого Запись Из НеУдаляемые Цикл
// Запись[0] - объект, который хотели удалить
// Запись[1] - объект, который мешает удалению
Сообщить("Объект " + Запись[0] + " не удален. На него ссылается: " + Запись[1]);
КонецЦикла;
КонецЕсли;
Исключение
Сообщить("Произошла критическая ошибка: " + ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Важный момент: Если вы установите второй параметр в значение Ложь, система удалит объекты мгновенно, игнорируя любые связи. Это крайне опасно, так как в базе останутся «битые» ссылки (Объект не найден), что приведет к ошибкам в отчетах и работе алгоритмов.
Часто возникает ситуация, когда документ не удаляется, так как на него ссылаются записи в регистрах сведений. Например, документ может быть указан в регистре «Статусы документов» или «История изменений». Выясним, как программно очистить эти зависимости. Для решения этой задачи пригодится универсальная обработка регистров сведений для очистки записей по фильтрам.
Для удаления записей из регистра сведений по конкретной ссылке необходимо использовать СоздатьНаборЗаписей. Разберем алгоритм очистки на примере:
Процедура ОчиститьЗаписиРегистраПоДокументу(ДокументСсылка)
// Предположим, у нас есть регистр сведений "СведенияОДокументах"
// где в измерении "Документ" хранится наша ссылка
НаборЗаписей = РегистрыСведений.СведенияОДокументах.СоздатьНаборЗаписей();
НаборЗаписей.Отбор.Документ.Установить(ДокументСсылка);
// Записываем пустой набор, тем самым удаляя все записи по фильтру
НаборЗаписей.Записать();
КонецПроцедуры
Если вы не знаете заранее, в каких регистрах может находиться ссылка, рекомендуется использовать метод НайтиСсылки. Он возвращает таблицу значений со списком всех мест в базе данных, где упоминается ваш объект. Проанализировав эту таблицу, можно динамически формировать очистку для каждого найденного регистра.
При выполнении удаления программно можно столкнуться с ошибкой Нарушение прав доступа. Это происходит даже в том случае, если у пользователя есть роль «Полные права». Разберем причины:
УдалитьОбъекты иногда может расцениваться системой как попытка интерактивного действия. Если в роли снята галочка «Интерактивное удаление», операция может блокироваться.Решение: Для выполнения массовой очистки данных лучше всего выносить код удаления в серверный модуль с установленным свойством Привилегированный. В этом режиме проверки прав доступа игнорируются, что позволяет корректно очистить базу от лица системы.
Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), крайне рекомендуется использовать встроенные методы подсистемы «Удаление помеченных объектов». Это позволит избежать «изобретения велосипеда» и обеспечит корректную работу в фоновом режиме.
В БСП за это отвечает программный интерфейс модуля УдалениеПомеченныхОбъектов. Основное преимущество здесь в том, что система сама знает, как обрабатывать исключения, и может выводить пользователю стандартное диалоговое окно со списком блокирующих ссылок.
При удалении большого количества документов (тысячи и более) монопольный режим, предложенный в некоторых решениях, является избыточным и вредным для многопользовательской работы. В случаях, когда требуется сократить огромный объем накопленных исторических данных в крупной базе, для параллельной обработки регистров в несколько потоков используется многопоточная свёртка 1С:ERP. Вместо этого проанализируем стратегию порционного удаления:
1. Использование блокировок: Перед удалением конкретной порции объектов установите БлокировкаДанных на эти ссылки. Это предотвратит попытки изменения этих документов другими пользователями в момент удаления.
2. Удаление пакетами: Не пытайтесь удалить 10 000 документов за один вызов метода УдалитьОбъекты. Это вызовет разрастание лога транзакций SQL-сервера и может привести к временной заморозке всей базы. Разделите массив на пакеты по 200–500 штук и фиксируйте транзакцию после каждого пакета.
// Пример пакетного удаления
РазмерПакета = 500;
ВсегоОбъектов = МассивПомеченных.Количество();
ТекущийИндекс = 0;
Пока ТекущийИндекс < ВсегоОбъектов Цикл
ПакетДляУдаления = Новый Массив;
Для К = 1 По РазмерПакета Цикл
Если ТекущийИндекс >= ВсегоОбъектов Тогда Прервать; КонецЕсли;
ПакетДляУдаления.Добавить(МассивПомеченных[ТекущийИндекс]);
ТекущийИндекс = ТекущийИндекс + 1;
КонецЦикла;
// Удаляем порцию данных
УдалитьОбъекты(ПакетДляУдаления, Истина, НеУдаляемые);
КонецЦикла;
Мы рассмотрели комплексный подход к программному удалению данных. Помните, что безопасность данных — приоритет, поэтому всегда используйте параметр ПроверятьСсылочнуюЦелостность = Истина. Для эффективной очистки связанных регистров применяйте НаборЗаписей, а для обхода проблем с правами доступа используйте Привилегированный режим. Перед запуском любых обработок по удалению обязательно создавайте резервную копию информационной базы.