Разработка и Конфигурация · 13 мин
Как работать с объектом Соответствие в 1С
Как работать с объектом Соответствие в 1С: создание, методы Вставить, Получить, Удалить, обход в цикле, типичные ошибки и примеры кода на встроенном языке.
Соответствие в 1С — это универсальная коллекция пар «ключ — значение», аналог словаря или хэш-таблицы в других языках программирования. Разработчик использует его, когда нужно быстро находить данные по уникальному ключу: например, сопоставить контрагента его ИНН, номенклатуру — артикулу поставщика или сотрудника — табельному номеру.
Главное преимущество соответствия перед массивом и таблицей значений — скорость поиска. Доступ к значению по ключу выполняется практически мгновенно независимо от количества элементов, тогда как перебор таблицы значений в поисках нужной строки занимает время, пропорциональное её размеру. На больших объёмах данных это различие становится критичным.
Объект доступен и на клиенте, и на сервере, сериализуется при передаче между ними, поэтому его удобно использовать как контейнер для обмена данными внутри прикладного кода. В этой статье разобраны создание объекта, основные методы, обход в цикле, особенности ключей и типичные ошибки, которые приводят к потере данных.
Что такое Соответствие и когда его применять
Соответствие хранит неупорядоченный набор элементов, где каждый элемент состоит из ключа и связанного с ним значения. Ключом может быть значение практически любого типа: строка, число, дата, ссылка на объект базы данных, булево. Значением — тоже любой тип, включая другие коллекции, структуры и даже другие соответствия, что позволяет строить вложенные хранилища.
Типичные сценарии применения: кэширование результатов запроса для быстрого повторного доступа, сопоставление данных из разных источников при обмене, подсчёт количества вхождений (где ключ — само значение, а значение — счётчик), временное хранение настроек обработки. Если задача сводится к «по известному X быстро найти Y», соответствие почти всегда лучший выбор.
Когда соответствие не подходит: если важен порядок элементов (используйте массив или таблицу значений), если нужны индексируемые данные с сортировкой и итогами (таблица значений), если коллекцию нужно показать пользователю в форме напрямую (динамический список или таблица значений с реквизитом формы).
Создание объекта и добавление элементов
Объект создаётся конструктором Новый Соответствие. Добавление элементов выполняется методом Вставить(Ключ, Значение) либо прямым присваиванием через квадратные скобки. Оба варианта равнозначны по результату.
КэшКонтрагентов = Новый Соответствие;
// Два способа добавить элемент
КэшКонтрагентов.Вставить("7707083893", СсылкаНаКонтрагента);
КэшКонтрагентов["7710140679"] = ДругаяСсылка;
// Значением может быть структура
ДанныеКонтрагента = Новый Структура("Наименование, КПП", "ООО Ромашка", "770701001");
КэшКонтрагентов.Вставить("7707083893", ДанныеКонтрагента);
Обратите внимание на последний блок примера: повторная вставка с ключом «7707083893» не вызовет ошибки, а просто заменит ранее сохранённую ссылку на структуру. Это частый источник трудноуловимых ошибок — данные «пропадают» без каких-либо сообщений. Если нужно гарантировать уникальность, перед вставкой проверяйте наличие ключа методом Получить.
Чтение значений: Получить и обращение по ключу
Прочитать значение можно двумя способами: методом Получить(Ключ) или через квадратные скобки Соответствие[Ключ]. Различие проявляется, когда ключ отсутствует: Получить вернёт Неопределено, а обращение через скобки в большинстве режимов также вернёт Неопределено, однако считается менее явным стилем. Безопасная практика — использовать Получить и проверять результат.
НайденноеЗначение = КэшКонтрагентов.Получить(ИскомыйИНН);
Если НайденноеЗначение = Неопределено Тогда
// Ключа нет — выполняем запрос к базе и кэшируем результат
НайденноеЗначение = НайтиКонтрагентаПоИНН(ИскомыйИНН);
КэшКонтрагентов.Вставить(ИскомыйИНН, НайденноеЗначение);
КонецЕсли;
Приведённый шаблон «проверил кэш — не нашёл — вычислил — сохранил» — самый распространённый сценарий использования соответствия в прикладном коде. Он сокращает количество обращений к базе данных, когда одни и те же данные запрашиваются многократно, например при загрузке большого файла с тысячами строк.
Проверить само наличие ключа без извлечения значения можно сравнением результата Получить с Неопределено. Отдельного метода «СодержитКлюч» у соответствия нет, поэтому если Неопределено является допустимым хранимым значением, такая проверка неоднозначна — учитывайте это при проектировании структуры данных.
Обход соответствия в цикле
Перебор всех элементов выполняется конструкцией Для Каждого ... Из ... Цикл. Переменная цикла имеет тип КлючИЗначение и содержит два свойства: Ключ и Значение.
Для Каждого Элемент Из КэшКонтрагентов Цикл
Сообщить("ИНН: " + Элемент.Ключ + ", значение: " + Элемент.Значение);
КонецЦикла;
Порядок обхода соответствия не гарантирован и не совпадает с порядком добавления элементов. Если дальнейшая логика зависит от последовательности — например, вывод печатной формы или формирование файла, — сначала выгрузите ключи в массив или таблицу значений и отсортируйте их, либо изначально используйте упорядоченную коллекцию.
Удалять элементы непосредственно внутри цикла обхода нельзя — это приведёт к ошибке. Если нужно очистить часть элементов по условию, сначала соберите ключи для удаления в отдельный массив, а после завершения цикла пройдитесь по нему методом Удалить.
- 1Создайте пустой массив КлючиДляУдаления
- 2В цикле обхода соответствия добавляйте в массив ключи, подходящие под условие
- 3Завершите цикл обхода
- 4Во втором цикле по массиву вызовите Соответствие.Удалить(Ключ) для каждого ключа
- 5Проверьте итоговое значение Соответствие.Количество()
Удаление элементов и другие полезные методы
Метод Удалить(Ключ) удаляет элемент по ключу; если ключа нет, ошибки не возникает — операция просто ничего не делает. Метод Очистить() удаляет все элементы разом. Метод Количество() возвращает число элементов и используется для контроля заполненности.
| Метод | Назначение | Особенность |
|---|---|---|
Вставить(Ключ, Значение) | Добавить или заменить элемент | Перезаписывает существующий ключ без предупреждения |
Получить(Ключ) | Прочитать значение | Возвращает Неопределено, если ключа нет |
Удалить(Ключ) | Удалить элемент | Отсутствующий ключ не вызывает ошибку |
Очистить() | Удалить все элементы | Необратимо, копию нужно делать заранее |
Количество() | Число элементов | Удобно для проверки пустоты кэша |
Копирование соответствия — отдельная тема. Присваивание Копия = Оригинал не создаёт независимую коллекцию: обе переменные будут ссылаться на один и тот же объект, и изменение через одну отразится в другой. Для получения независимой копии создайте новое соответствие и перенесите элементы циклом, помня, что вложенные коллекции при этом скопируются по ссылке.
Особенности ключей и сравнение значений
Сравнение ключей выполняется по значению с учётом типа. Строка "123" и число 123 — это два разных ключа. Ссылка на объект базы данных сравнивается по уникальному идентификатору: две переменные, содержащие ссылку на один и тот же элемент справочника, образуют один и тот же ключ, что очень удобно при кэшировании по объектам.
Строковые ключи сравниваются без учёта регистра в рамках особенностей встроенного языка при использовании в некоторых контекстах, однако надёжнее не зависеть от этого: приводите ключи к единому виду перед вставкой и поиском. Рабочая практика — нормализовать строковые ключи функциями ВРег() и СокрЛП(), чтобы «ИНН001» и « инн001 » не порождали два разных элемента.
Значения любых типов хранятся без ограничений, но помните о сериализации: если соответствие передаётся между клиентом и сервером или помещается во временное хранилище, все вложенные значения должны быть сериализуемыми. Несериализуемые объекты (например, некоторые COM-объекты) вызовут ошибку при передаче.
Как выбрать коллекцию под задачу
Практический пример: кэш при загрузке данных
Объединим рассмотренное в законченный фрагмент — загрузку строк файла, где для каждой строки нужно найти номенклатуру по артикулу. Без кэша на десяти тысячах строк выполнится десять тысяч запросов; с соответствием количество запросов сократится до числа уникальных артикулов.
КэшНоменклатуры = Новый Соответствие;
Для Каждого СтрокаДанных Из ЗагружаемыеСтроки Цикл
Артикул = СокрЛП(СтрокаДанных.Артикул);
НоменклатураСсылка = КэшНоменклатуры.Получить(Артикул);
Если НоменклатураСсылка = Неопределено Тогда
НоменклатураСсылка = НайтиНоменклатуруПоАртикулу(Артикул); // запрос к базе
КэшНоменклатуры.Вставить(Артикул, НоменклатураСсылка);
КонецЕсли;
// Дальнейшая работа со ссылкой
КонецЦикла;
Проверить эффективность такого решения можно простым замером: выведите в журнал значение КэшНоменклатуры.Количество() после цикла и сравните с числом загруженных строк. Если строк сто тысяч, а элементов в кэше три тысячи — вы сэкономили девяносто семь тысяч обращений к базе.
В длительных фоновых загрузках кэш-соответствие растёт вместе с данными. Если обрабатываются миллионы уникальных ключей, следите за расходом памяти: иногда выгоднее периодически очищать кэш методом Очистить() или группировать данные так, чтобы повторные ключи шли подряд.
Проверка результата и отладка
Убедиться, что соответствие заполнено корректно, проще всего в отладчике: поставьте точку останова после цикла заполнения и добавьте переменную соответствия в табло — конфигуратор покажет все пары «ключ — значение». Программно содержимое выводится циклом обхода с Сообщить() или записью в журнал регистрации.
Как проверить корректность работы
Совпадает с числом уникальных ключей в исходных данных
Меньше ожидаемого — ключи дублируются или перезаписываются
Возвращается ожидаемое значение
Неопределено — ключ другого типа или с лишними пробелами
Кэш создаётся заново конструктором Новый
Накапливаются данные прошлых вызовов — объект не переинициализируется
Отдельно проверяйте граничные случаи: пустой ключ, ключ Неопределено, значения с начальными и конечными пробелами. Именно на таких данных соответствие чаще всего ведёт себя не так, как ожидал разработчик.
Частые вопросы
Чем Соответствие отличается от Структуры в 1С?
Структура имеет фиксированный набор именованных полей, известных на этапе написания кода, и обращение идёт через точку. Соответствие допускает произвольные динамические ключи любого типа, которые можно добавлять и удалять во время выполнения. Для передачи параметров с известными именами берите структуру, для динамического поиска по ключу — соответствие.
Сохраняется ли порядок элементов при обходе соответствия?
Нет, порядок обхода не гарантирован и не связан с порядком добавления. Если последовательность важна, выгрузите ключи в массив или таблицу значений, отсортируйте и обращайтесь к соответствию по отсортированным ключам.
Можно ли использовать ссылку на элемент справочника как ключ?
Да, это один из самых удобных сценариев. Ссылки сравниваются по уникальному идентификатору, поэтому две переменные, указывающие на один объект базы, образуют один ключ. Так строят кэши вида «контрагент → договор по умолчанию».
Что вернёт Получить, если ключа нет в соответствии?
Метод вернёт Неопределено, ошибки не будет. Поэтому результат всегда проверяют сравнением с Неопределено перед использованием, иначе дальше по коду возникнет ошибка обращения к свойствам пустого значения.
Как скопировать соответствие, чтобы копия была независимой?
Простое присваивание копирует только ссылку на тот же объект. Создайте новое соответствие и перенесите элементы циклом: НовоеСоответствие.Вставить(Элемент.Ключ, Элемент.Значение). Учтите, что вложенные коллекции при этом останутся общими — для глубокого копирования их тоже нужно копировать рекурсивно.
Можно ли передать соответствие с сервера на клиент?
Да, соответствие сериализуется при передаче между клиентом и сервером и помещении во временное хранилище. Ограничение одно: все вложенные значения должны быть сериализуемыми типами, иначе при передаче возникнет ошибка.
Что важно запомнить
Соответствие — коллекция пар «ключ — значение» с мгновенным поиском. Создаётся через Новый Соответствие, заполняется методом Вставить, читается через Получить с проверкой на Неопределено. Ключи уникальны и чувствительны к типу, порядок обхода не гарантирован, присваивание копирует ссылку, а не данные.