Как организовать цикл по двум независимым таблицам (Магазины и Кассы) для загрузки данных в 1С?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В процессе разработки внешних обработок в среде 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда на форме присутствуют две или более табличные части, которые логически связаны между собой, но технически не имеют жестких ссылочных связей в структуре данных. Типичный пример из практики автоматизации розничной торговли: наличие таблицы Магазины и таблицы Кассы, где каждой строке первой таблицы соответствует определенная строка во второй.

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

Метод 1. Синхронная обработка по индексу строк

Если ваша бизнес-логика подразумевает, что таблицы заполняются строго параллельно (например, пользователь добавляет магазин в первую таблицу, а затем соответствующую ему кассу во вторую), мы можем применить обращение к строкам по их порядковому номеру (индексу). Этот метод является самым быстрым в реализации, так как не требует поиска ключей связи.

Рассмотрим пример реализации такого цикла:


КоличествоСтрок = Объект.Магазины.Количество();
Для Счетчик = 0 По КоличествоСтрок - 1 Цикл
    // Получаем строку из первой таблицы
    СтрокаМагазин = Объект.Магазины[Счетчик];
    ТекущийМагазин = СтрокаМагазин.Магазин;
    
    // Получаем строку из второй таблицы по тому же индексу
    Попытка
        СтрокаКасса = Объект.Касса[Счетчик];
        ТекущаяКасса = СтрокаКасса.Касса;
    Исключение
        // Обработка ситуации, если во второй таблице строк меньше
        Продолжить;
    КонецПопытки;
    
    // Выполняем загрузку данных для пары Магазин + Касса
    ЗагрузитьДанныеПоМагазину(ТекущийМагазин, ТекущаяКасса);
КонецЦикла;

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

Метод 2. Использование объекта «Соответствие» (Map)

Когда прямой индексной связи нет, а вложенный цикл (цикл в цикле) кажется неэффективным, на помощь приходит объект Соответствие. Это специальная коллекция в 1С, предназначенная для быстрого поиска значений по ключу. В нашем случае ключом будет выступать Магазин, а значением — Касса.

Разберем по шагам, как оптимизировать алгоритм:

  1. Сначала мы один раз перебираем таблицу касс и заполняем соответствие.
  2. Затем в основном цикле по магазинам просто "достаем" нужную кассу из коллекции.

// Шаг 1. Подготовка данных
КартаКасс = Новый Соответствие;
Для Каждого СтрКасса Из Объект.Касса Цикл
    // Предполагаем, что у кассы есть скрытый реквизит или связь
    КартаКасс.Вставить(СтрКасса.ВладелецМагазин, СтрКасса.Касса);
КонецЦикла;

// Шаг 2. Основной цикл
Для Каждого СтрМагазин Из Объект.Магазины Цикл
    ТекущаяКасса = КартаКасс.Получить(СтрМагазин.Магазин);
    
    Если ТекущаяКасса <> Неопределено Тогда
        // Логика загрузки
    КонецЕсли;
КонецЦикла;

Данный подход исключает квадратичную зависимость времени выполнения (N*M) и делает код гораздо более читаемым и производительным.

Метод 3. Связь через скрытый идентификатор (UUID)

Проанализируем ситуацию, упомянутую в обсуждении: использование uuid. Если при заполнении настроек или при открытии формы вы генерируете уникальный идентификатор для каждой пары "Магазин-Касса", это дает 100% гарантию правильного сопоставления даже при сортировках таблиц.

Вы можете добавить в обе табличные части колонку ИдентификаторСвязи (тип Строка или УникальныйИдентификатор). Сделайте её невидимой для пользователя (свойство Видимость = Ложь). При заполнении таблиц записывайте в них одинаковые значения ключа. Тогда поиск будет выглядеть так:


Для Каждого СтрМагазин Из Объект.Магазины Цикл
    ПараметрыОтбора = Новый Структура("ИдентификаторСвязи", СтрМагазин.ИдентификаторСвязи);
    НайденныеКассы = Объект.Касса.НайтиСтроки(ПараметрыОтбора);
    
    Если НайденныеКассы.Количество() > 0 Тогда
        ТекущаяКасса = НайденныеКассы[0].Касса;
        // Работаем с данными
    КонецЕсли;
КонецЦикла;

Метод 4. Особенности реализации для регламентных заданий

Выясним важную деталь: автор темы упомянул, что загрузка должна работать как регламентное задание. В этом случае мы сталкиваемся с ограничением — на сервере нет доступа к элементам формы (Элементы, СписокВыбора и прочее).

Если ваша логика сопоставления завязана на программном заполнении списков выбора на форме, ее необходимо перенести в Модуль объекта или в Общий модуль. Рассмотрим рекомендации по переносу:

Метод 5. Использование временных таблиц в запросе

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


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Магазины ИЗ &ТчМагазины КАК ТчМагазины;
    |ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Кассы ИЗ &ТчКассы КАК ТчКассы;
    |ВЫБРАТЬ
    |   ВТ_Магазины.Магазин,
    |   ВТ_Кассы.Касса
    |ИЗ
    |   ВТ_Магазины КАК ВТ_Магазины
    |ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Кассы КАК ВТ_Кассы
    |ПО ВТ_Магазины.Индекс = ВТ_Кассы.Индекс";

Запрос.УстановитьПараметр("ТчМагазины", Объект.Магазины.Выгрузить());
Запрос.УстановитьПараметр("ТчКассы", Объект.Касса.Выгрузить());

Результат = Запрос.Выполнить().Выбрать();
Пока Результат.Следующий() Цикл
    // Безопасная и быстрая загрузка данных
КонецЦикла;

Подведем итог: выбор метода зависит от архитектуры вашей обработки. Если таблицы жестко связаны по порядку — используйте индекс. Если таблицы независимы и могут сортироваться — используйте скрытые колонки-идентификаторы и объект Соответствие. Если же загрузка выполняется в фоне (регламентное задание) — переносите данные в запрос через временные таблицы.

← На главную