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