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

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

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

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

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

Способ записи зависит от контекста: код выполняется на сервере или на клиенте, объект уже существует в базе или создаётся новый, работа идёт через форму или программно в фоновом процессе. Ниже разобраны основные сценарии с примерами кода на встроенном языке 1С.

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

Табличная часть хранится в базе данных как связанная с объектом таблица, но на уровне встроенного языка она не является самостоятельным объектом записи. Строки табличной части не существуют отдельно от «шапки»: у них нет собственного метода записи, а ссылка всегда указывает на весь документ или справочник целиком.

Поэтому любое изменение — добавление строки, правка количества, удаление позиции — требует записи родительского объекта. Если вы изменили строки в объекте, но не вызвали Объект.Записать(), при повторном чтении из базы вы получите старые данные, а изменения будут потеряны.

Запись значения в табличную часть нового документа

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

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

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

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

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

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

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

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

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

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

Метод Добавить() возвращает объект строки, через который доступны все реквизиты табличной части, описанные в конфигураторе. Обращайтесь к реквизитам по именам, заданным в метаданных, — опечатка в имени вызовет ошибку «Поле объекта не обнаружено».

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

Изменение табличной части существующего объекта

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

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

// Поиск нужной строки

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

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

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

Строки[0].Количество = 10;

Иначе

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

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

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

КонецЕсли;

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

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

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

Запись через форму: особенности клиентского кода

Когда пользователь работает в форме документа, табличная часть представлена данными формы, а не объектом базы. В модуле формы доступ к строкам идёт через Объект.Товары (для управляемых форм), и изменения попадут в базу только когда пользователь нажмёт «Записать» или код вызовет Записать() формы.

&НаКлиенте

Процедура ДобавитьСтроку(Команда)

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

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

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

Модифицированность = Истина;

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

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

Табличная часть справочника и обработки

Работа со справочником аналогична документу, с той разницей, что запись выполняется без режима проведения:

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

Строка = ЭлементОбъект.Состав.Добавить();

Строка.Материал = МатериалСсылка;

Строка.Норма = 0.5;

ЭлементОбъект.Записать();

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

Заполнение табличной части из запроса или таблицы значений

Когда данные для строк берутся из базы, эффективнее выполнить запрос и загрузить результат одним методом Загрузить(), чем добавлять строки в цикле:

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

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

"ВЫБРАТЬ

| Остатки.Номенклатура КАК Номенклатура,

| Остатки.КоличествоОстаток КАК Количество

|ИЗ

| РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК Остатки";

Запрос.УстановитьПараметр("Период", ТекущаяДатаСеанса());

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

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

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

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

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

Проверка результата и отладка

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

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

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

"ВЫБРАТЬ

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

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

|ИЗ

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

|ГДЕ

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

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

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

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

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

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

Ссылка объекта после записи
Норма

Ссылка заполнена, Пустая() возвращает Ложь

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

Ссылка пустая — запись не выполнена, ищите исключение

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

Запрос к табличной части возвращает ожидаемое число строк

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

Строк меньше, чем добавлялось — возможен откат транзакции

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

Документ проведён, движения присутствуют в регистрах

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

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

FAQ

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

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

Почему изменения табличной части пропадают после закрытия формы?

Потому что объект не был записан в базу. Изменения в форме хранятся только в памяти до вызова записи. Либо пользователь должен нажать «Записать», либо код должен вызвать метод записи формы или объекта. Признак несохранённых изменений — включённый признак модифицированности формы.

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

Нет, штатными средствами платформы — нельзя. Табличная часть физически хранится отдельной таблицей, но логически является частью объекта и записывается только вместе с ним. Прямые правки в таблицах СУБД в обход платформы нарушают целостность данных и не поддерживаются.

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

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

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

Это значит, что объект изменяется другим пользователем или сеансом. Повторите попытку позже, обернув запись в попытку-исключение, либо перечитайте объект заново через ПолучитьОбъект() и примените изменения к свежей версии. Не отключайте управляемые блокировки ради устранения ошибки — это ведёт к потере данных.

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

Используйте обработчик ОбработкаЗаполнения в модуле объекта: получите данные документа-основания запросом и загрузите результат в табличную часть методом Загрузить(). Это штатный механизм ввода на основании, который автоматически вызывается при создании документа из интерфейса.

Итог

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

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