Как загрузить значения из таблицы значений в табличную часть документа по совпадению ключевого поля?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки в системе 1С:Предприятие часто возникает задача частичного обновления данных в табличной части (ТЧ) документа на основе внешней таблицы значений (ТЗ). Например, когда мы получаем дополнительные сведения о сотрудниках из внешней базы (такой как ЗУП) и хотим обновить только конкретную колонку (например, ОстатокДней), не затрагивая остальные 20 реквизитов строки.

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

Способ 1. Использование метода НайтиСтроки в цикле

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

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


// Предположим, ТабОбщ — это наша ТЗ с данными, а Объект.Состав — ТЧ документа
СтруктураПоиска = Новый Структура("Сотрудник");

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

Обратите внимание, что мы используем вложенный цикл Для каждого СтрокаТЧ Из МассивНайденныхСтрок. Это критически важно, так как в табличной части документа может быть несколько строк с одним и тем же сотрудником. Если использовать просто МассивНайденныхСтрок[0], данные обновятся только в первой найденной строке, что может привести к логическим ошибкам в учете.

Способ 2. Оптимизация производительности через «Соответствие» (Map)

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

Этот подход работает быстрее, потому что поиск в Соответствие осуществляется по хеш-таблице за константное время. Разберем алгоритм:

  1. Создаем объект Соответствие.
  2. Заполняем его данными из ТЗ (ключ — сотрудник, значение — количество дней).
  3. Один раз обходим табличную часть документа и подставляем данные.

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

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

Важный нюанс: использование соответствия позволяет избежать вложенных циклов и значительно сократить время выполнения кода на больших объемах данных.

Способ 3. Индексация таблицы значений

Если вы все же предпочитаете использовать НайтиСтроки, но данных много, не забудьте про индексацию. В 1С объекты типа ТаблицаЗначений поддерживают создание индексов для ускорения поиска.

Перед началом поиска по таблице выполните команду: ТабОбщ.Индексы.Добавить("Сотрудник");. Это создаст внутренний индекс, и метод НайтиСтроки будет отрабатывать мгновенно. Однако помните, что для самих табличных частей (объектов типа ДанныеФормыКоллекция или ТЧ документа) программное создание индексов в рантайме недоступно, поэтому поиск "по документу" (как в способе 1) индексацию ТЧ использовать не будет.

Способ 4. Пакетное обновление через ЗаполнитьЗначенияСвойств

В ситуациях, когда имен колонок в ТЗ и ТЧ много и они совпадают (например, нужно перенести не только ОстатокДней, но и Подразделение, Должность и т.д.), вместо ручного присваивания каждой колонки целесообразно использовать метод ЗаполнитьЗначенияСвойств.

Проанализируем пример совмещения поиска и группового заполнения реквизитов:


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

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

Рекомендации при работе с внешними данными (ЗУП)

Как было отмечено в обсуждении, часто данные сопоставляются по уникальному идентификатору (УИД). При работе с методом ПолучитьСсылку(Новый УникальныйИдентификатор(СтрокаУИД)) будьте осторожны: если объекта с таким идентификатором в вашей базе нет, 1С создаст «пустую» или «битую» ссылку (Объект не найден).

Перед тем как использовать найденную по УИД ссылку в документе, рекомендуется проверить её наличие в базе с помощью метода Метаданные.НайтиПоПолномуИмени(...).ПустаяСсылка() или попыткой получения объекта. Если ваша база «самописная», как у автора темы, надежнее всего организовать поиск по дополнительному реквизиту, где хранится ИдентификаторЗУП, используя метод Справочники.Посетители.НайтиПоРеквизиту("ID_ZUP", ЗначениеИзТЗ).

Резюме

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

← На главную