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

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

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

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

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

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

Материал охватывает оба контекста — серверный и клиентский, а также типичные ошибки, из-за которых обращение к табличной части возвращает пустую коллекцию или вызывает исключение.

Как устроена табличная часть и где взять её имя

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

Каждая строка табличной части — это структурированное значение с полями-реквизитами. У строки есть служебное свойство НомерСтроки (нумерация с единицы) и реквизиты, определённые в конфигураторе: Номенклатура, Количество, Цена и т.д. Обращение к реквизиту строки выполняется через точку: Строка.Количество.

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

Классический сценарий — серверный код в модуле объекта, внешней обработке или процедуре «НаСервере». Сначала получают объект (например, Документы.РеализацияТоваровУслуг.СоздатьДокумент() или Ссылка.ПолучитьОбъект()), затем обращаются к табличной части по имени.

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

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

Сообщить("Строка " + СтрокаТовара.НомерСтроки

+ ": " + СтрокаТовара.Номенклатура

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

КонецЦикла;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

КонецЕсли;

КонецЦикла;

Для полной очистки есть метод Очистить(): ДокОбъект.Товары.Очистить();. Он быстрее поэлементного удаления и не требует цикла.

Поиск нужной строки в табличной части

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

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

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

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

Иначе

// строки нет — добавляем новую

КонецЕсли;

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

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

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

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

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

КонецЦикла;

Работа с табличной частью на форме

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

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

&НаКлиенте

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

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

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

Возврат;

КонецЕсли;

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

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

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

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

Табличные части в запросах

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

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

|ГДЕ

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

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

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

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

Результат = Запрос.Выполнить().Выгрузить();

В запросе у строк табличной части есть поле Ссылка — ссылка на документ-владелец, по нему и ставят отбор. Такой подход в разы быстрее при обработке сотен документов и не требует записи объектов.

Способы чтения табличной части

Перебор через объект

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

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

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

НайтиСтроки на форме

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

Типичные ошибки и как их избежать

Самая частая проблема — обращение по синониму вместо имени. Если в конфигураторе табличная часть называется «Товары», а вы пишете Объект.СписокТоваров, получите ошибку «Поле объекта не обнаружено». Всегда сверяйте имя в дереве метаданных.

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

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

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

Как проверить, что код отработал правильно

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

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

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

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

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

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

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

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

Обязательные реквизиты строк
Норма

Номенклатура, количество и цена заполнены, суммы сходятся

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

Пустые ссылки или нулевые суммы — строка добавлена, но реквизиты не заполнены

Проведение документа
Норма

Документ проводится без ошибок, движения корректны

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

Ошибка проведения или неверные движения — проверьте заполнение строк

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

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

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

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

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

Почему НайтиСтроки возвращает пустой массив, хотя строка точно есть?

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

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

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

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

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

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

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

Итог

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

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