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

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

Как записать данные в табличную часть в 1С

Как записать данные в табличную часть документа или справочника в 1С: методы Добавить, Загрузить, Записать, примеры кода, типичные ошибки и проверка результата.

Табличная часть — это встроенная в документ или справочник коллекция строк: список товаров в накладной, начисления сотрудника, этапы заказа. Записать в неё данные можно интерактивно (руками в форме) или программно — через встроенный язык 1С. Программная запись нужна при загрузке данных из файлов, обмене между базами, автоматическом заполнении документов по остаткам или заказам.

Главное, что нужно понять: табличная часть не существует отдельно от объекта-владельца. Нельзя записать строки «Товары», не записав сам документ «Реализация товаров и услуг». Поэтому любой сценарий сводится к трём шагам: получить объект, заполнить коллекцию строк, вызвать метод Записать() у объекта.

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

Как устроена табличная часть и что нужно знать перед записью

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

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

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

Добавление строк методом Добавить()

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

НовыйДок = Документы.РеализацияТоваровУслуг.СоздатьДокумент();

НовыйДок.Дата = ТекущаяДатаСеанса();

НовыйДок.Контрагент = Контрагент;

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

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

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

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

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

НовыйДок.Записать(РежимЗаписиДокумента.Запись);

Обратите внимание: сумма и итоги по строке не всегда рассчитываются автоматически. В типовых конфигурациях пересчёт выполняют обработчики событий формы (ПриИзменении), а при программном заполнении объекта эти обработчики не срабатывают. Поэтому суммы, НДС и прочие вычисляемые поля заполняйте явно в коде.

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

Массовая загрузка методом Загрузить()

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

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

ДокОбъект.Товары.Загрузить(ТаблицаТоваров);

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

Метод Загрузить() сначала полностью очищает табличную часть, затем переносит строки из таблицы значений. Совпадение идёт по именам колонок: колонки, которых нет в табличной части, игнорируются, а реквизиты без соответствующей колонки остаются пустыми. Это удобно, но опасно: если в таблице значений нет колонки «СтавкаНДС», после загрузки она будет пустой во всех строках.

Очистка и изменение существующих строк

Для точечной правки не обязательно перезаписывать всю коллекцию. Строки можно перебирать в цикле и изменять:

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

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

СтрокаТовара.Цена = СтрокаТовара.Цена * 1.1;

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

КонецЦикла;

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

Удалить конкретную строку можно методом Удалить(СтрокаТовара), очистить всю коллекцию — методом Очистить(). При удалении в цикле перебирайте коллекцию с конца или собирайте строки для удаления в отдельный массив, иначе индексы сместятся и часть строк будет пропущена.

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

Если обработка изменяет много документов подряд, оборачивайте запись в транзакцию (НачатьТранзакцию / ЗафиксироватьТранзакцию / ОтменитьТранзакцию). Тогда при ошибке на середине пакета база не останется с частично обновлёнными документами.
ПЗ
Практическое замечание

Запись объекта: режимы и проведение

Для документов метод Записать() принимает режим: РежимЗаписиДокумента.Запись сохраняет документ без проведения, РежимЗаписиДокумента.Проведение — сразу проводит его, формируя движения по регистрам. Если документ уже проведён, запись в режиме «Запись» отменит проведение — учитывайте это при доработке проведённых документов.

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

При проведении срабатывают все проверки заполнения и обработчики события ОбработкаПроведения. Если в строках не заполнены обязательные реквизиты или склад/организация не указаны, запись завершится ошибкой. Текст ошибки читайте в сообщении — он укажет, какого реквизита не хватает.

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

Заполнение табличной части в управляемой форме

Когда код выполняется в модуле формы, объект документа доступен как реквизит формы Объект. Строки добавляются аналогично: НоваяСтрока = Объект.Товары.Добавить();. Изменения сразу видны пользователю, но в базу попадут только после записи документа.

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

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

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

Проверка результата и контроль ошибок

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

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

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

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

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

Совпадает с количеством строк источника

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

Строк меньше — часть данных не загрузилась или Загрузить() очистил коллекцию

Суммы и НДС в строках
Норма

Заполнены и сходятся с расчётом Количество × Цена

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

Нулевые суммы — забыли программный пересчёт

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

Соответствует задуманному режиму записи

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

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

Итог

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

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

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

Можно ли записать табличную часть, не записывая сам документ?

Нет. Табличная часть физически хранится как часть объекта и сохраняется в базе только при вызове Записать() у документа или справочника. Любые изменения коллекции без записи объекта будут потеряны.

Почему возникает ошибка «Поле объекта не обнаружено» при обращении к строке?

Имя реквизита в коде не совпадает с именем в конфигураторе, либо вы обращаетесь к другой табличной части. Откройте конфигуратор, найдите объект и сверьте точные имена табличной части и её реквизитов — встроенный язык чувствителен к написанию.

Чем отличается Загрузить() от добавления строк в цикле?

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

Как добавить строку в документ, который уже проведён?

Получите объект через Ссылка.ПолучитьОбъект(), добавьте строку и запишите в режиме РежимЗаписиДокумента.Проведение, чтобы документ остался проведённым. Учтите, что перепроведение изменит движения по регистрам — для закрытых периодов это может быть нежелательно.

Почему после программного заполнения суммы в строках равны нулю?

Пересчёт сумм в типовых конфигурациях выполняют обработчики событий формы, которые не срабатывают при объектной записи. Рассчитывайте сумму, НДС и прочие итоги в коде явно либо вызывайте типовые процедуры пересчёта табличных частей из общих модулей.

Можно ли заполнить табличную часть запросом напрямую?

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