При разработке расширений для конфигураций «1С:Предприятие 8» программисты часто сталкиваются с ситуацией, когда при создании нового реквизита объекта (например, Справочника или Документа) в списке доступных типов отсутствует ТаблицаЗначений. Рассмотрим подробнее архитектурные причины этого ограничения и разберем по шагам альтернативные методы реализации аналогичного функционала.
Для начала проанализируем ситуацию: тип ТаблицаЗначений является исключительно программным объектом. Он существует только в оперативной памяти сервера (или толстого клиента) в момент выполнения кода. У этого типа нет физического представления в таблицах базы данных SQL. Реквизит любого объекта метаданных (будь то справочник, документ или задача) должен иметь тип, который платформа может однозначно преобразовать в поле или набор полей в СУБД для постоянного хранения.
Выясним причину, по которой это разделение критично: если бы платформа позволяла назначать реквизиту тип ТаблицаЗначений, она не знала бы, какую структуру колонок создавать в базе данных, какие индексы строить и как обеспечивать ссылочную целостность данных внутри этой таблицы. Именно поэтому в списке типов для реквизитов объектов мы видим только примитивные типы (число, строка, дата) или ссылки.
Важно различать, где именно мы пытаемся добавить данные. Рассмотрим два варианта:
ТаблицаЗначений недоступна по описанным выше причинам. Это касается и основной конфигурации, и расширений.ТаблицаЗначений. Однако при интерактивном добавлении реквизита в редакторе формы платформа чаще предлагает использовать ДанныеФормыКоллекция — это специальный тип-обертка, который позволяет отображать табличные данные в интерфейсе и передавать их между клиентом и сервером.Если ваша задача — просто временно хранить данные в процессе работы пользователя с формой, используйте реквизит формы. Если же данные должны быть записаны в базу данных и сохранены после закрытия сеанса, необходимо выбрать один из следующих методов.
Это самый правильный и стандартный способ хранения структурированных данных в 1С. Если вам нужно хранить таблицу в объекте расширения, мы создаем новую Табличную часть (ТЧ).
Проанализируем преимущества этого подхода:
Разберем по шагам процесс добавления ТЧ в расширение:
Объект.ИмяВашейТЧ.Добавить().Иногда структура таблицы заранее неизвестна или она слишком сложна для стандартной табличной части. В этом случае мы можем использовать реквизит с типом ХранилищеЗначений. В него можно «упаковать» (сериализовать) практически любой объект, включая ТаблицуЗначений, Массив или Структуру.
Посмотрим на пример кода для записи таблицы в реквизит объекта:
// На сервере
НоваяТаблица = Новый ТаблицаЗначений;
НоваяТаблица.Колонки.Добавить("Товар");
НоваяТаблица.Колонки.Добавить("Количество");
// Заполняем таблицу какими-то данными
НоваяСтрока = НоваяТаблица.Добавить();
НоваяСтрока.Товар = Справочники.Номенклатура.НайтиПоНаименованию("Товар 1");
НоваяСтрока.Количество = 10;
// Помещаем таблицу в реквизит типа ХранилищеЗначений
ОбъектХранилище = Новый ХранилищеЗначений(НоваяТаблица);
Объект.РеквизитХранилище = ОбъектХранилище;
Объект.Записать();
Для получения данных обратно используйте метод Получить():
Если ТипЗнч(Объект.РеквизитХранилище) = Тип("ХранилищеЗначений") Тогда
ВосстановленнаяТаблица = Объект.РеквизитХранилище.Получить();
Если ТипЗнч(ВосстановленнаяТаблица) = Тип("ТаблицаЗначений") Тогда
// Работаем с таблицей
КонецЕсли;
КонецЕсли;
Важный нюанс: Данные внутри ХранилищаЗначений невозможно прочитать обычным SQL-запросом. Платформа хранит их в бинарном виде. Используйте этот метод только тогда, когда поиск по этим данным внутри запросов не требуется.
Современный и очень гибкий метод — хранение таблицы в виде строки неограниченной длины. Проанализируем ситуацию: если мы преобразуем таблицу в формат JSON, мы получаем текстовую строку, которую легко хранить, передавать через API и даже просматривать глазами при отладке.
Разберем пример реализации через JSON:
// Сериализация таблицы в строку JSON
ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, МояТаблицаЗначений);
СтрокаДляХранения = ЗаписьJSON.Закрыть();
// Записываем в реквизит объекта (тип Строка неограниченной длины)
Объект.ДанныеТаблицыСтрокой = СтрокаДляХранения;
Этот метод удобен тем, что строку можно прочитать в консоли запросов, в отличие от ХранилищаЗначений. Однако, как и в предыдущем случае, полноценный поиск по колонкам внутри такой строки в запросе будет затруднен.
При работе в расширении помните о свойстве «Используемые типы». Если вы создаете колонку в табличной части и хотите назначить ей тип ссылки на объект из основной конфигурации, этот объект обязательно должен быть добавлен в расширение. В противном случае платформа просто не «увидит» этот тип в списке доступных.
Также учитывайте ограничение передачи данных между клиентом и сервером. Тип ТаблицаЗначений не существует на клиенте (в тонком клиенте или веб-клиенте). Если вам нужно передать данные из кода сервера на форму, используйте метод ЗначениеВРеквизитФормы(), который преобразует вашу таблицу в коллекцию данных формы.
Подведем итог нашему анализу:
Применяя эти подходы, вы сможете эффективно обходить ограничения платформы и реализовывать сложные задачи в своих расширениях.