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

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

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

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

Почему возникают ошибки при обновлении табличной части на клиенте/сервере формы

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

  1. Разница типов данных: Реквизит табличной части на управляемой форме представлен объектом ДанныеФормыКоллекция, а не объектом ТаблицаЗначений или ТабличнаяЧасть. У типа ДанныеФормыКоллекция нет метода Найти(), что приводит к ошибке выполнения. Для поиска по значению колонки у него реализован метод НайтиСтроки(), принимающий структуру отбора.
  2. Разрыв связи между выгруженной копией и формой: Если разработчик выполняет выгрузку данных в отдельную таблицу значений (Данные = РеквизитФормыВЗначение("Объект").Товары.Выгрузить()), любые изменения в переменной Данные происходят только в памяти и не отображаются в форме документа до тех пор, пока данные не будут явно загружены обратно.
  3. Неверная логика в ветке ИНАЧЕ: Попытка повторного поиска строки в ветке Иначе, когда строка уже была найдена до условия Если, либо обращение к методам не того объекта.

Способ 1. Прямая обработка коллекции формы через НайтиСтроки

Рассмотрим вариант, когда мы работаем напрямую с коллекцией формы Объект.Товары (тип ДанныеФормыКоллекция) без промежуточных выгрузок прикладного объекта. Этот способ удобен, если строк в таблице немного и мы выполняем операцию в контексте формы на сервере.

Посмотрим на пример кода:


// рез - ТаблицаЗначений, полученная из результата запроса: рез = Запрос.Выполнить().Выгрузить();

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

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

Способ 2. Обработка через Таблицу Значений с последующей загрузкой в реквизит формы

Если требуется выполнять поиск через быстрый метод Найти() или производить сложную манипуляцию с колонками, удобнее выгрузить данные формы в отдельную таблицу значений, обработать её в цикле, а затем загрузить обратно в табличную часть формы методом Загрузить().

Разберем по шагам реализацию этого способа:


// 1. Получаем таблицу с результатом запроса
рез = Запрос.Выполнить().Выгрузить();

// 2. Преобразуем объект формы в прикладной объект и выгружаем ТЧ в ТаблицуЗначений
Данные = РеквизитФормыВЗначение("Объект").Товары.Выгрузить();

// 3. Обходим результаты запроса и модифицируем ТЗ
Для Каждого Стр Из рез Цикл
    
    СтрокаТЗ = Данные.Найти(Стр.Номенклатура, "Номенклатура");
    
    Если СтрокаТЗ = Неопределено Тогда
        // Если номенклатура не найдена, создаем новую строку в ТЗ
        СтрокаТЗ = Данные.Добавить();
        СтрокаТЗ.Номенклатура = Стр.Номенклатура;
        СтрокаТЗ.КолФ = Стр.Количество;
    Иначе
        // Если найдена - просто обновляем значение количества
        СтрокаТЗ.КолФ = Стр.Количество;
    КонецЕсли;
    
КонецЦикла;

// 4. Загружаем измененную ТаблицуЗначений обратно в коллекцию формы
Объект.Товары.Загрузить(Данные);

Обратите внимание: Метод Объект.Товары.Загрузить() полностью очищает текущую коллекцию формы и заполняет её строками из переданной таблицы значений с совпадением имен колонок. Это исключает необходимость построчного удаления или ручного присвоения строк обратно в форму.

Способ 3. Оптимальный вариант: слияние данных на уровне запроса

Вместо перебора коллекций в цикле встроенного языка наиболее производительным и надежным подходом является объединение текущих данных формы и данных базы средствами СУБД с помощью временных таблиц.

Рассмотрим алгоритм решения:

  1. Выгружаем текущую табличную часть формы в ТаблицаЗначений.
  2. Передаем полученную таблицу в запрос в качестве параметра.
  3. Во временной таблице соединяем данные формы с таблицей документов/регистров через ПОЛНОЕ СОЕДИНЕНИЕ или ЛЕВОЕ СОЕДИНЕНИЕ.
  4. Выгружаем результат запроса и загружаем его обратно в форму одной командой Объект.Товары.Загрузить(РезультатЗапроса.Выгрузить()).

Такой подход избавляет от выполнения ресурсоемких циклов во встроенном языке 1С и гарантирует корректную обработку дублей строк.

Важные замечания и рекомендации

При реализации заполнения табличных частей обратите внимание на следующие нюансы:

  1. Проверка нового документа: Если в параметрах запроса используется Объект.Ссылка, убедитесь, что документ уже записан в базу данных. Для нового (еще не сохраненного) документа ссылка будет пустой, и запрос не вернет движений.
  2. Поиск ссылок в коде: Избегайте поиска складов и других справочников по наименованию (НайтиПоНаименованию("Основной склад")). Используйте предопределенные элементы, константы либо параметры настроек.
  3. Флаг модифицированности: Любое программное изменение данных в Объект.Товары при открытии формы приводит к тому, что документ считается измененным (устанавливается свойство Модифицированность = Истина). Если пользователю требуется только просмотр информации без принудительного сохранения документа, расчетные колонки следует делать реквизитами самой формы, а не табличной части документа.
← На главную