Коллекция Соответствие в 1С: создание, методы и применение при обмене данными

· 9 мин

Содержание

Соответствие в 1С создают оператором Новый Соответствие — это коллекция пар «ключ — значение», где по ключу любого типа мгновенно получают связанное с ним значение. Заполняют её методом Вставить(Ключ, Значение), читают через Получить(Ключ) или квадратные скобки Соотв[Ключ], обходят циклом Для Каждого … Из … Цикл.

Чаще всего соответствие нужно, когда по одному значению надо быстро находить другое: по коду товара — ссылку на номенклатуру, по ГУИДу объекта из другой базы — ссылку в своей, по коду валюты — курс. При обмене данными между базами именно соответствие хранит сопоставление «объект источника → объект приёмника». Ниже — синтаксис, методы и рабочие примеры.

Что такое соответствие и чем оно отличается от массива

Соответствие — это универсальная коллекция встроенного языка. Внутри неё лежат пары: у каждой есть ключ и значение. Ключ уникален — двух одинаковых ключей в одной коллекции быть не может.

Главное отличие от массива: в массиве вы обращаетесь к элементу по числовому индексу (Массив[0]), а в соответствии — по ключу любого типа. Ключом может быть строка, число, дата, булево, ссылка на объект, значение перечисления.

Это даёт прямой доступ по смысловому ключу без перебора. Чтобы в массиве найти нужный элемент, вы пишете цикл и сравниваете каждый. В соответствии то же самое — одна строка Соотв.Получить(Ключ), причём скорость почти не зависит от размера коллекции.

Простой критерий выбора: нужен список по порядку — берите массив. Нужен поиск «по чему-то» — берите соответствие.

Как создать соответствие и заполнить его вручную

Пустое соответствие создаётся в одну строку:

Соотв = Новый Соответствие;

Дальше его наполняют парами. Метод Вставить принимает два параметра — ключ и значение:

КурсыВалют = Новый Соответствие;
КурсыВалют.Вставить("USD", 92.5);
КурсыВалют.Вставить("EUR", 99.8);
КурсыВалют.Вставить("CNY", 12.7);

Если вставить пару с ключом, который уже есть, старое значение заменится новым — ошибки не будет. Это удобно для накопления: можно смело перезаписывать.

Читают значение двумя способами. Через метод Получить:

Курс = КурсыВалют.Получить("USD"); // 92.5

Или через квадратные скобки — результат тот же:

Курс = КурсыВалют["EUR"]; // 99.8

Если запрошенного ключа в соответствии нет, оба варианта вернут Неопределено, а не вызовут ошибку. Это принципиальное отличие от структуры, и на нём строится большинство проверок.

Удаление пары — метод Удалить(Ключ), полная очистка — Очистить(), число пар — Количество():

КурсыВалют.Удалить("CNY");
Всего = КурсыВалют.Количество(); // 2

Перебор идёт по парам «ключ — значение». В цикле каждый элемент — это объект типа КлючИЗначение с двумя свойствами: Ключ и Значение.

Для Каждого Пара Из КурсыВалют Цикл
    Сообщить(Пара.Ключ + ": " + Пара.Значение);
КонецЦикла;

Порядок обхода соответствия не гарантирован — он не совпадает с порядком вставки. Если важен порядок, сортируйте отдельно или используйте таблицу значений.

Чтобы проверить наличие ключа, сравнивают результат Получить с Неопределено:

Если КурсыВалют.Получить("GBP") = Неопределено Тогда
    // такого ключа нет
КонецЦикла;

Есть тонкость: если вы специально храните в соответствии значения Неопределено, проверка Получить(Ключ) = Неопределено соврёт — она не отличит «ключа нет» от «ключ есть, но значение пустое». В таком случае проверяйте наличие через обход или храните вместо Неопределено другой маркер.

Соответствие, структура и другие коллекции: что когда применять

У встроенного языка несколько похожих коллекций, и их часто путают. Разница в типе ключа и в поведении при обращении к несуществующему элементу.

КоллекцияКлюч / индексНет элементаКогда брать
Массивчисло (индекс)ошибка по индексуупорядоченный перечень значений
Соответствиелюбой типвозвращает Неопределенопоиск значения по произвольному ключу
Структуратолько строка-идентификаторошибка (нужен Свойство())фиксированный набор именованных полей
Таблица значенийстрока + колонки—табличные данные с несколькими полями

