К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как обратиться к реквизиту табличной части документа в 1С

Как обратиться к реквизиту табличной части документа в 1С: синтаксис для клиента и сервера, обход строк, типичные ошибки и примеры кода на встроенном языке.

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

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

Как устроено обращение к табличной части

Табличная часть документа встроена в объект и доступна как свойство с именем, заданным в конфигураторе (например, «Товары», «Услуги», «Оплата»). Это коллекция значений типа «ТабличнаяЧасть», каждая строка которой имеет тип «СтрокаТабличнойЧасти». Реквизиты строки доступны через точку по имени, указанному в метаданных.

Общая схема обращения выглядит так: Объект.ИмяТабличнойЧасти[Индекс].ИмяРеквизита. Индексация строк начинается с нуля. Если табличная часть пуста, обращение по индексу вызовет ошибку «Индекс находится за границами массива», поэтому перед доступом по индексу проверяйте количество строк методом Количество().

Обращение к реквизиту в модуле объекта и на сервере

В модуле объекта документа табличная часть доступна напрямую по имени, без указания ссылки или переменной. Это самый простой контекст: обработчики ПриЗаписи, ОбработкаПроведения, ПередЗаписью работают именно так.

// Чтение реквизита первой строки

Если Товары.Количество() > 0 Тогда

ЦенаПервойСтроки = Товары[0].Цена;

КонецЕсли;

// Изменение реквизита в цикле

Для Каждого СтрокаТовара Из Товары Цикл

СтрокаТовара.Сумма = СтрокаТовара.Цена * СтрокаТовара.Количество;

КонецЦикла;

Если код выполняется в общем модуле или вне по отношению к документу, сначала получают объект из ссылки методом ПолучитьОбъект(). Работа через объект требует прав на изменение и блокирует документ на время записи, поэтому для простого чтения данных предпочтительнее запрос.

ДокументОбъект = СсылкаНаДокумент.ПолучитьОбъект();

Для Каждого СтрокаТовара Из ДокументОбъект.Товары Цикл

Сообщить(СтрокаТовара.Номенклатура);

КонецЦикла;

Обращение к реквизиту в форме документа на клиенте

В управляемой форме документа объект доступен через реквизит формы (обычно Объект), а текущая строка табличной части — через свойство ТекущиеДанные элемента формы. Именно через ТекущиеДанные корректно работать в клиентских обработчиках событий таблицы: ПриИзменении, ПриНачалеРедактирования и других.

&НаКлиенте

Процедура ТоварыЦенаПриИзменении(Элемент)

ТекущиеДанные = Элементы.Товары.ТекущиеДанные;

Если ТекущиеДанные <> Неопределено Тогда

ТекущиеДанные.Сумма = ТекущиеДанные.Цена * ТекущиеДанные.Количество;

КонецЕсли;

КонецПроцедуры

Проверка на Неопределено обязательна: если пользователь вышел из строки или таблица пуста, ТекущиеДанные возвращает Неопределено, и обращение к реквизиту вызовет ошибку «Поле объекта не обнаружено». На клиенте также доступен обход коллекции: Для Каждого Строка Из Объект.Товары Цикл — это безопасно, так как данные формы уже находятся на клиенте.

Порядок действий в форме
  1. 1
    Определите контекст: клиентский обработчик или серверный
  2. 2
    На клиенте получите строку через Элементы.Товары.ТекущиеДанные
  3. 3
    Проверьте, что ТекущиеДанные не равны Неопределено
  4. 4
    Обратитесь к реквизиту строки через точку по имени из конфигуратора
  5. 5
    При необходимости пересчитайте зависимые реквизиты той же строки
  6. 6
    Проверьте результат, изменив значение в интерфейсе вручную

Обращение к реквизиту через запрос

Для чтения данных табличных частей большого числа документов запрос — единственный производительный способ. В тексте запроса табличная часть указывается через точку после имени документа: Документ.РеализацияТоваровУслуг.Товары. Реквизиты строки доступны как поля виртуальной таблицы.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Товары.Номенклатура КАК Номенклатура,

| Товары.Количество КАК Количество,

| Товары.Сумма КАК Сумма

|ИЗ

| Документ.РеализацияТоваровУслуг.Товары КАК Товары

|ГДЕ

| Товары.Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", СсылкаНаДокумент);

Выборка = Запрос.Выполнить().Выбрать();

Пока Выборка.Следующий() Цикл

Сообщить(Выборка.Номенклатура);

КонецЦикла;

Запрос работает только на сервере и только на чтение — изменить реквизит строки через запрос нельзя. Ссылка на сам документ в табличной части доступна как поле Ссылка, а номер строки — как поле НомерСтроки.

Сравнение способов доступа

Через объект (ПолучитьОбъект)

Подходит для изменения данных. Медленный при массовой обработке, блокирует документ, требует прав на изменение.

Через запрос

Подходит для чтения и анализа множества документов. Быстрый, но только на сервере и только чтение.

Через ТекущиеДанные формы

Подходит для интерактивной работы пользователя в форме. Не применим вне контекста формы.

Обращение по имени реквизита, заданному строкой

