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

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

1С: как обратиться к табличной части объекта

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

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

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

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

Базовый синтаксис обращения к табличной части

Имя табличной части задаётся в конфигураторе в дереве метаданных объекта. Если у документа «РеализацияТоваровУслуг» есть табличная часть «Товары», то в коде она доступна как ДокументОбъект.Товары. Это коллекция значений типа «ТабличнаяЧасть», каждая строка которой имеет тип «СтрокаТабличнойЧасти».

К реквизитам строки обращаются через точку: Строка.Номенклатура, Строка.Цена, Строка.Сумма. У каждой строки также есть служебное свойство НомерСтроки — порядковый номер, начиная с единицы. Индексация коллекции при этом идёт с нуля: первая строка — Объект.Товары[0].

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

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

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

Сообщить(ПерваяСтрока.Количество);

Перед обращением по индексу всегда проверяйте, что табличная часть не пуста, иначе получите ошибку «Индекс находится за границами массива». Для этого используется метод Количество(): Если Объект.Товары.Количество() > 0 Тогда ... КонецЕсли;.

Перебор строк и чтение данных

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

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

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

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

КонецЦикла;

Если нужен доступ к строке по номеру или требуется менять порядок обхода, подходит цикл со счётчиком. Помните, что индекс начинается с нуля, а Количество() возвращает фактическое число строк, поэтому верхняя граница цикла — Количество() - 1.

Для Индекс = 0 По Объект.Товары.Количество() - 1 Цикл

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

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

КонецЦикла;

Для чтения данных без изменения объекта эффективнее запрос: он не блокирует объект целиком и работает быстрее на больших объёмах. Запрос к табличной части строится через точку после имени таблицы документа.

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

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

"ВЫБРАТЬ

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

| Товары.Количество,

| Товары.Сумма

|ИЗ

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

|ГДЕ

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

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

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

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

Сообщить(Строка(Выборка.Номенклатура) + ": " + Выборка.Количество);

КонецЦикла;

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

Чтобы изменить табличную часть, нужен объект, а не ссылка. Ссылка — это только идентификатор записи в базе; попытка обратиться Ссылка.Товары вернёт данные для чтения, но записать изменения через ссылку нельзя. Правильная последовательность: ПолучитьОбъект() → изменения → Записать().

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

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

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

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

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

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

// изменение существующей строки

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

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

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

// безопасное удаление — обход с конца

Для Индекс = 0 По ДокументОбъект.Товары.Количество() - 1 Цикл

СтрокаТовары = ДокументОбъект.Товары[ДокументОбъект.Товары.Количество() - 1 - Индекс];

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

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

КонецЕсли;

КонецЦикла;

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

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

В модуле формы документа данные объекта доступны через реквизит формы, обычно называемый Объект. Обращение выглядит так же: Объект.Товары, но важно понимать, что это данные формы, а не объект базы напрямую. В управляемых формах на клиенте доступен ограниченный набор методов, а серверные вызовы оформляются через директивы &НаСервере и &НаКлиенте.

&НаКлиенте

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

Итого = 0;

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

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

КонецЦикла;

Элементы.ИтогоСумма.Заголовок = "Итого: " + Итого;

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

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

&НаКлиенте

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

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

Если СтрокаТовары = Неопределено Тогда

Возврат;

КонецЕсли;

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

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

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

Поиск строк по условию

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

// поиск одной строки

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

Если СтрокаТовары = Неопределено Тогда

Сообщить("Позиция не найдена");

Иначе

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

КонецЕсли;

// поиск всех строк по отбору

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

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

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

// обработка найденных строк

КонецЦикла;

Метод НайтиСтроки() удобен для удаления: сначала собираете строки по отбору в массив, затем удаляете их в отдельном цикле — это решает проблему изменения коллекции во время обхода.

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

Обращение из внешней обработки и общего модуля

Из внешней обработки или общего модуля доступ к табличной части начинается с получения объекта по ссылке. Ссылку можно получить запросом, из параметра обработки или через Документы.ИмяДокумента.НайтиПоНомеру(). Дальше логика та же: объект, коллекция, строки.

Функция ПолучитьСуммуДокумента(СсылкаНаДокумент) Экспорт

Итого = 0;

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

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

"ВЫБРАТЬ

| ЕСТЬNULL(СУММА(Товары.Сумма), 0) КАК ИтогоСумма

|ИЗ

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

|ГДЕ

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

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

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

Если Выборка.Следующий() Тогда

Итого = Выборка.ИтогоСумма;

КонецЕсли;

Возврат Итого;

КонецФункции

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

Маршрут решения

Как выбрать действие

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

Проверка результата и ограничения

После записи объекта убедитесь, что изменения действительно попали в базу. Самый простой способ — открыть документ в пользовательском режиме и сверить строки табличной части с ожидаемыми. Программно можно перечитать данные запросом и сравнить количество строк и итоговые суммы.

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

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

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

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

Совпадает с ожидаемым числом добавленных или оставшихся строк

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

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

Значения реквизитов строк
Норма

Номенклатура, количество и суммы соответствуют заданным в коде

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

Пустые или старые значения — вероятно, не вызван Записать() или изменён не тот объект

Движения документа по регистрам
Норма

После перепроведения движения соответствуют новым строкам

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

Движения устарели — документ записан без проведения

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

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

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

Почему Объект.Товары[1] возвращает не первую строку?

Индексация коллекций во встроенном языке начинается с нуля. Первая строка — Объект.Товары[0], вторая — Объект.Товары[1]. При этом свойство НомерСтроки у первой строки равно единице, что часто вводит в заблуждение.

Как узнать имя табличной части, если конфигурация незнакомая?

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

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

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

Что делать, если при записи объекта возникает ошибка блокировки?

Документ открыт или изменяется другим пользователем либо фоновым заданием. Оберните запись в Попытка/Исключение, зафиксируйте проблемный документ и повторите обработку позже. При массовой обработке не прерывайте весь процесс из-за одной блокировки.

Чем отличается Найти() от НайтиСтроки() у табличной части?

Найти() возвращает первую подходящую строку или Неопределено и принимает значение и имя колонки. НайтиСтроки() принимает структуру отбора и возвращает массив всех строк, удовлетворяющих условию, — удобно для обработки и удаления нескольких строк.

Итог

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

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