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