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