Ключевые выводы из таблицы:

  • 📌 Структура хранит именованные поля и обращается к ним через точку (Стр.Сумма). Ключом служит только строковый идентификатор, а запрос несуществующего поля через скобки вызывает ошибку — наличие проверяют методом Свойство().
  • 📌 Соответствие принимает ключ любого типа и при отсутствии ключа молча отдаёт Неопределено. Это делает его безопаснее для поиска.
  • 📌 Если на каждый ключ приходится не одно значение, а несколько полей, соответствие не подойдёт — берите таблицу значений или соответствие, где значением выступает структура.

Частый приём: значением соответствия делают структуру или другое соответствие. Так получают «двумерный» справочник — например, по ключу «склад» лежит соответствие «товар → остаток».

Как заполнить соответствие из запроса или выборки

Вручную соответствие заполняют редко. На практике его собирают из результата запроса — чтобы потом быстро находить данные без повторных обращений к базе.

Типичная задача: получить соответствие «номенклатура → остаток». Сначала запрос, затем выгрузка результата в цикл:

Запрос = Новый Запрос;
Запрос.Текст =
    "ВЫБРАТЬ Номенклатура, КоличествоОстаток
    |ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки";

Выборка = Запрос.Выполнить().Выбрать();

ОстаткиПоТоварам = Новый Соответствие;
Пока Выборка.Следующий() Цикл
    ОстаткиПоТоварам.Вставить(Выборка.Номенклатура, Выборка.КоличествоОстаток);
КонецЦикла;

После этого остаток любого товара достаётся мгновенно: ОстаткиПоТоварам[ТекущийТовар]. Это и есть главный смысл соответствия — один проход по данным, а дальше сколько угодно быстрых обращений по ключу.

Тот же шаблон применяют для кэширования ссылок: собрали соответствие «код → ссылка» один раз, и в большом цикле обработки документов не дёргаете базу на каждой строке.

Когда у ключа несколько измерений, соответствие вкладывают одно в другое. Остаток по паре «склад + товар» удобно хранить как соответствие складов, в котором значением лежит соответствие товаров:

Остатки = Новый Соответствие;
Пока Выборка.Следующий() Цикл
    ПоТоварам = Остатки.Получить(Выборка.Склад);
    Если ПоТоварам = Неопределено Тогда
        ПоТоварам = Новый Соответствие;
        Остатки.Вставить(Выборка.Склад, ПоТоварам);
    КонецЕсли;
    ПоТоварам.Вставить(Выборка.Номенклатура, Выборка.КоличествоОстаток);
КонецЦикла;

Теперь остаток достаётся по двум ключам: сначала берут вложенное соответствие по складу, затем значение по товару.

ПоСкладу = Остатки.Получить(ТекущийСклад);
Остаток = ?(ПоСкладу = Неопределено, 0, ПоСкладу.Получить(ТекущийТовар));

Проверка на Неопределено на каждом уровне обязательна: если склад в данных не встретился, вложенного соответствия не будет, и прямое обращение к нему оборвёт код.

Как соответствие используют при обмене данными между базами

В выгрузках и загрузках соответствие решает центральную задачу обмена — сопоставление объектов источника и приёмника. У объекта в одной базе своя ссылка, в другой — своя. Чтобы при повторной загрузке не плодить дубли, нужно знать, какому объекту-источнику какой объект уже соответствует.

Как это устроено на практике:

  1. При загрузке объект ищут по уникальному признаку — коду, ИНН, артикулу или ГУИДу (УникальныйИдентификатор ссылки).
  2. Найденную или вновь созданную ссылку кладут в соответствие: ключ — идентификатор из источника, значение — ссылка в своей базе.
  3. Когда в выгрузке встречается ссылка на этот же объект (например, товар в табличной части документа), его ссылку в приёмнике берут прямо из соответствия, а не ищут в базе заново.
СопоставлениеОбъектов = Новый Соответствие;

// при обработке объекта-источника
СсылкаПриёмника = НайтиИлиСоздать(ОбъектИсточника);
СопоставлениеОбъектов.Вставить(ОбъектИсточника.Идентификатор, СсылкаПриёмника);

