При разработке механизмов интеграции между различными конфигурациями «1С:Предприятие 8» программисты часто сталкиваются с необходимостью передачи связанных данных, например, справочников Номенклатура и ЕдиницыИзмерения. Основная сложность заключается не столько в самой передаче, сколько в правильной организации структуры данных, чтобы избежать избыточности и корректно восстановить связи в базе-приемнике. Разберем эту задачу подробно, проанализируем типичные ошибки и выработаем оптимальную стратегию реализации.
Рассмотрим ситуацию, представленную в исходном вопросе. Автор попытался получить данные одним запросом, используя ПОЛНОЕ СОЕДИНЕНИЕ. Проанализируем, к чему это приводит на практике. При соединении справочника Номенклатура со справочником ЕдиницыИзмерения по ссылке, мы получаем плоскую таблицу. Если у одной номенклатуры есть одна единица измерения, в таблице будет одна строка. Однако, если мы пытаемся выгрузить весь массив данных без четкой иерархии, мы получаем избыточность: наименование единицы измерения будет повторяться для каждой позиции номенклатуры, где она используется. Это увеличивает объем передаваемого трафика через веб-сервис, что критично для мобильных приложений.
Более того, использование ПОЛНОЕ СОЕДИНЕНИЕ без условий фильтрации может привести к появлению в выборке «одиноких» записей из обоих справочников, которые не связаны друг с другом, что окончательно запутает логику обработки в приемнике. Выясним, как сделать этот процесс более профессиональным.
Вместо того чтобы пытаться «склеить» всё в одну таблицу, мы можем использовать более элегантные подходы. Рассмотрим первый вариант: использование двух временных таблиц и левого соединения, чтобы гарантировать получение номенклатуры вместе с ее актуальными единицами измерения.
Проанализируем пример кода, который позволит подготовить данные правильно:
Функция ПолучитьДанныеДляВыгрузки() Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка КАК СсылкаНоменклатуры,
| Номенклатура.Наименование КАК НаименованиеНоменклатуры,
| Номенклатура.Цена КАК Цена,
| ЕдиницыИзмерения.Наименование КАК НаименованиеЕдиницы,
| ЕдиницыИзмерения.Ссылка КАК СсылкаЕдиницы
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ЕдиницыИзмерения КАК ЕдиницыИзмерения
| ПО Номенклатура.ЕдиницаИзмерения = ЕдиницыИзмерения.Ссылка";
РезультатЗапроса = Запрос.Выполнить();
Возврат Сериализовать(РезультатЗапроса.Выгрузить());
КонецФункции
Важный момент: если справочник ЕдиницыИзмерения является подчиненным справочнику Номенклатура, то в запросе обязательно нужно использовать связь по владельцу: ПО ЕдиницыИзмерения.Владелец = Номенклатура.Ссылка. Это гарантирует, что вы получите именно те единицы, которые принадлежат конкретной позиции.
Одной из главных ошибок при синхронизации является поиск элементов по наименованию. Рассмотрим ситуацию: в базе-источнике пользователь переименовал товар. Если в приемнике поиск идет по наименованию, система не найдет товар, создаст дубль, и у вас появится две карточки одного и того же товара с разными именами. Чтобы этого избежать, необходимо всегда передавать УникальныйИдентификатор (GUID).
При формировании данных на сервере добавим получение идентификатора:
СтрокаДанных.Идентификатор = Строка(Номенклатура.Ссылка.УникальныйИдентификатор());
В приемнике поиск будет выглядеть так:
Идентификатор = Новый УникальныйИдентификатор(ДанныеИзСети.GUID);
СсылкаНаЭлемент = Справочники.Номенклатура.ПолучитьСсылку(Идентификатор);
ОбъектНоменклатуры = СсылкаНаЭлемент.ПолучитьОбъект();
Если ОбъектНоменклатуры = Неопределено Тогда
ОбъектНоменклатуры = Справочники.Номенклатура.СоздатьЭлемент();
ОбъектНоменклатуры.УстановитьСсылкуНового(СсылкаНаЭлемент);
КонецЕсли;
Теперь разберем, как правильно загружать полученные данные. Проблема кода из вопроса в том, что создание элементов происходит безусловно, что порождает дубли при каждом нажатии кнопки. Нам нужно реализовать проверку существования. Рассмотрим алгоритм «Сначала ищем — потом обновляем или создаем».
Посмотрим на пример правильной обработки в цикле:
Пока Выборка.Следующий() Цикл
// 1. Сначала работаем с Единицей Измерения
СсылкаЕд = Справочники.ЕдиницыИзмерения.НайтиПоНаименованию(Выборка.НаименованиеЕдиницы);
Если СсылкаЕд.Пустая() Тогда
НоваяЕд = Справочники.ЕдиницыИзмерения.СоздатьЭлемент();
НоваяЕд.Наименование = Выборка.НаименованиеЕдиницы;
НоваяЕд.Записать();
СсылкаЕд = НоваяЕд.Ссылка;
КонецЕсли;
// 2. Теперь работаем с Номенклатурой
СсылкаНом = Справочники.Номенклатура.НайтиПоНаименованию(Выборка.НаименованиеНоменклатуры);
Если СсылкаНом.Пустая() Тогда
НоваяНом = Справочники.Номенклатура.СоздатьЭлемент();
Иначе
НоваяНом = СсылкаНом.ПолучитьОбъект();
КонецЕсли;
НоваяНом.Наименование = Выборка.НаименованиеНоменклатуры;
НоваяНом.Цена = Выборка.Цена;
НоваяНом.ЕдиницаИзмерения = СсылкаЕд; // Привязываем созданную/найденную единицу
НоваяНом.Записать();
КонецЦикла;
Проанализируем ситуацию с точки зрения скорости. Если в вашей выборке 1000 элементов, вызов метода Записать() 1000 раз приведет к 1000 открытий и закрытий транзакций в базе данных. Это крайне медленно, особенно на мобильных устройствах. Мы должны объединить запись в одну транзакцию.
Рассмотрим, как это реализовать:
НачатьТранзакцию();
Попытка
// Здесь располагается цикл загрузки (Шаг 3)
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
Сообщить("Ошибка при загрузке данных: " + ОписаниеОшибки());
КонецПопытки;
Хотя веб-сервисы в 1С традиционно работают через SOAP/XDTO, для мобильных приложений и легких интеграций мы рекомендуем использовать формат JSON. Он значительно компактнее и быстрее обрабатывается. Начиная с платформы 8.3.6, в 1С реализованы мощные инструменты: ЗаписьJSON и ЧтениеJSON. Передавая через веб-сервис строку в формате JSON, вы уменьшаете нагрузку на сеть и упрощаете десериализацию данных в мобильном приложении.
Подводя итог, проанализируем лучшие практики, которые помогут сделать ваш обмен надежным:
ПланыОбмена для регистрации только измененных объектов.УникальныйИдентификатор — единственный способ гарантировать целостность данных.Выполнив эти шаги, вы сможете создать надежную систему синхронизации данных, которая будет корректно обрабатывать связи между справочниками Номенклатура и ЕдиницыИзмерения, исключая дублирование и обеспечивая высокую скорость работы приложения.