Каждый разработчик 1С в своей ежедневной практике сталкивается с необходимостью написания, отладки и анализа запросов к базе данных. В эпоху обычного приложения этот вопрос решался стандартными инструментами, но переход на управляемые формы (УФ) и регулярные обновления Библиотеки стандартных подсистем (БСП) привнесли свои сложности. Часто бывает так: мы скачиваем очередную обработку, запускаем её, но результат выполнения запроса либо не отображается, либо программа аварийно завершает работу с загадочной системной ошибкой. В рамках этой статьи мы детально разберем, как выбрать надежную консоль запросов для управляемого приложения 1С 8.3, и выясним истинную причину возникновения аппаратных сбоев при вызове конструктора запросов в толстом клиенте управляемого приложения.
Для начала давайте разберемся, какие вообще существуют варианты консолей запросов для управляемого приложения и в чем их ключевые различия. На рынке решений для разработчиков выделяется несколько бесплатных и условно-бесплатных инструментов:
Если в процессе выполнения вашего запроса консоль показывает, что результат есть (например, в строке состояния отображается число строк), но сама таблица на форме остается пустой, первым делом проанализируйте текст запроса. Довольно распространенной ошибкой является наличие инструкции ПОМЕСТИТЬ в самом последнем запросе пакета. Помните, что если пакетный запрос заканчивается помещением данных во временную таблицу, СУБД возвращает пустой результирующий набор для этой секции. Чтобы увидеть результат, обязательно добавьте в конец пакета выборку из этой временной таблицы с помощью инструкции ВЫБРАТЬ * ИЗ ИмяВременнойТаблицы.
Теперь давайте перейдем к разбору сложной технической проблемы, с которой массово сталкиваются разработчики после обновления типовых конфигураций (Бухгалтерия предприятия КОРП, ERP Управление предприятием, ЗУП и др.) до свежих релизов БСП. При попытке интерактивно открыть ветку метаданных (например, справочники или документы) или вызвать встроенный конструктор запроса в некоторых внешних консолях система падает со следующей ошибкой:
При подписке ПереопределитьПолучаемуюФормуПрисоединенногоФайлаЗарплатаКадрыБазовая на событие ОбработкаПолученияФормы произошла ошибка. Обработчик события не найден.
Выясним причину этого сбоя. Данная ошибка воспроизводится при одновременном выполнении следующих пяти условий:
ОбработкаПолученияФормы вызываются экспортные методы, расположенные в общих модулях, которые компилируются исключительно на стороне сервера (для этих модулей в конфигураторе сняты флажки «Клиент (управляемое приложение)» и «Вызов сервера»).Дело в том, что когда внешняя обработка консоли пытается инициализировать конструктор запросов платформы, ядро системы начинает обход метаданных и инициализацию контекста получения форм для связанных объектов (в частности, для присоединенных файлов). Платформа генерирует событие ОбработкаПолученияФормы. В новых версиях БСП разработчики фирмы 1С перенесли обработчики этих подписок в серверные модули (например, в модуль РаботаСФайлами), у которых отсутствует признак вызова с клиента. Толстый клиент управляемого приложения в клиент-серверной архитектуре пытается скомпилировать этот вызов локально на клиенте, не находит соответствующую процедуру и выдает критическую ошибку.
Рассмотрим разницу в коде обработчиков типичной подписки в старых и новых релизах конфигураций.
Раньше в БСП использовался клиентский вызов, который перенаправлял выполнение на сервер через модуль с установленным признаком «Вызов сервера»:
// Устаревший обработчик, который вызывался корректно из толстого клиента
Процедура ПереопределитьПолучаемуюФормуПрисоединенногоФайла(Источник,
ВидФормы,
Параметры,
ВыбраннаяФорма,
ДополнительнаяИнформация,
СтандартнаяОбработка) Экспорт
РаботаСФайламиСлужебныйВызовСервера.ОпределитьФормуПрисоединенногоФайла(
Источник,
ВидФормы,
Параметры,
ВыбраннаяФорма,
ДополнительнаяИнформация,
СтандартнаяОбработка);
КонецПроцедуры
В обновленных версиях конфигурации этот код был оптимизирован и перенесен непосредственно в серверный общий модуль без поддержки клиентской компиляции:
// Новый обработчик в модуле "РаботаСФайлами" (только сервер)
Процедура ОпределитьФормуПрисоединенногоФайла(Источник, ВидФормы, Параметры,
ВыбраннаяФорма, ДополнительнаяИнформация, СтандартнаяОбработка) Экспорт
ЭтоФормаВерсии = Ложь;
Если Источник <> Неопределено Тогда
ЭтоФормаВерсии = ОбщегоНазначения.ЕстьРеквизитОбъекта("РодительскаяВерсия", Метаданные.НайтиПоТипу(ТипЗнч(Источник)));
КонецЕсли;
// ... дальнейшая логика определения формы
КонецПроцедуры
Поскольку общий модуль РаботаСФайлами доступен только на сервере, толстый клиент управляемого приложения при обходе подписок на события во внешних обработках аварийно прерывает выполнение потока.
Существует несколько практических способов обойти или полностью решить эту проблему в зависимости от того, есть ли у вас доступ к изменению метаданных конфигурации.
Способ 1. Изменение настроек внешней консоли запросов (без изменения конфигурации)
Многие современные консоли (например, консоль Евгения Люлюка) предоставляют возможность гибкой настройки вызова конструктора метаданных. Посмотрим на алгоритм действий:
Способ 2. Запуск сеанса в тонком клиенте
Если перед вами не стоит задача визуального проектирования схем компоновки данных (СКД), требующих исключительно толстого клиента, запускайте отладку и работу с базой через Тонкий клиент. В тонком клиенте конструктор запросов функционирует на совершенно иных системных механизмах, транслируя вызовы на сервер корректно, что полностью предотвращает появление ошибки инициализации форм.
Способ 3. Модификация конфигурации (для баз, находящихся на поддержке с возможностью изменения)
Если вы разрабатываете собственное решение или ваша типовая конфигурация открыта для редактирования, вы можете устранить этот баг платформы на корню. Для этого:
ПереопределитьПолучаемуюФормуПрисоединенногоФайлаЗарплатаКадрыБазовая).Способ 4. Переход на асинхронные методы в коде внешней обработки
Если вы сами программируете или дорабатываете консоль запросов, замените модальный вызов конструктора на асинхронный. Разберем пример кода. Вместо устаревшего модального вызова:
// Этот вызов приводит к ошибке в толстом клиенте УФ на новых БСП
КонструкторЗапроса = Новый КонструкторЗапроса;
Если КонструкторЗапроса.ОткрытьМодально() Тогда
ТекстЗапроса = КонструкторЗапроса.Текст;
КонецЕсли;
Нам следует использовать асинхронный метод Показать() с передачей описания оповещения:
// Безопасный асинхронный вызов конструктора запросов
&НаКлиенте
Процедура ОткрытьКонструкторЗапроса()
Конструктор = Новый КонструкторЗапроса;
Конструктор.Текст = Объект.ТекстЗапроса;
ОписаниеОповещения = Новый ОписаниеОповещения("ПослеЗакрытияКонструктора", ЭтотОбъект);
Конструктор.Показать(ОписаниеОповещения);
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗакрытияКонструктора(РезультатВыбора, ДополнительныеПараметры) Экспорт
// РезультатВыбора возвращает Истина, если пользователь нажал "ОК" в конструкторе
Если РезультатВыбора Тогда
// Здесь мы получаем измененный текст запроса и обновляем поле на форме
Объект.ТекстЗапроса = РезультатВыбора.Текст;
КонецЕсли;
КонецПроцедуры
Такой подход полностью соответствует современным стандартам разработки фирмы 1С и исключает проблемы совместимости при любых обновлениях платформы или конфигурации.
Мало кто знает, но все базовые диалоги и конструкторы (такие как конструктор запросов на управляемых формах, журнал регистрации или активные пользователи) хранятся внутри исполняемых файлов платформы в виде обычных внешних обработок формата .epf. Платформа обращается к ним по внутреннему ресурсному пути v8res://.
Мы можем легко выгрузить любой из этих встроенных инструментов на диск, чтобы изучить их устройство, перенять лучшие практики разработки управляемого интерфейса или модифицировать их логику под свои задачи. Проанализируем список некоторых системных утилит:
v8res://mngbase/QueryWizard.epfv8res://mngbase/StandardEventLog.epfv8res://mngbase/StandardActiveUsers.epfv8res://mngbase/StandardFindByRef.epfv8res://mngbase/StandardDeleteMarkedObjects.epfЧтобы выгрузить, например, встроенный конструктор запросов на локальный диск компьютера, нам достаточно выполнить простой программный код в любой внешней обработке или в режиме отладки:
// Копируем встроенную обработку платформы на жесткий диск
ПутьКИсточнику = "v8res://mngbase/QueryWizard.epf";
ПутьКПолучателю = "C:\Temp\QueryWizard.epf";
Попытка
КопироватьФайл(ПутьКИсточнику, ПутьКПолучателю);
Сообщить("Файл успешно скопирован в: " + ПутьКПолучателю);
Исключение
Сообщить("Не удалось скопировать файл. Ошибка: " + ОписаниеОшибки());
КонецПопытки;
После выполнения данного кода вы сможете открыть полученный файл QueryWizard.epf в Конфигураторе, детально изучить алгоритмы построения дерева запроса, перетаскивания таблиц (drag-and-drop) и динамического формирования текста запроса на управляемых формах.