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