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