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