При разработке механизмов обмена данными между конфигурациями 1С, особенно если одной из баз является «Управление производственным предприятием» (УПП), программисты часто сталкиваются с трудностями при переносе единиц измерения. Использование Application (COM-соединения) добавляет свои нюансы в части типизации объектов и работы с запросами. Разберем подробно, почему возникают ошибки при заполнении единиц измерения и как их правильно решать.
Первая и самая важная причина, по которой реквизиты могут оставаться пустыми при переносе — это архитектурная особенность хранения единиц измерения в УПП и схожих конфигурациях. Проанализируем ситуацию: в карточке номенклатуры есть два принципиально разных реквизита:
КлассификаторЕдиницИзмерения. Здесь хранятся общероссийские стандарты (штуки, килограммы, метры).ЕдиницыИзмерения, который является подчиненным справочнику Номенклатура.В документах, таких как «Перемещение товаров», реквизит ЕдиницаИзмерения в табличной части ожидает ссылку именно на подчиненный справочник ЕдиницыИзмерения. Если мы попытаемся напрямую присвоить значение из классификатора в поле, предназначенное для подчиненного справочника, система либо выдаст ошибку, либо (в случае COM-соединения) просто запишет пустое значение из-за несоответствия типов. Посмотрим на типичную ошибку в коде:
// ОШИБОЧНЫЙ ПОДХОД
НоваяСтрока.ЕдиницаИзмерения = НоваяСтрока.Номенклатура.БазоваяЕдиницаИзмерения;
// Здесь происходит попытка записи элемента Классификатора в поле Справочника
Для того чтобы получить правильную ссылку, нам необходимо найти в подчиненном справочнике ЕдиницыИзмерения тот элемент, который соответствует базовой единице из классификатора. Для этого в базе-источнике (или базе-приемнике, в зависимости от логики обмена) нужно выполнить запрос. Рассмотрим, как правильно инициализировать объекты через COM-соединение.
Частая ошибка начинающих разработчиков — использование локального конструктора Новый для создания запроса, который должен выполниться во внешней базе. Разберем правильный синтаксис:
// Правильное создание объекта Запрос во внешней базе
Запрос = БазаИсточник.NewObject("Запрос");
// Если написать "Запрос = Новый Запрос",
// объект будет создан в текущей базе и не увидит таблицы внешней базы
Проанализируем структуру запроса, который поможет нам найти нужную единицу измерения для конкретной номенклатуры:
Запрос = БазаИсточник.NewObject("Запрос");
Запрос.Текст =
"ВЫБРАТЬ
| ЕдиницыИзмерения.Ссылка КАК ЕдИзм
|ИЗ
| Справочник.ЕдиницыИзмерения КАК ЕдиницыИзмерения
|ГДЕ
| ЕдиницыИзмерения.Владелец = &Номенклатура
| И ЕдиницыИзмерения.ЕдиницаПоКлассификатору = &БазоваяЕдиница";
Запрос.УстановитьПараметр("Номенклатура", НоменклатураСсылкаCOM);
Запрос.УстановитьПараметр("БазоваяЕдиница", НоменклатураСсылкаCOM.БазоваяЕдиницаИзмерения);
Результат = Запрос.Выполнить().Выгрузить();
Многие разработчики жалуются, что при просмотре результата запроса в отладчике они видят лишь надпись COMОбъект и не могут понять, выбралось ли что-то на самом деле. Выясним, как проверить содержимое таких объектов.
Когда вы получаете данные через COM, вы работаете с прокси-объектами. Чтобы увидеть их реальное значение в табло отладчика, используйте следующие приемы:
БазаИсточник.String(Результат[0].ЕдИзм).Результат[0].ЕдИзм.Наименование или Результат[0].ЕдИзм.Код.Результат.Количество().Если Результат.Количество() > 0, но после присвоения НоваяСтрока.ЕдиницаИзмерения = Результат[0].ЕдИзм поле остается пустым, убедитесь, что вы не забыли вызвать метод Записать() для объекта документа. В интерфейсе изменения могут не отобразиться до момента фактической записи объекта в базу данных.
Выполнение запроса для каждой строки документа через COM-соединение — это крайне ресурсоемкая операция. Каждый вызов метода через COM требует времени на пересылку данных между процессами. Если в документе сотни строк, обмен будет «зависать».
Рассмотрим более эффективный алгоритм совместной работы:
Соответствие для быстрого поиска в памяти текущего сеанса.Пример получения данных одним пакетом:
ЗапросВсехЕдиниц = БазаИсточник.NewObject("Запрос");
ЗапросВсехЕдиниц.Текст =
"ВЫБРАТЬ
| ЕдиницыИзмерения.Владелец КАК Номенклатура,
| ЕдиницыИзмерения.Ссылка КАК СсылкаНаЕдИзм
|ИЗ
| Справочник.ЕдиницыИзмерения КАК ЕдиницыИзмерения
|ГДЕ
| ЕдиницыИзмерения.Владелец В (&МассивНоменклатуры)
| И ЕдиницыИзмерения.ЕдиницаПоКлассификатору = ЕдиницыИзмерения.Владелец.БазоваяЕдиницаИзмерения";
ЗапросВсехЕдиниц.УстановитьПараметр("МассивНоменклатуры", МассивСсылокCOM);
ТаблицаЕдиниц = ЗапросВсехЕдиниц.Выполнить().Выгрузить();
В сложных случаях, когда базы сильно различаются или запросы не отрабатывают из-за особенностей прав доступа, можно использовать поиск по GUID. Этот метод считается наиболее надежным при синхронизации данных.
Посмотрим на пример логики:
// Получаем GUID единицы в одной базе
УникальныйИдентификаторСтрокой = БазаИсточник.String(ЕдиницаСсылка.УникальныйИдентификатор());
// Находим этот же объект в другой базе
НужнаяСсылка = Справочники.ЕдиницыИзмерения.ПолучитьСсылку(Новый УникальныйИдентификатор(УникальныйИдентификаторСтрокой));
Этот способ гарантирует, что вы работаете с конкретным объектом, независимо от его представления или иерархии в справочнике. Однако помните, что для этого объекты в обеих базах должны иметь одинаковые UUID, что обычно достигается при правильной первоначальной синхронизации данных.
Подводя итог, при работе с единицами измерения в УПП через COM-соединение, всегда проверяйте соответствие типов (Классификатор vs Справочник) и используйте методы внешней базы для создания объектов запросов. Это позволит избежать пустых колонок и обеспечит корректность ведения складского учета в целевой базе.