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

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

Как сохранить табличную часть в 1С

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

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

Главная ошибка новичков — попытка «сохранить табличную часть отдельно». В типовой модели данных 1С табличная часть не существует как самостоятельный объект: она хранится в составе владельца и записывается вместе с ним. Поэтому базовый сценарий всегда сводится к заполнению строк и вызову метода Записать() у объекта-владельца.

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

Как устроено хранение табличной части в базе

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

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

Базовый способ: запись вместе с объектом

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

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

ДокОбъект.Дата = ТекущаяДата();

ДокОбъект.Контрагент = КонтрагентСсылка;

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

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

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

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

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

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

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

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

Сохранение в хранилище значения

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

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

Хранилище = Новый ХранилищеЗначения(ТЗ, Новый СжатиеДанных(9));

НастройкиОбъект.ДанныеТаблицы = Хранилище;

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

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

Учтите ограничение: в хранилище значения сериализуются данные, а не ссылки на живые объекты формы. Ссылки на элементы справочников и документов сохраняются корректно, но при переносе в другую базу они станут «битыми», если там нет тех же объектов с теми же GUID.

Выгрузка в XML и передача между базами

Для обмена между базами или сохранения в файл табличную часть сериализуют в XML. Простейший путь — выгрузить в таблицу значений и записать через ЗаписьXML с использованием СериализаторXDTO:

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

Запись = Новый ЗаписьXML;

Запись.ОткрытьФайл("C:\Temp\Товары.xml");

Запись.ЗаписатьОбъявлениеXML();

СериализаторXDTO.ЗаписатьXML(Запись, ТЗ);

Запись.Закрыть();

Чтение выполняется зеркально через ЧтениеXML и СериализаторXDTO.ПрочитатьXML(). Этот способ надёжен для однотипных конфигураций. Если структуры метаданных в базах различаются, безопаснее формировать XML вручную, записывая каждую строку и колонку явно.

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

Сохранение из формы: модифицированность и буфер

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

Для копирования табличной части между формами используйте Выгрузить() у данных формы табличной части — в управляемых формах реквизит формы типа «ТаблицаЗначений» поддерживает методы Выгрузить() и Загрузить(). Для временного хранения на сервере удобно помещать таблицу во временное хранилище: ПоместитьВоВременноеХранилище(ТЗ, УникальныйИдентификаторФормы).

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

Записать() у объекта

Основной способ. Данные попадают в базу в транзакции с объектом. Не подходит для хранения снимков отдельно от владельца.

Хранилище значения

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

XML / сериализация

Для обмена между базами и выгрузки в файл. Требует аккуратности со ссылками при разных конфигурациях.

Временное хранилище

Для передачи между вызовами сервера в рамках сеанса. Данные живут ограниченное время и не сохраняются в базе.

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

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

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

Типичные ошибки
01
Заполнение строк без вызова Записать() — данные остаются только в памяти и теряются
02
Работа с разными экземплярами объекта: изменили один, записали другой — изменения потеряны
03
Использование Загрузить() с таблицей несовпадающего состава колонок — часть данных молча не переносится
04
Запись без обработки исключений при конкурентном доступе — необработанная ошибка блокировки у пользователя
05
Хранение больших таблиц в хранилище значения без сжатия — рост размера базы

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

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

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

"ВЫБРАТЬ КОЛИЧЕСТВО(*) КАК ЧислоСтрок

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

|ГДЕ Ссылка = &Ссылка");

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

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

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

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

Совпадает с числом строк в объекте до записи

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

Строк меньше или ноль — запись не выполнилась или объект был перезаписан

Значения ключевых колонок
Норма

Суммы и количества совпадают с исходными данными

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

Пустые или нулевые значения — несовпадение имён колонок при Загрузить()

Повторное открытие формы
Норма

Табличная часть отображается полностью

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

Форма пуста — записан другой экземпляр объекта

Часто задаваемые вопросы

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

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

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

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

Почему после Загрузить() часть колонок осталась пустой?

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

Как сохранить табличную часть обработки, если она не хранится в базе?

Выгрузите её в таблицу значений и сохраните в реквизит типа «ХранилищеЗначения» любого объекта (например, справочника настроек) либо сериализуйте в XML-файл. При следующем открытии загрузите данные обратно.

Безопасно ли записывать объект, пока его редактирует пользователь?

Платформа защищает данные блокировками: при конфликте одна из записей завершится ошибкой. Программную запись выполняйте в конструкции Попытка/Исключение и уведомляйте пользователя, чтобы он не потерял свои изменения.

Итог

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

Табличная часть сохраняется только вместе с объектом-владельцем через Записать(). Для снимков и переноса используйте Выгрузить() в таблицу значений с последующим помещением в хранилище значения или XML. Всегда проверяйте результат запросом и обрабатывайте конфликты блокировок.