При разработке на платформе 1С:Предприятие часто возникает задача программного формирования таблицы значений (ТЗ), структура которой должна в точности повторять существующую табличную часть (ТЧ) какого-либо документа. Это особенно важно, когда предполагается дальнейшее использование этой таблицы в качестве параметра в запросе. Если колонки ТЗ не будут жестко типизированы, платформа может некорректно интерпретировать данные при создании временной таблицы в СУБД, что приведет к ошибкам или существенному снижению производительности. В этой статье мы подробно разберем несколько способов решения этой задачи, проанализируем их плюсы и минусы, а также изучим нюансы работы с типами данных.
Прежде чем перейти к методам реализации, разберем причину, по которой простого создания колонок методом Добавить() без указания типов недостаточно. Когда мы передаем таблицу значений в запрос как параметр, платформа 1С выполняет следующие действия:
Если тип колонки в ТЗ не определен (имеет тип Произвольный), платформа пытается определить его по значению в первой строке. Если таблица пуста, это часто приводит к созданию поля типа NVARCHAR(1) или BINARY, что делает невозможным дальнейшее соединение этой таблицы с реальными данными БД или их индексацию. Поэтому типизация — это не просто "хороший тон", а техническая необходимость.
Рассмотрим наиболее элегантный и производительный способ, который часто встречается в типовых конфигурациях. Он заключается в использовании метода ВыгрузитьКолонки(). Для его реализации нам не нужно создавать реальный объект документа в памяти, достаточно обратиться к пустой ссылке.
Разберем пример кода:
// Получаем структуру колонок через пустую ссылку табличной части
ТЗ = Документы.РеализацияТоваровУслуг.ПустаяСсылка().Товары.ВыгрузитьКолонки();
Преимущества этого метода:
Важно помнить, что этот метод работает на сервере или в толстом клиенте. Если вам нужно получить структуру на стороне тонкого клиента, данные придется передавать с сервера.
Проанализируем ситуацию, когда нам нужно программно управлять процессом создания колонок, например, исключая определенные реквизиты или добавляя свои. В этом случае мы можем обратиться к объекту Метаданные.
Рассмотрим по шагам, как это реализовать:
ТЗ = Новый ТаблицаЗначений;
МетаданныеТЧ = Метаданные.Документы.РеализацияТоваровУслуг.ТабличныеЧасти.Товары;
// Перебираем реквизиты табличной части
Для Каждого Реквизит Из МетаданныеТЧ.Реквизиты Цикл
ТЗ.Колонки.Добавить(Реквизит.Имя, Реквизит.Тип);
КонецЦикла;
Важное уточнение: При таком подходе мы упускаем так называемые "стандартные реквизиты", такие как НомерСтроки. Если ваша логика в запросе опирается на индекс строки, их нужно добавить отдельно, обратившись к коллекции СтандартныеРеквизиты того же объекта метаданных.
Довольно оригинальный и эффективный метод — получение структуры через результат запроса. Выясним, почему это удобно: запрос сразу возвращает объект ТаблицаЗначений с уже прописанными типами полей, которые максимально "понятны" для СУБД.
Пример реализации:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 0
| РеализацияТоваровУслугТовары.Номенклатура КАК Номенклатура,
| РеализацияТоваровУслугТовары.Количество КАК Количество,
| РеализацияТоваровУслугТовары.Цена КАК Цена
|ИЗ
| Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары";
ТЗ = Запрос.Выполнить().Выгрузить();
Использование конструкции ВЫБРАТЬ ПЕРВЫЕ 0 гарантирует, что запрос не будет считывать данные из базы, а только сформирует схему результата. Этот метод хорош тем, что позволяет сразу задать псевдонимы полей (через КАК), которые могут отличаться от имен в метаданных.
Разберем ситуацию с составными типами данных. Если в табличной части реквизит имеет составной тип (например, ДокументСсылка.Реализация, ДокументСсылка.Поступление), то при выгрузке в ТЗ и последующей передаче в запрос как временной таблицы, производительность соединений может упасть. SQL-серверу сложно индексировать поля с неопределенным типом.
Для оптимизации рекомендуется принудительно ограничивать тип в запросе, используя конструкцию ВЫРАЗИТЬ:
Запрос.Текст =
"ВЫБРАТЬ
| ВТ_Данные.Номенклатура,
| ВЫРАЗИТЬ(ВТ_Данные.ДокументОснование КАК Документ.РеализацияТоваровУслуг) КАК Ссылка
|ИЗ
| &ВТ_Данные КАК ВТ_Данные";
Также стоит обратить внимание на строки неограниченной длины. Если в метаданных колонка ТЧ определена как строка неограниченной длины, вы не сможете проиндексировать ее во временной таблице. В таких случаях при создании колонок в ТЗ лучше вручную задать ОписаниеТипов с ограничением длины (например, 150-250 символов), если это допустимо бизнес-логикой.
Проанализируем и сравним все рассмотренные варианты:
ДокументОбъект ради структуры — это лишний расход оперативной памяти.В заключение отметим, что правильная типизация таблиц значений — это залог стабильной работы информационной системы. Выбирайте метод исходя из контекста задачи: для простого копирования структуры лучше ВыгрузитьКолонки(), для гибкой настройки — Запрос или Метаданные.