При работе с инструментом Конвертация данных 2.0 разработчики часто сталкиваются с ситуацией, когда при загрузке данных в информационную базу-приемник необходимо выполнить дополнительные программные действия. Одной из типичных задач является перенос контактной информации из регистров сведений в табличные части объектов (например, контрагентов или физических лиц). Однако выполнение этого кода в обработчике ПриЗагрузке может привести к ошибке «Объект недоступен для изменения». Рассмотрим причины возникновения этой проблемы и разберем по шагам, как правильно реализовать алгоритм заполнения данных.
Разберем ситуацию, когда в правилах конвертации объектов (ПКО) для справочника Контрагенты используется обработчик события ПриЗагрузке. В этом обработчике вызывается алгоритм, который должен считать данные из старого регистра сведений и программно заполнить табличную часть КонтактнаяИнформация загружаемого объекта. Ошибка Ошибка при вызове метода контекста (Добавить): Объект недоступен для изменения на позиции выполнения метода Объект.КонтактнаяИнформация.Добавить() чаще всего сигнализирует о том, что программа пытается изменить объект, состояние которого не предполагает наличие или модификацию данной табличной части.
Проанализируем основные причины этой ошибки:
Контрагенты) группы и элементы имеют разную структуру. Часто на уровне метаданных табличные части определены только для элементов. Если при обмене загружается группа, попытка обратиться к её табличной части или вызвать метод Добавить() вызовет исключение.ПриЗагрузке объект уже инициализирован, его свойства заполнены из XML-файла, но он еще не записан в базу данных. Для нового объекта ссылка (Объект.Ссылка) может быть пустой, что также накладывает ограничения при использовании запросов внутри обработчика.Как показывает практика и обсуждение на форуме, наиболее частой причиной является именно попытка обработки групп справочника. Выясним причину: при выгрузке контрагента «за собой» он часто тянет структуру папок, в которых находится. Обработчик срабатывает для каждого объекта, включая эти папки.
Для исправления ситуации необходимо добавить проверку свойства ЭтоГруппа. Рассмотрим пример модифицированного кода внутри обработчика или алгоритма:
// Проверяем, что объект существует и не является группой
Если Объект <> Неопределено Тогда
// Если справочник иерархический, прерываем выполнение для групп
Попытка
Если Объект.ЭтоГруппа Тогда
Возврат;
КонецЕсли;
Исключение
// Если у объекта нет свойства ЭтоГруппа, продолжаем выполнение
КонецПопытки;
// Далее следует основной код алгоритма
// ...
НоваяСтрока = Объект.КонтактнаяИнформация.Добавить();
// Заполнение свойств строки
КонецЕсли;
Использование блока Попытка...Исключение при проверке на группу полезно, если один и тот же алгоритм используется для разных типов объектов (например, для физических лиц, где иерархии может не быть, и для контрагентов).
Проанализируем ситуацию глубже. Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), то простого добавления строк в табличную часть КонтактнаяИнформация может быть недостаточно. В современных версиях 1С за отображение и хранение КИ отвечает сложный механизм, использующий скрытые поля и формат XML/JSON в реквизите ЗначенияПолей.
Рассмотрим, что нужно учесть при программном добавлении КИ:
Представление и поля 1-10, при открытии карточки в базе-приемнике данные могут не отобразиться или «слететь». Система ожидает структурированную строку в формате XML/JSON.УправлениеКонтактнойИнформацией.КонтактнаяИнформацияВXML().Посмотрим на пример заполнения строки с учетом специфики БСП:
НоваяСтрока = Объект.КонтактнаяИнформация.Добавить();
НоваяСтрока.Тип = Выборка.Тип;
НоваяСтрока.Вид = СоответствиеВидовКИ[Выборка.Вид];
НоваяСтрока.Представление = Выборка.Представление;
// Формируем структуру для адреса, если это адрес
Если Выборка.Тип = Перечисления.ТипыКонтактнойИнформации.Адрес Тогда
// Здесь должна быть логика формирования XML строки через компоненты КИ
// В упрощенном виде для старых систем можно заполнять поля:
НоваяСтрока.Поле1 = Выборка.Поле1; // Индекс
НоваяСтрока.Поле2 = Выборка.Поле2; // Регион
// ... и так далее
КонецЕсли;
В представленном автором коде используется Новый Запрос внутри обработчика, который выполняется для каждого загружаемого объекта. Если вам нужно загрузить 10 000 контрагентов, система выполнит 10 000 отдельных обращений к базе данных, что катастрофически замедлит обмен.
Разберем, как оптимизировать этот процесс:
ПередЗагрузкойДанных (на уровне всей обработки обмена) можно один раз выполнить запрос ко всему регистру УдалитьКонтактнаяИнформация и выгрузить результат в ТаблицуЗначений или Соответствие.Параметры.Вставить("ТаблицаКИ", ВашаТаблица).ПриЗагрузке не делайте запрос, а используйте метод НайтиСтроки() или поиск по соответствию в подготовленной таблице. Поиск в оперативной памяти выполняется в десятки раз быстрее, чем запрос к БД.Одной из главных трудностей автора было отсутствие возможности пройтись отладчиком по коду. Выясним, как это сделать правильно. Код обработчиков в универсальном обмене выполняется через функцию Выполнить(), поэтому обычные точки останова в конфигураторе не сработают.
Порядок действий для настройки отладки:
УниверсальныйОбменДаннымиXML.ПереносКИ).Объект, Ссылка и ЭтоГруппа.Подведем итог: при программном изменении объектов в процессе обмена данными всегда проверяйте тип объекта (элемент или группа) и учитывайте особенности конфигурации-приемника в части хранения специальных данных, таких как контактная информация. Это позволит избежать блокировок и обеспечит целостность загружаемых данных.