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