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