Вот я, наконец, добрался до давно мучившей меня проблемы — как реализовать Удаление помеченных объектов следующим образом:
а) не монопольно — многие пользователи и Склад работают допоздна, так что выгнать их нет никакой возможности;
б) автоматически, чтобы запустилось Фоновое Задание и удалило весь накопившийся «мусор».
Перелопатив большое количество материала, который нашел на Инфостарте и в сети, пришел к неутешительным выводам — эти варианты мне не подходят, придется обходиться своими силами….
Да и радости не прибавлял тот факт, что в 18-ой платформе была всё таки исправлена древняя ошибка № 20013012, теперь установить Монопольный режим при запуске Удаления помеченных объектов стало практически невозможно…..
Возник вопрос — что удалить, а что оставить? Решили, если есть ссылки на Справочники или Документы — оставляем, а Регистрами Сведений решили пожертвовать (даже если будет урон, то незначительный).
Вот что в результате получилось:
Процедура УдалениеПомеченныхОбъектов() Экспорт
УстановитьПривилегированныйРежим(Истина);
Попытка
ПомеченныеОбъекты = НайтиПомеченныеНаУдаление();
ТабСсылок = НайтиПоСсылкам(ПомеченныеОбъекты);
МассивКУдалению = Новый Массив;
ТабНеУдаляемых = ТабСсылок.СкопироватьКолонки();
Для Каждого Элемент из ПомеченныеОбъекты Цикл
СтрокиСсылки = ТабСсылок.НайтиСтроки(Новый Структура(«Ссылка», Элемент));
Если СтрокиСсылки.Количество() > 0 Тогда
Если СтрокиСсылки.Количество() = 1 Тогда
Если Лев(СтрокиСсылки[0].Метаданные.ПолноеИмя(),15) = «РегистрСведений» Тогда
МассивКУдалению.Добавить(Элемент); // Если ссылка на РегистрСведений, то удалять
Продолжить;
КонецЕсли;
Если СтрокиСсылки[0].Данные <> Элемент Тогда
НоваяСтрока = ТабНеУдаляемых.Добавить();
НоваяСтрока.Ссылка = СтрокиСсылки[0].Ссылка;
НоваяСтрока.Данные = СтрокиСсылки[0].Данные;
НоваяСтрока.Метаданные = СтрокиСсылки[0].Метаданные;
Продолжить;
Иначе
МассивКУдалению.Добавить(Элемент);
Продолжить;
КонецЕсли;
КонецЕсли;
Если СтрокиСсылки.Количество() > 1 Тогда // Надо проверить!!!
// Может там ссылка на справочник, или документ, или регистр сведений???
НеУдалять = Ложь;
Для й = 0 По СтрокиСсылки.Количество()-1 Цикл
// Проверим метаданные, если ссылка на РегистрСведений, тогда удалять
Если Лев(СтрокиСсылки[й].Метаданные.ПолноеИмя(),15) = «РегистрСведений» Тогда
Продолжить;
КонецЕсли;
Если СтрокиСсылки[й].Данные <> Элемент Тогда
НеУдалять = Истина; Прервать;
КонецЕсли;
КонецЦикла;
й = ?(й = Неопределено, 0, й);
Если НеУдалять Тогда
НоваяСтрока = ТабНеУдаляемых.Добавить();
НоваяСтрока.Ссылка = СтрокиСсылки[й].Ссылка;
НоваяСтрока.Данные = СтрокиСсылки[й].Данные;
НоваяСтрока.Метаданные = СтрокиСсылки[й].Метаданные;
Иначе
МассивКУдалению.Добавить(Элемент);
КонецЕсли;
КонецЕсли;
Иначе
МассивКУдалению.Добавить(Элемент); // Ссылка вообще не найдена….
КонецЕсли;
КонецЦикла;
Для Каждого Элемент из МассивКУдалению Цикл
Ссылка = Элемент.Ссылка;
Объект = Ссылка.ПолучитьОбъект();
Попытка
Если Не Объект = Неопределено Тогда
Объект.Удалить();
КонецЕсли;
Исключение
ЗаписьЖурналаРегистрации(«Удаление помеченных объектов.»,
УровеньЖурналаРегистрации.Информация, , ,
«Не могу удалить объект » + Объект);
КонецПопытки;
КонецЦикла;
// Информацию о неудаляемых ссылках сбросим в текстовый файл
ТекстДок = Новый ТекстовыйДокумент;
Для каждого Ссылка из ТабНеУдаляемых Цикл
СтрСообщения = «Объект не удален: » + СокрЛП(Ссылка[0]);
СтрСсылка = «, используется в » + СокрЛП(Ссылка[1]);
ТекстДок.ДобавитьСтроку(СтрСообщения + СтрСсылка);
КонецЦикла;
ТекстДок.Записать(КаталогВременныхФайлов() + «Undelete.txt»);
Исключение
ЗаписьЖурналаРегистрации(«Удаление помеченных объектов.»,
УровеньЖурналаРегистрации.Информация, , , «Не могу удалить выбранные объекты: » + ОписаниеОшибки());
Возврат;
КонецПопытки;
КонецПроцедуры
Не забывайте важные нюансы:
а) ничего не должно мешать выполнению Фонового Задания, проверяйте Модули объекта справочников и документов на предмет неинициализированных значений переменных (они могут быть определены в Толстом клиенте);
б) запускаться Фоновое задание должно под Полными правами (ну можно ещё сделать Роль «Программист» и наделить её всеми возможными галками);
в) желательно не ограничивать Фоновое Задание временем выполнения, если большая база, то поиск ссылок на удаляемый объект займет большое количество времени.
Пробуйте, ищите и у вас обязательно всё получится…..
Однако, не нравится запуск Контроля/Удаления сразу всех Помеченных объектов…
Может реализовать отбор пакетов по N (например 100 объектов)?
я сделал по очереди, мне кажется так удобнее
А если ссылка тоже помечена на удаление?
По правильному конечно нужно рекурсией до самого верха добраться и проверить все ссылки и ссылки ссылок на пометку на удаление. Если все помечены, то можно всю ветку удалять.
Но по времени исполнения будет не быстро.
(3) Finder_S, мне кажется, если эта зачистка работает по расписанию, то в конце концов любая ветка помеченных объектов удалится. Просто это будет выполнено в несколько проходов. Но по любому это лучше, чем вообще не чистить 😉
Времени нет самому писать. Чувак, выручил. От души )))))))
Большое спасибо за статью, воспользуюсь только наверно переделаю, по отдельному объекту, будет работать в фоне и по ночам
Посмотрел код, вроде грамотно. Универсальность обработки удаления помеченных на удаление не работает пока не удалишь ссылки на регистры сведений. Попробую у себя сделать.
🙂 Спасибо, очень пригодилось!!!
Век живи — век учись. Спасибо за статью.