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