Процедура "ЗаполнитьИзЗапроса" сокращает и упрощает прикладной код:
- Запрос к базе данных составляется непосредственно в обработчике событий формы;
- Значения реквизитов формы процедура самостоятельно считывает в качестве параметров запроса;
- Значения реквизитов формы процедура самостоятельно заполняет результатом выборки данных.
По производительности процедура "ЗаполнитьИзЗапроса" медленнее традиционно реализованных процедур &НаСервереБезКонтекста, но быстрее, чем &НаСервере (с контекстом).
В обновленной публикации:
- В процедуру "ЗаполнитьИзЗапроса" добавлена возможность указания имен параметров запроса в явном виде - это исключает дополнительный вызов сервера для автоматического определения перечня параметров Запроса;
- Подправлен код;
- Добавлена обработка для оценки производительности процедуры "ЗаполнитьИзЗапроса".
Процедура ЗаполнитьИзЗапроса принимает четыре параметра:
- ОбъектПриемник - куда копировать результат запроса;
- ТекстЗапроса - стандартный параметризованный запрос;
- ОбъектИсточник - откуда брать параметры для Запроса - необязательный параметр, по умолчанию используется ОбъектПриемник;
- СтруктураПараметровЗапроса - необязательное перечисление параметров запроса и их значений. Исключает дополнительный вызов сервера для автоматического определения имен параметров в Запросе.
Пример заполнения на форме “КурсаВалюты” &НаКлиенте через предлагаемую процедуру:
Порядок работы процедуры ЗаполнитьИзЗапроса:
- Если СтруктураПараметровЗапроса не указана явно, параметры определяются в ТекстеЗапроса автоматически &НаСервереБезКонтекста;
- &НаКлиенте СтруктураПараметровЗапроса заполняется значениями свойств ОбъектаИсточника (символ “_” (подчеркивание) в имени параметра запроса интерпретируется как “.” (точка) для доступа к вложенным свойствам объекта);
- &НаСервереБезКонтекста выполняется ТекстЗапроса;
- &НаКлиенте заполняются свойства ОбъектаПриемника значениями полей результирующей таблицы Запроса (символ “_” (подчеркивание) в имени поля интерпретируется как “.” (точка) для доступа к вложенным свойствам объекта).
Оценка производительности для толстого клиента:
- Процедура ЗаполнитьИзЗапроса (п.2.2.) выполняется в 1,5 раза медленнее традиционно реализованной функции на &НаСервереБезКонтекста (п.1.3.), но в 2 раза быстрее процедуры на &НаСервере (с контекстом) (п.1.4.);
- Автоматическое определение параметров запроса увеличивает время выполнение процедуры ЗаполнитьИзЗапроса в 1,7 раза (п.2.3.). Данную опцию удобно использовать на этапе отладки, когда параметры запроса окончательно не определены.
- ЛЮБОПЫТНО! Вызов клиентом сервера без контекста (п.1.3.) в 3!!! раза медленнее обращения сервера к БД (п.2.1.).
Ниже представлен код реализованных процедур:
&НаКлиентеНаСервереБезКонтекста Процедура ЗаполнитьИзЗапроса(ОбъектПриемник, Знач ТекстЗапроса, Знач ОбъектИсточник=Неопределено, Знач СтруктураПараметровЗапроса=Неопределено) ОбъектИсточник = ?(ОбъектИсточник=Неопределено,ОбъектПриемник,ОбъектИсточник); Если ТипЗнч(СтруктураПараметровЗапроса)<>Тип("Структура") тогда СтруктураПараметровЗапроса = Новый Структура; Для каждого ИмяПараметра Из ИменаПараметровЗапроса(ТекстЗапроса) Цикл СтруктураПараметровЗапроса.Вставить(ИмяПараметра); КонецЦикла; КонецЕсли; Для каждого Параметр Из СтруктураПараметровЗапроса Цикл Если Параметр.Значение=Неопределено тогда Попытка СтруктураПараметровЗапроса.Вставить(Параметр.Ключ, ПрочитатьВложенныйОбъект(ОбъектИсточник, Параметр.Ключ)); Исключение СтруктураПараметровЗапроса.Вставить(Параметр.Ключ, Null); КонецПопытки; КонецЕсли; КонецЦикла; МассивЗначений = ЗаполнитьМассивРезультатомЗапроса(СтруктураПараметровЗапроса, ТекстЗапроса, 1); Если МассивЗначений.Количество()>0 тогда Для каждого Колонка Из МассивЗначений[0] Цикл Попытка ЗаписатьВоВложенныйОбъект(Колонка.Значение, ОбъектПриемник, Колонка.Ключ) Исключение КонецПопытки; КонецЦикла; КонецЕсли; КонецПроцедуры &НаКлиентеНаСервереБезКонтекста Функция ПрочитатьВложенныйОбъект(Объект, Путь="", Разделитель="_") ПозицияРазделителя = Найти(Путь, Разделитель); Если ПозицияРазделителя=0 тогда ПозицияРазделителя=СтрДлина(Путь)+1; КонецЕсли; ИмяВложенногоОбъекта=Сред(Путь,1,ПозицияРазделителя-1); ОставшийсяПуть=Сред(Путь,ПозицияРазделителя+1); Если ИмяВложенногоОбъекта="" тогда Возврат Объект; КонецЕсли; Если ОставшийсяПуть="" тогда Возврат Объект[ИмяВложенногоОбъекта]; КонецЕсли; Возврат ПрочитатьВложенныйОбъект(Объект[ИмяВложенногоОбъекта], ОставшийсяПуть, Разделитель); КонецФункции &НаКлиентеНаСервереБезКонтекста Процедура ЗаписатьВоВложенныйОбъект(Значение, Объект, Путь="", Разделитель="_") ПозицияРазделителя = Найти(Путь, Разделитель); Если ПозицияРазделителя=0 тогда ПозицияРазделителя=СтрДлина(Путь)+1; КонецЕсли; ИмяВложенногоОбъекта=Сред(Путь,1,ПозицияРазделителя-1); ОставшийсяПуть=Сред(Путь,ПозицияРазделителя+1); Если ИмяВложенногоОбъекта="" тогда Объект=Значение; Возврат; КонецЕсли; Если ОставшийсяПуть="" тогда Объект[ИмяВложенногоОбъекта]=Значение; Возврат; КонецЕсли; ЗаписатьВоВложенныйОбъект(Значение, Объект[ИмяВложенногоОбъекта], ОставшийсяПуть, Разделитель); КонецПроцедуры &НаСервереБезКонтекста Функция ИменаПараметровЗапроса(ТекстЗапроса) Запрос = Новый Запрос(ТекстЗапроса); МассивПараметров = Новый Массив; Для каждого Параметр Из Запрос.НайтиПараметры() Цикл МассивПараметров.Добавить(Параметр.Имя) КонецЦикла; Возврат МассивПараметров; КонецФункции &НаСервереБезКонтекста Функция ЗаполнитьМассивРезультатомЗапроса(СтруктураПараметров, ТекстЗапроса, КоличествоЗаписей=0) Запрос = Новый Запрос(ТекстЗапроса); Для каждого Параметр Из СтруктураПараметров Цикл Запрос.УстановитьПараметр(Параметр.Ключ, Параметр.Значение); КонецЦикла; РезультатЗапроса = Запрос.Выполнить(); МассивИменКолонок = Новый Массив; Для каждого Колонка Из РезультатЗапроса.Колонки Цикл МассивИменКолонок.Добавить(Колонка.Имя); КонецЦикла; ВыборкаЗаписей = РезультатЗапроса.Выбрать(); РезультирующийМассив = Новый Массив(); Если ВыборкаЗаписей.Следующий() тогда СтруктураДанных = Новый Структура(); Для каждого ИмяКолонки Из МассивИменКолонок Цикл СтруктураДанных.Вставить(ИмяКолонки, ВыборкаЗаписей[ИмяКолонки]); КонецЦикла; РезультирующийМассив.Добавить(СтруктураДанных); Если КоличествоЗаписей<>1 тогда ВыбраноЗаписей=1; Пока ВыборкаЗаписей.Следующий() и (ВыбраноЗаписей<КоличествоЗаписей или КоличествоЗаписей=0) цикл СтруктураДанных = Новый Структура(); Для каждого ИмяКолонки Из МассивИменКолонок цикл СтруктураДанных.Вставить(ИмяКолонки, ВыборкаЗаписей[ИмяКолонки]); КонецЦикла; РезультирующийМассив.Добавить(СтруктураДанных); ВыбраноЗаписей=ВыбраноЗаписей+1; КонецЦикла; КонецЕсли; КонецЕсли; Возврат РезультирующийМассив; КонецФункции