При интеграции двух информационных баз 1С с использованием COM-соединения (OLE) разработчики нередко сталкиваются с ситуацией: при попытке заполнить реквизит создаваемого объекта возникает исключение «Ошибка при установке значения атрибута контекста». При этом простые текстовые поля (например, стандартное Наименование) заполняются корректно, а на поле с полным наименованием процесс аварийно прерывается. Разберем по шагам, почему возникает эта ошибка и какими способами её можно обойти.
Проанализируем механику работы платформы «1С:Предприятие». Для объектов метаданных СправочникОбъект, СправочникСсылка, а также для планов видов характеристик в платформе существует встроенный системный метод ПолноеНаименование(). Данная функция возвращает строку, содержащую наименование элемента вместе со всеми вышестоящими родительскими группами через косую черту.
Когда разработчик выполняет прямое присвоение через внешнее соединение:
НовыйОбъект.ПолноеНаименование = лЗначение;
// или обращение по индексу:
НовыйОбъект["ПолноеНаименование"] = лЗначение;
Встроенный язык и COM-интерфейс выполняют поиск идентификатора в контексте объекта. В силу правил разрешения имен приоритет отдается стандартному системному методу платформы. Попытка записать значение в функцию приводит к невозможности изменения контекста и генерации ошибки времени выполнения.
Согласно стандартам разработки фирмы «1С», реквизитам объектов запрещено давать имена, совпадающие со свойствами и методами платформы. Именно поэтому во всех типовых конфигурациях («1С:ERP», «1С:Комплексная автоматизация», «1С:Управление торговлей», «1С:Бухгалтерия предприятия») реквизит для развернутого описания номенклатуры называется НаименованиеПолное. Имя ПолноеНаименование обычно встречается в специализированных решениях (например, «1С:Управляющий») либо в нетиповых конфигурациях.
Выясним точное имя реквизита в подключаемой информационной базе. Чаще всего разработчик по привычке пишет ПолноеНаименование, тогда как в структуре конфигурации реквизит объявлен как НаименованиеПолное.
Чтобы код интеграции работал надежно с разными конфигурациями, реализуем предварительную проверку состава метаданных подключаемой базы:
ИмяРеквизита = "";
МетаРеквизиты = OLEБаза.Метаданные.Справочники[ИмяСправочника].Реквизиты;
Если МетаРеквизиты.Найти("НаименованиеПолное") <> Неопределено Тогда
ИмяРеквизита = "НаименованиеПолное";
ИначеЕсли МетаРеквизиты.Найти("ПолноеНаименование") <> Неопределено Тогда
ИмяРеквизита = "ПолноеНаименование";
КонецЕсли;
Если ИмяРеквизита = "НаименованиеПолное" Тогда
НовыйОбъект.НаименованиеПолное = лЗначение;
КонецЕсли;
Если в удаленной базе реквизит называется НаименованиеПолное, прямое присвоение выполняется без ошибок.
Если в удаленной базе реквизит действительно назван разработчиками ПолноеНаименование, прямое обращение через точку или квадратные скобки всегда будет вызывать коллизию с методом платформы. В этом случае используем системную процедуру ЗаполнитьЗначенияСвойств, вызванную в контексте внешней базы.
Разберем реализацию этого обхода:
Структура на стороне OLE-подключения с помощью метода NewObject.ПолноеНаименование и передаем необходимое значение.ЗаполнитьЗначенияСвойств внешней базы, передавая целевой объект справочника и созданную структуру.Посмотрим на пример программного кода:
// Создаем структуру в контексте удаленной базы
лСтруктура = OLEБаза.NewObject("Структура");
лСтруктура.Вставить("ПолноеНаименование", лЗначение);
// Заполняем реквизиты объекта без прямого обращения к свойству через точку
OLEБаза.ЗаполнитьЗначенияСвойств(НовыйОбъект, лСтруктура);
// Записываем элемент в удаленной базе
НовыйОбъект.Записать();
Механизм ЗаполнитьЗначенияСвойств обращается напрямую к реквизитам объекта метаданных, игнорируя интерфейсные методы, благодаря чему значение успешно записывается в базу.
Если имеется доступ к изменению конфигурации подключаемой базы, наиболее надежным архитектурным решением является вынос логики заполнения в модуль объекта или менеджер справочника.
Добавим в модуль менеджера справочника удаленной базы экспортную процедуру:
Процедура ЗаполнитьРеквизитыНоменклатуры(ОбъектНоменклатуры, СтруктураДанных) Экспорт
ЗаполнитьЗначенияСвойств(ОбъектНоменклатуры, СтруктураДанных);
КонецПроцедуры
На стороне внешней базы останется лишь вызвать этот метод через менеджер справочника, передав ссылку на созданный объект и данные для заполнения. Это полностью исключает влияние внешнего COM-маршалинга на обращение к реквизитам.
При организации обмена через COM-соединение обратим внимание на следующие правила:
V83.COMConnector, а не V83.Application. Внешнее соединение работает быстрее, расходует меньше оперативной памяти и не запускает пользовательский интерфейс, что исключает блокировку процесса модальными окнами.ПолноеНаименование, Уровень, Метаданные, Ссылка).