В процессе эксплуатации информационных баз 1С часто возникает необходимость объединить или заменить повторяющиеся элементы справочников (например, дубли контрагентов, номенклатуры, договоров или организаций). Типовая интерактивная обработка поиска и удаления дублей не всегда подходит, если требуется применить сложные пользовательские условия отбора правильного элемента либо выполнить массовую замену в фоновом режиме по расписанию.
Разберем по шагам, какими способами можно реализовать быструю и безопасную замену ссылок во всех объектах конфигурации, как обойти типичные ошибки подписок на события и какие нюансы платформы необходимо учитывать.
В большинстве современных конфигураций (1С:ERP, 1С:Комплексная автоматизация, 1С:Управление торговлей, 1С:Бухгалтерия предприятия) заложена встроенная функциональность БСП. Чтобы не писать собственный сложный обход всех метаданных, мы можем воспользоваться методами общего модуля ПоискИУдалениеДублей.
Рассмотрим пример программной замены ссылок на сервере:
// Формируем массив замен
ПараметрыЗамены = Новый Массив;
// Каждая замена описывается структурой
СтрокаЗамены = Новый Структура;
СтрокаЗамены.Вставить("ОшибочныйЭлемент", СсылкаДубль);
СтрокаЗамены.Вставить("ПравильныйЭлемент", СсылкаОригинал);
ПараметрыЗамены.Добавить(СтрокаЗамены);
// Выполняем замену ссылок средствами БСП
ПоискИУдалениеДублей.ЗаменитьСсылки(ПараметрыЗамены);
Преимущество этого метода заключается в том, что он автоматически учитывает блокировки данных, права доступа, служебные связи и регистры сведений, сводя к минимуму риск повреждения ссылочной целостности информационной базы.
Если конфигурация не использует БСП или требуется реализовать полностью кастомную логику, мы можем использовать метод платформы НайтиПоСсылкам(). Проанализируем базовый алгоритм поиска ссылающихся объектов и их пакетной перезаписи:
Посмотрим на пример кода серверной процедуры:
&НаСервере
Процедура ЗаменитьСсылкуВБазе(СсылкаДубль, СсылкаОригинал)
МассивСсылок = Новый Массив;
МассивСсылок.Добавить(СсылкаДубль);
ТаблицаСсылок = НайтиПоСсылкам(МассивСсылок);
Для Каждого СтрокаСсылки Из ТаблицаСсылок Цикл
ОбъектСсылка = СтрокаСсылки.Данные;
МетаданныеОбъекта = ОбъектСсылка.Метаданные();
// Проверяем, является ли объект ссылочным типом для редактирования
Если ОбщегоНазначения.ЭтоДокумент(МетаданныеОбъекта)
Или ОбщегоНазначения.ЭтоСправочник(МетаданныеОбъекта) Тогда
Попытка
Объект = ОбъектСсылка.ПолучитьОбъект();
Если Объект = Неопределено Тогда
Продолжить;
КонецЕсли;
// Отключаем обработчики событий для ускорения и обхода проверок
Объект.ОбменДанными.Загрузка = Истина;
// Замена в реквизитах шапки
Для Каждого Реквизит Из МетаданныеОбъекта.Реквизиты Цикл
Если Объект[Реквизит.Имя] = СсылкаДубль Тогда
Объект[Реквизит.Имя] = СсылкаОригинал;
КонецЕсли;
КонецЦикла;
// Замена в табличных частях
Для Каждого ТЧ Из МетаданныеОбъекта.ТабличныеЧасти Цикл
Для Каждого СтрокаТЧ Из Объект[ТЧ.Имя] Цикл
Для Каждого РеквизитТЧ Из ТЧ.Реквизиты Цикл
Если СтрокаТЧ[РеквизитТЧ.Имя] = СсылкаДубль Тогда
СтрокаТЧ[РеквизитТЧ.Имя] = СсылкаОригинал;
КонецЕсли;
КонецЦикла;
КонецЦикла;
КонецЦикла;
Объект.Записать();
Исключение
ЗаписьЖурналаРегистрации("ЗаменаДублей", УровеньЖурналаРегистрации.Ошибка,,,
ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
При ручной замене ссылок важно помнить о поведении платформы при записи объектов:
ОбменДанными.Загрузка = Истина, движения документа в регистрах накопления и бухгалтерии автоматически не обновляются. Чтобы актуализировать движения, требуется либо выполнять перепроведение документа (что может изменить закрытые периоды), либо точечно переписывать наборы записей соответствующих регистров.При использовании сторонних обработок в режиме толстого клиента часто возникает ошибка: Ошибка при вызове метода контекста (ПолучитьОбъект): При подписке ... произошла ошибка. Метод обработчика события ... не найден.
Выясним причину: в современных конфигурациях на управляемых формах многие общие модули компилируются исключительно на сервере (снят признак «Клиент (обычное приложение)»). При запуске внешней обработки в обычном приложении подписки на события пытаются вызвать методы модулей, недоступных в текущем клиентском контексте.
Чтобы устранить эту проблему без редактирования конфигурации, применим следующие подходы:
/RunModeManagedApplication, где все операции с объектами базы происходят строго в серверном контексте &НаСервере.ФоновыеЗадания.Выполнить(). Фоновое задание всегда стартует на сервере, что гарантирует доступ ко всем серверным модулям и их подпискам.Попытка ускорить процесс заменой ссылок напрямую в таблицах SQL-сервера крайне опасна по следующим причинам:
УникальныйИдентификатор в виде бинарных данных binary(16) со специфической перестановкой байтов. Прямая вставка стандартного строкового GUID приведет к созданию некорректных битых ссылок.