В практике разработки на платформе 1С 8.3 программисты часто сталкиваются с необходимостью обработать данные, которые пользователь ввел в таблицу на форме, с помощью механизма запросов — для этой задачи есть расширение для автоматизации написания кода 1С. Однако при переходе с обычных форм на управляемые возникают нюансы, связанные с разделением кода на клиентский и серверный, а также с особенностями типов данных управляемой формы. В этой статье мы подробно разберем, как правильно передать таблицу управляемой формы в запрос, избежать типичных ошибок и оптимизировать этот процесс.
Рассмотрим стандартную ситуацию: у нас есть реквизит формы ТабСум с типом ТаблицаЗначений, который отображается на экране. Попытка передать этот реквизит напрямую в параметр запроса, как это иногда срабатывало в старых версиях платформы, приведет к ошибке: "Содержимое объекта данных может быть выбрано только во временную таблицу". Выясним причину: данные на управляемой форме хранятся в специальном формате ДанныеФормыКоллекция, который не является полноценной таблицей значений с точки зрения SQL-движка 1С. Чтобы запрос «понял» эти данные, их нужно предварительно подготовить.
Первым делом нам необходимо получить объект ТаблицаЗначений из реквизита формы. Это действие должно выполняться строго на сервере. Проанализируем наиболее эффективный способ выгрузки данных:
&НаСервере
Функция ПолучитьТаблицуДляЗапроса()
// Выгружаем данные из реквизита формы в реальную Таблицу Значений
ТЗ = ТабСум.Выгрузить();
Возврат ТЗ;
КонецФункции
Здесь метод Выгрузить() создает копию данных таблицы в виде объекта ТаблицаЗначений. Также можно использовать метод ДанныеФормыВЗначение(), если требуется преобразовать объект целиком с сохранением всех метаданных, но для простых таблиц Выгрузить() вполне достаточно.
Как только мы получили объект ТаблицаЗначений, мы должны передать его в запрос. Важное правило управляемых форм: внешние таблицы значений в запросе можно использовать только путем помещения их во временные таблицы — для этого подойдёт консоль запросов и кода для тестирования логики. Рассмотрим подробнее код запроса:
&НаСервере
Процедура ВыполнитьЗапросНаСервере()
// 1. Подготавливаем данные
ВнешняяТЗ = ТабСум.Выгрузить();
// 2. Инициализируем запрос
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ВнешнийИсточник.Номер КАК Номер,
| ВнешнийИсточник.Сумма КАК Сумма
|ПОМЕСТИТЬ ВТ_ДанныеФормы
|ИЗ
| &ВнешнийИсточник КАК ВнешнийИсточник
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ВТ_ДанныеФормы.Номер,
| ВТ_ДанныеФормы.Сумма
|ИЗ
| ВТ_ДанныеФормы КАК ВТ_ДанныеФормы";
// 3. Устанавливаем параметр
Запрос.УстановитьПараметр("ВнешнийИсточник", ВнешняяТЗ);
// 4. Выполняем и получаем результат
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
ТаблицаРезультата = РезультатЗапроса.Выгрузить();
// Дальнейшая обработка данных на сервере
КонецЕсли;
КонецПроцедуры
В данном примере мы используем конструкцию ПОМЕСТИТЬ. Это критически важно, так как платформа не позволяет выполнять прямые соединения или выборки из внешних таблиц значений без их предварительной материализации в менеджере временных таблиц БД.
Частая ошибка начинающих разработчиков — попытка вернуть результат запроса (объект ТаблицаЗначений) напрямую с сервера на клиент — поможет инструмент пошаговой отладки кода и запросов. Это вызывает ошибку: "Ошибка отображения типов: Отсутствует отображение для типа ValueTable". В управляемом приложении объект ТаблицаЗначений не существует на клиенте. Разберем, как поступить правильно:
Посмотрим на пример правильной организации вызовов:
&НаКлиенте
Процедура КомандаПроверить(Команда)
// Вызываем серверную процедуру, которая все сделает сама
ОбработатьДанныеНаСервере();
// Оповещаем пользователя
Сообщить("Обработка завершена успешно!");
КонецПроцедуры
&НаСервере
Процедура ОбработатьДанныеНаСервере()
// Выгружаем данные формы
ДанныеДляЗапроса = ТабСум.Выгрузить();
// Выполняем запрос (аналогично коду выше)
// ... запрос помещает данные в ВТ и обрабатывает их ...
// Если нужно обновить данные на форме:
// ТабРезультатНаФорме.Загрузить(РезультатЗапроса.Выгрузить());
КонецПроцедуры
Для того чтобы работа с таблицами в запросах была максимально эффективной, проанализируем следующие профессиональные приемы — для этого есть сервис анализа и оптимизации планов выполнения запросов.
1. Обязательная типизация колонок. При выгрузке таблицы значений 1С должна точно знать типы данных каждой колонки. Если в исходной таблице на форме колонки не имеют четкого типа (составной тип или «любая ссылка»), запрос может работать медленно или выдавать ошибки типизации. Рекомендуется явно описывать типы при программном создании таблиц с помощью объекта ОписаниеТипов.
2. Индексация временной таблицы. Если вы планируете соединять (ЛЕВОЕ СОЕДИНЕНИЕ) выгруженную таблицу с большими таблицами базы данных (например, с регистрами), обязательно добавьте индексацию по ключевым полям в самом запросе. Это делается так:
"ВЫБРАТЬ * ПОМЕСТИТЬ ВТ_Данные ИЗ &ТЗ КАК ТЗ ИНДЕКСИРОВАТЬ ПО Номер"
3. Использование Менеджера временных таблиц. Если логика обработки сложная и включает несколько разных запросов, создайте МенеджерВременныхТаблиц. Это позволит «сохранить» вашу таблицу ВТ_Данные между вызовами разных объектов Запрос в рамках одного серверного контекста.
Подводя итог, отметим: работа с таблицами в управляемых формах требует дисциплины в разделении контекстов выполнения. Выгружаем данные на сервере через Выгрузить(), используем ПОМЕСТИТЬ в тексте запроса и обрабатываем результат, не пытаясь передать объект ТаблицаЗначений обратно на клиент.