Иногда имя реквизита заранее неизвестно — например, при универсальной обработке произвольных документов. В этом случае используют обращение через квадратные скобки со строковым выражением: СтрокаТовара["Цена"]. Такой приём работает и для строк табличной части, и для самого объекта.

ИмяРеквизита = "Цена";

Для Каждого СтрокаТовара Из Объект.Товары Цикл

Значение = СтрокаТовара[ИмяРеквизита];

КонецЦикла;

Если реквизита с таким именем нет в метаданных, возникнет ошибка. Для проверки существования реквизита анализируют метаданные: Объект.Метаданные().ТабличныеЧасти.Товары.Реквизиты.Найти(ИмяРеквизита). Это особенно важно в универсальных механизмах обмена и печати, где состав документов заранее не фиксирован.

Типичные ошибки и как их избежать

Наиболее частая проблема — обращение Объект.Товары.Цена без указания строки. Платформа сообщит «Поле объекта не обнаружено (Цена)», потому что у коллекции нет такого свойства — оно есть только у строки. Вторая типичная ситуация — использование Элементы.Товары.ТекущаяСтрока вместо ТекущиеДанные: ТекущаяСтрока возвращает идентификатор строки (число), а не данные, и обратиться к реквизиту через него нельзя. По идентификатору строку получают методом Объект.Товары.НайтиПоИдентификатору(ТекущаяСтрока).

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

Типичные ошибки
01
Обращение Объект.Товары.Цена без строки — ошибка «Поле объекта не обнаружено», нужно указать строку: Объект.Товары[0].Цена
02
Использование ТекущаяСтрока вместо ТекущиеДанные — возвращается идентификатор, а не данные строки
03
Обращение Товары[0] без проверки Количество() — ошибка индекса на пустой табличной части
04
Вызов ПолучитьОбъект() на тонком клиенте — метод недоступен, логику нужно переносить на сервер
05
Изменение реквизита строки в запросе — запросы в 1С только читают данные

Как проверить корректность обращения

После написания кода проверьте три вещи: существование табличной части и реквизита в конфигураторе, наличие строк в коллекции и контекст выполнения кода. Быстрый способ отладки — вывести значения через Сообщить() или остановиться в отладчике и посмотреть структуру строки табличной части в табло.

Контрольные точки

Как проверить результат

Табличная часть в конфигураторе
Норма

Имя табличной части и реквизита совпадает с кодом посимвольно

Тревожный признак

Ошибка «Поле объекта не обнаружено» при выполнении

Наличие строк
Норма

Товары.Количество() больше нуля перед обращением по индексу

Тревожный признак

Ошибка «Индекс находится за границами массива»

ТекущиеДанные в форме
Норма

ТекущиеДанные не равны Неопределено, реквизит читается

Тревожный признак

Неопределено при пустой таблице или выходе из строки

В отладчике строка табличной части отображается со всеми её реквизитами и текущими значениями — это позволяет убедиться, что обращение идёт к нужному полю. Для серверного кода в фоновых заданиях используйте запись в журнал регистрации вместо Сообщить(), так как сообщения фонового задания пользователь не увидит.

Итог

Что важно запомнить

Реквизит табличной части всегда доступен только через строку: по индексу, в цикле или через ТекущиеДанные формы. Для чтения множества документов используйте запрос, для изменения — объект с обязательной записью. Проверяйте количество строк и существование ТекущихДанных перед обращением к реквизиту.

Частые вопросы

Как обратиться к реквизиту строки, если известен только её номер?

Номер строки в интерфейсе начинается с единицы, а индексация коллекции — с нуля. Обращение: Объект.Товары[НомерСтроки - 1].Цена. Перед доступом убедитесь, что номер не превышает Объект.Товары.Количество().

Можно ли обратиться к реквизиту табличной части другого документа?

Да, через ссылку на нужный документ: получите объект методом Ссылка.ПолучитьОбъект() и далее работайте с его табличной частью обычным способом. Для чтения без изменений эффективнее использовать запрос с отбором по ссылке.

Почему в форме недоступен ПолучитьОбъект() для текущего документа?

В управляемой форме данные документа уже загружены в данные формы, доступные через реквизит Объект. Дополнительный вызов ПолучитьОбъект() не нужен и на клиенте невозможен. Изменяйте Объект.Товары напрямую — при записи формы изменения попадут в базу.

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

Используйте метод НайтиСтроки() с структурой отбора: Строки = Объект.Товары.НайтиСтроки(Новый Структура("Номенклатура", ИскомаяНоменклатура)). Метод возвращает массив подходящих строк, у каждой доступны все реквизиты.

Чем отличается обращение в обычной форме от управляемой?

В обычной форме табличное поле связано с данными напрямую, и текущая строка доступна через ЭлементыФормы.Товары.ТекущиеДанные аналогично. Основное отличие — в управляемых формах действует разделение клиент/сервер и нет прямого доступа к объекту на клиенте в некоторых контекстах, поэтому серверная логика выносится в отдельные процедуры.

Как безопасно изменить реквизит во всех строках большого документа?

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