При выполнении запросов к табличным частям документов начинающие разработчики часто сталкиваются с ситуацией: запрос успешно выбирает нужные данные, однако попытка изменить значения прямо в выборке запроса не дает результата. Рассмотрим, почему это происходит и как правильно получать и редактировать строки табличных частей документов в платформах 1С.
Выясним причину этой проблемы. Результат выполнения запроса (и создаваемая из него выборка) представляет собой независимый набор данных в памяти, предназначенный исключительно для чтения. Выборка запроса не содержит прямой ссылки на строки табличной части в базе данных. Ссылка в выборке ссылается лишь на сам документ в целом.
Чтобы внести изменения в табличную часть документа, необходимо сначала получить его объект (экземпляр типа ДокументОбъект), модифицировать требуемую строку в коллекции и затем записать документ.
Рассмотрим наиболее популярный способ поиска и редактирования строки. Сначала получаем ссылку на документ, затем вызываем метод ПолучитьОбъект() и производим поиск по ключевым колонкам табличной части с помощью метода НайтиСтроки().
Разберем по шагам пример кода:
// 1. Формируем запрос для поиска документов
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| РеализацияТоваровУслуг.Ссылка КАК Ссылка
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
| РеализацияТоваровУслуг.Номер = &Номер";
Запрос.УстановитьПараметр("Номер", "О-ИП0016647");
Выборка = Запрос.Выполнить().Выбрать();
// 2. Обходим результаты и модифицируем объект
Пока Выборка.Следующий() Цикл
ДокОбъект = Выборка.Ссылка.ПолучитьОбъект();
// Подготавливаем отбор по ключевому полю (например, Номенклатура)
Отбор = Новый Структура("Номенклатура", Справочники.Номенклатура.НайтиПоКоду("С-000000788"));
НайденныеСтроки = ДокОбъект.Товары.НайтиСтроки(Отбор);
Если НайденныеСтроки.Количество() > 0 Тогда
// Редактируем первую найденную строку
СтрокаТЧ = НайденныеСтроки[0];
СтрокаТЧ.Количество = 123;
КонецЕсли;
// Записываем измененный объект
ДокОбъект.Записать();
КонецЦикла;
Проанализируем другой эффективный вариант. Если в запросе к табличной части мы уже выбрали поле НомерСтроки, нет необходимости повторно выполнять поиск через НайтиСтроки(). Достаточно обратиться к коллекции строк объекта по индексу.
Обратите внимание: нумерация строк в табличных частях 1С начинается с 1, а индексация элементов в коде — с 0. Поэтому индекс строки рассчитывается как НомерСтроки - 1.
Посмотрим на следующий пример:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Табель.Ссылка КАК Ссылка,
| Табель.НомерСтроки КАК НомерСтроки,
| Табель.Сотрудник КАК Сотрудник
|ИЗ
| Документ.ТабельУчетаРабочегоВремениОрганизации.ОтработанноеВремя КАК Табель
|ГДЕ
| Табель.Ссылка = &Ссылка";
Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Количество() > 0 Тогда
ДокОбъект = СсылкаНаДокумент.ПолучитьОбъект();
Пока Выборка.Следующий() Цикл
// Получаем строку прямо по индексу
Индекс = Выборка.НомерСтроки - 1;
ТекущаяСтрока = ДокОбъект.ОтработанноеВремя[Индекс];
// Меняем реквизиты строки
ТекущаяСтрока.Часов = 8;
КонецЦикла;
ДокОбъект.Записать();
КонецЕсли;
Если задача выполняется непосредственно на форме документа (управляемой или обычной) и вам нужно изменить строку, с которой в данный момент работает пользователь, получать объект через запрос не требуется.
В этом случае работа происходит через элементы формы и реквизит формы:
Элементы.ОтработанноеВремя.ТекущиеДанные.ЭлементыФормы.ОтработанноеВремя.ТекущиеДанные.Пример изменения строки на форме:
ТекущаяСтрока = Элементы.ОтработанноеВремя.ТекущиеДанные;
Если ТекущаяСтрока <> Неопределено Тогда
ТекущаяСтрока.Часов = 8;
КонецЕсли;
Разберем важные рекомендации по написанию чистого и производительного кода при работе с табличными частями:
Для Каждого СтрокаТЧ Из ДокОбъект.ОтработанноеВремя Цикл ... КонецЦикла; без выполнения лишних запросов.ДокОбъект.ОбменДанными.Загрузка = Истина; перед вызовом Записать().