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

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

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

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

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

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

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

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

Самый распространённый сценарий — работа с табличной частью в модуле объекта документа или в обработке, где документ уже получен как объект. В этом случае табличная часть доступна напрямую по имени:

// В модуле объекта документа табличная часть доступна напрямую

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

Сообщить("Номенклатура: " + СтрокаТовары.Номенклатура

+ ", количество: " + СтрокаТовары.Количество);

КонецЦикла;

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

ДокументСсылка = Документы.РеализацияТоваровУслуг.НайтиПоНомеру("0001", ТекущаяДата());

// Чтение через ссылку — допустимо

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

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

КонецЦикла;

// Для изменения — получаем объект

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

ДокументОбъект.Товары[0].Количество = 5;

ДокументОбъект.Записать();

Обращение к табличной части в модуле формы

В управляемой форме документа данные представлены реквизитом формы типа «ДанныеФормыСтруктура», обычно он называется Объект. Табличная часть доступна через него как коллекция ДанныеФормыКоллекция:

&НаКлиенте

Процедура ПересчитатьИтоги(Команда)

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

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

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

КонецЦикла;

Сообщить("Итого по документу: " + ИтогСумма);

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

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

&НаКлиенте

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

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

Если ТекущаяСтрока = Неопределено Тогда

Возврат;

КонецЕсли;

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

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

Обратите внимание: проверка на Неопределено обязательна. Если табличная часть пуста или строка не выбрана, ТекущиеДанные вернёт именно это значение, и обращение к реквизиту строки вызовет ошибку.

Перебор, поиск и фильтрация строк табличной части

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

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

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

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

// Поиск одной строки по точному совпадению

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

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

Сообщить("Найдена строка № " + НайденнаяСтрока.НомерСтроки);

КонецЕсли;

// Поиск всех строк, подходящих под условие

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

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

Для Каждого СтрокаТЧ Из НайденныеСтроки Цикл

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

КонецЦикла;

Метод Найти() возвращает первую подходящую строку или Неопределено. Метод НайтиСтроки() всегда возвращает массив — пустой, если совпадений нет. В структуре отбора можно указать несколько полей, тогда условия объединяются по «И».

Порядок действий
  1. 1
    Определите, откуда выполняется код: модуль объекта, форма или внешняя обработка
  2. 2
    Если есть только ссылка и нужно изменение — получите объект методом ПолучитьОбъект()
  3. 3
    Обратитесь к табличной части по её имени из конфигуратора: Объект.Товары
  4. 4
    Используйте Найти() для одной строки или НайтиСтроки() для выборки по условию
  5. 5
    После изменений вызовите Записать() и проверьте результат в форме документа

Добавление, изменение и удаление строк

Для добавления строки используется метод Добавить(), который возвращает созданную строку. Дальше реквизиты строки заполняются обычным присваиванием:

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

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

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

НоваяСтрока.Цена = 1500;

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

Удалить строку можно двумя способами: методом Удалить() с указанием строки или индекса, либо полной очисткой табличной части методом Очистить(). При удалении в цикле есть важный нюанс: нельзя удалять строки из коллекции, по которой идёт перебор «Для Каждого» — это приведёт к пропуску строк или ошибке. Правильный подход — перебор с конца по индексу:

// Безопасное удаление строк по условию — с конца коллекции

ВсегоСтрок = Объект.Товары.Количество();

Для Инд = 1 По ВсегоСтрок Цикл

СтрокаТЧ = Объект.Товары[ВсегоСтрок - Инд];

Если СтрокаТЧ.Количество = 0 Тогда

Объект.Товары.Удалить(СтрокаТЧ);

КонецЕсли;

КонецЦикла;

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

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

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

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

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

"ВЫБРАТЬ

| РеализацияТовары.Номенклатура КАК Номенклатура,

| СУММА(РеализацияТовары.Количество) КАК Количество

|ИЗ

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

|ГДЕ

| РеализацияТовары.Ссылка.Дата МЕЖДУ &НачалоПериода И &КонецПериода

| И РеализацияТовары.Ссылка.Проведен

|

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

| РеализацияТовары.Номенклатура";

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

Запрос работает только на чтение. Если по результатам запроса нужно изменить документы, получайте объект каждого документа в цикле и модифицируйте его табличную часть, как описано выше.

Сравнение вариантов

Цикл по объекту

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

Запрос к табличной части

Оптимален для чтения и агрегации по многим документам. Не позволяет изменять данные и вызывать методы объекта

НайтиСтроки() на объекте

Удобен для фильтрации строк внутри одного документа. Работает только с уже загруженной табличной частью

Работа с несколькими табличными частями и обход по имени

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

// Перебор всех табличных частей документа через метаданные

Для Каждого ТабличнаяЧасть Из ДокументОбъект.Метаданные().ТабличныеЧасти Цикл

ИмяТЧ = ТабличнаяЧасть.Имя;

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

// обработка строки

КонецЦикла;

КонецЦикла;

Обращение через квадратные скобки ДокументОбъект["Товары"] эквивалентно обращению через точку, но позволяет подставлять имя из переменной. Это удобно в универсальных процедурах, куда имя табличной части передаётся параметром.

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

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

Количество строк после обработки
Норма

Объект.Товары.Количество() совпадает с ожидаемым числом

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

Строк меньше или больше — проверьте логику удаления и добавления

Сохранение изменений
Норма

После Записать() и повторного открытия документа изменения на месте

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

Изменения пропали — вероятно, работали со ссылкой или забыли Записать()

Итоги по документу
Норма

Суммы в строках и итог документа сходятся с контрольными значениями

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

Расхождения — проверьте пересчёт сумм и налогов после изменения строк

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

Как обратиться к табличной части, если у меня есть только ссылка на документ?

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

Почему возникает ошибка «Поле объекта не обнаружено» при обращении к табличной части?

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

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

У каждой строки есть свойство НомерСтроки — оно заполняется автоматически и начинается с единицы. Индекс же в коллекции начинается с нуля, поэтому для первой строки НомерСтроки = 1, а индекс равен 0. Если нужен индекс имеющейся строки, используйте метод Объект.Товары.Индекс(СтрокаТЧ).

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

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

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

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

Чем отличается Выгрузить() от НайтиСтроки() для табличной части?

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

Итог

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

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