Ключ при сопоставлении по ГУИДу удобнее хранить строкой. Уникальный идентификатор ссылки получают методом УникальныйИдентификатор(), а в ключ кладут его строковое представление — так ключ из источника и ключ при поиске заведомо одного типа:

КлючИсточника = Строка(ОбъектИсточника.Ссылка.УникальныйИдентификатор());
СопоставлениеОбъектов.Вставить(КлючИсточника, СсылкаПриёмника);

Если в одном месте положить ключом сам идентификатор (тип УникальныйИдентификатор), а искать по строке, соответствие их не свяжет — вернётся Неопределено. Одинаковый тип ключа на запись и на чтение здесь критичен.

Если обмен идёт порциями или в несколько проходов, соответствие, собранное в памяти, живёт только внутри одного вызова. Долговременное сопоставление между сеансами хранят в регистре сведений или в самих ссылках плана обмена, а соответствие используют как быстрый кэш внутри одной обработки.

В типовых механизмах (планы обмена, правила конвертации) сопоставление объектов платформа ведёт сама. Соответствие в собственном коде пишут там, где обмен нестандартный: разовая загрузка из файла, интеграция с внешней системой через код, перенос данных обработкой.

Частые ошибки при работе с соответствием

Разберём, что идёт не так и как чинить. Проблемы почти всегда в типе ключа или в предположении, что ключ точно есть.

Диагностика: выберите симптом

Как посмотреть содержимое соответствия при отладке

Увидеть, что реально лежит в коллекции, помогает отладчик. Поставьте точку останова и наведите курсор на переменную — во всплывающей подсказке или в окне «Табло» соответствие раскрывается по парам ключ — значение.

Быстрый способ без отладчика — вывести пары в сообщения:

Для Каждого Пара Из Соотв Цикл
    Сообщить("" + Пара.Ключ + " = " + Пара.Значение);
КонецЦикла;

Если нужно только убедиться, что коллекция не пустая, достаточно Соотв.Количество(). Ноль означает, что цикл заполнения не отработал или запрос вернул пусто — проверяйте источник данных, а не само соответствие.

Когда значением соответствия служит структура или ещё одно соответствие, в «Табло» разворачивайте вложенный узел — платформа покажет всю иерархию.

Когда пригодится фиксированное соответствие

Если коллекцию нужно только читать и защитить от случайного изменения, используют неизменяемый вариант — ФиксированноеСоответствие. Его создают на основе обычного:

Справочник = Новый ФиксированноеСоответствие(Соотв);

После этого методы Вставить и Удалить недоступны — попытка изменить вызовет ошибку. Читается фиксированное соответствие точно так же: Справочник[Ключ], Справочник.Получить(Ключ), обход циклом.

Такой вариант передают в параметры формы, в структуру настроек, в кэш общих модулей — везде, где значение должно оставаться неизменным на всё время жизни.

Частые вопросы

Чем соответствие отличается от структуры простыми словами?
У структуры ключ — только строка-идентификатор, доступ через точку, а запрос несуществующего поля даёт ошибку. У соответствия ключ любого типа, а отсутствие ключа возвращает Неопределено. Структура — для фиксированного набора именованных полей, соответствие — для поиска по произвольному ключу.
Можно ли использовать ссылку на объект как ключ?
Да. Ссылка на элемент справочника, документ или значение перечисления — корректный ключ. На этом строят кэши «ссылка → данные» в обработках и обменах.
Сохраняется ли порядок добавления пар?
Нет. Порядок обхода соответствия не определён и может не совпадать с порядком вставки. Нужен порядок — выгружайте пары в таблицу значений и сортируйте.
Как превратить соответствие в таблицу значений?
Прямого метода нет. Создают таблицу с колонками «Ключ» и «Значение», перебирают пары в цикле и добавляют строки методом Добавить(). После этого таблицу можно сортировать и отбирать.
Есть ли ограничение на число пар в соответствии?
Жёсткого лимита на количество пар нет — коллекция живёт в оперативной памяти, поэтому практический потолок задаёт объём памяти сеанса. Для миллионов строк уместнее временная таблица или регистр, а не соответствие в памяти.
Чем соответствие помогает при обмене данными?
Оно хранит сопоставление объектов источника и приёмника: по идентификатору из другой базы мгновенно отдаёт ссылку в своей. Это убирает дубли и повторные поиски по базе внутри одной обработки обмена.