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

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

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

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

Табличная часть в 1С — это коллекция строк, привязанная к объекту: документу, справочнику или обработке. Каждая строка содержит набор реквизитов, и задача «получить значение реквизита» сводится к двум шагам: сначала добраться до нужной строки, затем прочитать у неё нужное поле. Способ обращения зависит от контекста: объектная модель на сервере, данные формы на клиенте или выборка запросом.

Чаще всего обращение выглядит так: Документ.Товары[0].Номенклатура — здесь Товары — имя табличной части, [0] — индекс первой строки (нумерация с нуля), Номенклатура — имя реквизита. Но на практике почти никогда не известен точный индекс нужной строки, поэтому применяют перебор, поиск по значению или запрос.

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

Обращение к строке по индексу

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

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

ПерваяСтрока = Объект.Товары[0];

Товар = ПерваяСтрока.Номенклатура;

Количество = ПерваяСтрока.Количество;

КонецЕсли;

Обязательно проверяйте, что табличная часть не пуста, прежде чем обращаться по индексу. Обращение к Товары[0] при пустой коллекции вызовет ошибку «Индекс находится за границами массива». Это одна из самых частых ошибок новичков.

Последнюю строку удобно получать выражением Объект.Товары[Объект.Товары.Количество() - 1]. Если строка только что добавлена методом Добавить(), метод возвращает ссылку на неё, и обращаться по индексу не нужно:

НоваяСтрока = Объект.Товары.Добавить();

НоваяСтрока.Номенклатура = ВыбранныйТовар;

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

Перебор всех строк циклом

Когда нужно обработать все значения реквизита — например, просуммировать суммы или собрать список номенклатуры — используют цикл Для Каждого:

ИтогоСумма = 0;

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

ИтогоСумма = ИтогоСумма + СтрокаТовары.Сумма;

КонецЦикла;

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

Для выборочной обработки внутри цикла ставят условие. Например, собрать количество только по строкам с конкретным складом:

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

Если СтрокаТовары.Склад = ОсновнойСклад Тогда

ОбщееКоличество = ОбщееКоличество + СтрокаТовары.Количество;

КонецЕсли;

КонецЦикла;

Поиск строки по значению реквизита

Если известно значение одного из реквизитов, строку находят методом Найти(). Метод возвращает строку или Неопределено, если совпадений нет:

НайденнаяСтрока = Объект.Товары.Найти(ИскомыйТовар, "Номенклатура");

Если НайденнаяСтрока <> Неопределено Тогда

ЦенаТовара = НайденнаяСтрока.Цена;

КонецЕсли;

Второй параметр — строка с именем реквизита или нескольких реквизитов через запятую. Проверка на Неопределено обязательна: обращение к реквизиту несуществующей строки вызовет ошибку.

Когда совпадений может быть несколько, применяют НайтиСтроки() со структурой отбора — метод возвращает массив строк:

Отбор = Новый Структура("Склад", ОсновнойСклад);

СтрокиСклада = Объект.Товары.НайтиСтроки(Отбор);

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

// обработка каждой найденной строки

КонецЦикла;

Сравнение способов получения значения

По индексу [N]

Быстро, но требует проверки Количество(); подходит, когда позиция строки известна

Цикл Для Каждого

Для обработки всех строк; читаемый код, но полный проход коллекции

Найти() / НайтиСтроки()

Когда известно значение реквизита; требует проверки на Неопределено

Запрос

Для выборки из базы без чтения всего объекта; оптимален при больших табличных частях

Получение значения в управляемой форме

На клиенте в управляемой форме объектная модель недоступна — работа идёт с данными формы. Текущую строку таблицы получают через элемент формы:

&НаКлиенте

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

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

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

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

КонецЕсли;

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

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

Если требуется строка по её идентификатору (например, из Элементы.Товары.ТекущаяСтрока), применяют Объект.Товары.НайтиПоИдентификатору(Идентификатор). Помните: ТекущаяСтрока — это числовой идентификатор, а не индекс и не сама строка.

Получение значения запросом

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

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

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

"ВЫБРАТЬ

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

| СУММА(Товары.Сумма) КАК Сумма

|ИЗ

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

|ГДЕ

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

|СГРУППИРОВАТЬ ПО

| Товары.Номенклатура";

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

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

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

// Выборка.Номенклатура, Выборка.Сумма

КонецЦикла;

Запрос — единственный разумный вариант, когда нужно собрать значения реквизитов табличных частей сразу по многим документам, например для отчёта. Перебор объектов через ПолучитьОбъект() в цикле в таких задачах работает на порядки медленнее и нагружает сервер.

Если нужна только сумма по колонке табличной части, не пишите цикл — используйте встроенный метод Итог(): Объект.Товары.Итог("Сумма"). Это короче и быстрее ручного накопления.
ПЗ
Практическое замечание

Частые ошибки и как их проверить

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

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

Типичные ошибки
01
Обращение Товары[0] без проверки Количество() — ошибка индекса на пустой табличной части
02
Использование результата Найти() без проверки на Неопределено — падение при отсутствии строки
03
Путаница ТекущаяСтрока (идентификатор) и индекс строки — обращение не к той строке
04
Опечатка в имени реквизита в строковом параметре Найти() — ошибка только в момент выполнения
05
Чтение объектов в цикле вместо запроса — сильное падение производительности
Контрольные точки

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

Значение в отладчике
Норма

Переменная содержит ожидаемое значение нужного типа

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

Неопределено или значение другого типа

Поведение на пустой табличной части
Норма

Код отрабатывает без ошибок, результат пустой или ноль

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

Ошибка «Индекс за границами»

Поиск несуществующего значения
Норма

Найти() вернул Неопределено, ветка обработки сработала

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

Аварийное завершение при обращении к реквизиту

FAQ

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

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

Чем отличается НомерСтроки от индекса строки?

Индекс используется для обращения Товары[Индекс] и начинается с нуля. Свойство НомерСтроки — видимый пользователю номер, начинается с единицы. Связь: НомерСтроки = Индекс + 1.

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

Используйте метод ВыгрузитьКолонку("Номенклатура") — он вернёт массив значений указанного реквизита из всех строк. Для дальнейшей обработки массив можно свернуть или передать в запрос.

Почему Найти() возвращает Неопределено, хотя строка точно есть?

Чаще всего несовпадение типов или значений: ссылка сравнивается со строкой, лишние пробелы в строковом реквизите, разный регистр. Проверьте в отладчике точное значение реквизита в строках и тип искомого значения.

Можно ли получить значение реквизита табличной части по ссылке, не открывая объект?

Да, только через запрос к таблице Документ.ИмяДокумента.ИмяТабличнойЧасти с отбором по Ссылка. Прямое обращение Ссылка.Товары недоступно — у ссылки нет табличных частей, только реквизиты шапки.

Итог

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

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