bdd2

Виртуализация документов в запросах

Опубликовал Осипов Сергей (fixin) в раздел Программирование - Практика программирования

В типовых конфигурациях при печати документов обычно используется запрос к базе данных для получения данных о документе. Это не всегда удобно, когда требуется вместо реального объекта отправить на печать модифицированный, измененный объект. В таких случаях рекомендую не переписывать запросы типовых, а использовать виртуализацию запросов.

Суть метода

 

Суть метода заключается в том, чтобы точечно вставить изменение непосредственно перед выполнением кода запроса.

Например, в типовой конфигурации УТ есть запрос по печати расходной накладной в модуле объекта:

      

ВЫБРАТЬ

             РеализацияТоваровУслуг.Номенклатура,

             …

             Документ.РеализацияТоваровУслуг.ВозвратнаяТара КАК РеализацияТоваровУслуг

       ГДЕ

             РеализацияТоваровУслуг.Ссылка = &ТекущийДокумент

       УПОРЯДОЧИТЬ ПО

             Метка,

             НомерСтроки


Этот запрос помещается в текст запроса Запрос.Текст, затем вызывается выполнение:

      

ЗапросТовары = Запрос.Выполнить().Выгрузить();

 

Для того, чтобы воспользоваться виртуализацией и напечатать текущий модифицированный документ из памяти, а не хранящийся в  базе данных, достаточно вызвать метод перед выполнением запроса:

 

ОбработатьЗапросПоВиртуальномуДокументу(Запрос, Ссылка.ПолучитьОбъект(), ЭтотОбъект());


Этот метод заменяет обращения к таблицам документа на обращения к виртуальным таблицам, помещаемым в менеджер временных таблиц.

Функция позволяет можно заменить табличные части и реквизиты шапки документа.

 

Более интересное применение виртуализации – модификация документа перед его проведением.

Например, в УТ серии должны храниться в документе по одной строке на каждую серию. Это неудобно для пользователей. Поэтому можно серии вынести в отдельную таблицу, но при проведении эмулировать документ с заполненными сериями, т.е. проставлять для каждой строки серию. В этом случае и пригодится вызов виртуализации при контроле остатков, запросе по табличной части документа и т.п.

Демонстрационная обработка для УТ

В обработке-примере используется документ РеализацияТоваровУслуг из УТ.

В обработку скопирована процедура печати накладной.

Перед вызовом каждого из двух запросов добавлена строка:

      

ОбработатьЗапросПоВиртуальномуДокументу(Запрос, Ссылка.ПолучитьОбъект(), ЭтотОбъект);


Этого достаточно, чтобы печатная форма брала объект из памяти, а не из базы данных. Сравните с трудоемкостью изменения запроса, если бы вы захотели сделать это другим способом!

В форме можно нажать кнопку «Показать форму документа», внести изменения в документ, затем, не закрывая форму документа, нажать кнопку «Распечатать документ» и получить печатную форму накладной по несохраненному в базе объекту.

Пример:

Открываем обработку, выбираем документ:

Открываем документ:

Нажимаем распечатать:

Модифицируем номер, контрагента и количество товара в первой строке:

Нажимаем распечатать:

Как видно, изменения, сделанные в памяти, отобразились в печатной форме, минуя базу данных.

Код процедуры виртуализации

Функция ОбработатьЗапросПоВиртуальномуДокументу(Запрос, ДокументОбъект, ДокументОбъектНовый) Экспорт

      

       ЗапросТМП = Новый Запрос();

       Если  Запрос.МенеджерВременныхТаблиц = Неопределено Тогда

             ЗапросТМП.МенеджерВременныхТаблиц = Новый МенеджерВременныхТаблиц;

             Запрос.МенеджерВременныхТаблиц=ЗапросТМП.МенеджерВременныхТаблиц;

       Иначе

             ЗапросТМП.МенеджерВременныхТаблиц = Запрос.МенеджерВременныхТаблиц;

       КонецЕсли;

      

       //Заменяем запрос к документу на запрос к таблице...

       ИмяДокумента = ДокументОбъект.Метаданные().Имя;

       МД = ДокументОбъект.Метаданные();

       ТипСсылка = Новый ОписаниеТипов("ДокументСсылка." + ИмяДокумента);

       Для Каждого МДТЧ ИЗ МД.ТабличныеЧасти Цикл

             ИмяТЧ = МДТЧ.Имя; //Идентификатор табличной части

             МаскаТЧ = "Документ." + ИмяДокумента + "." + ИмяТЧ;

             Если Найти(Запрос.Текст, МаскаТЧ) = 0 Тогда Продолжить; КонецЕсли;

             ИмяВТ = "ВТТаб" + ИмяТЧ;//Идентификатор временной таблицы

             Запрос.Текст = СтрЗаменить(Запрос.Текст, МаскаТЧ, " " + ИмяВТ + " ");

            

             ТЗТабличнаяЧасть = ДокументОбъектНовый[ИмяТЧ].Выгрузить();

             ТЗТабличнаяЧасть.Колонки.Добавить("Ссылка", ТипСсылка);

             ТЗТабличнаяЧасть.ЗаполнитьЗначения(ДокументОбъект.Ссылка, "Ссылка");

            

             ЗапросТМП.Текст = "Выбрать * ПОМЕСТИТЬ " + ИмяВТ + " Из &Таб Как Т";

             ЗапросТМП.УстановитьПараметр("Таб", ТЗТабличнаяЧасть);

             ЗапросТМП.Выполнить();

       КонецЦикла;

      

       //Заменяем запросы к шапке

       МаскаШапки = "Документ." + ИмяДокумента;

       Если Найти(Запрос.Текст, МаскаШапки) <> 0 Тогда

             ИмяВТ = "ВТТабШапка" ;//Идентификатор временной таблицы

             Запрос.Текст = СтрЗаменить(Запрос.Текст, МаскаШапки, " " + ИмяВТ + " ");

            

             //Делаем одну строку таблицы на шапку

             ТЗШапка = Новый ТаблицаЗначений();

             СтрокаШапки = ТЗШапка.Добавить();

             //Берем реквизиты шапки

             Для Каждого МДРеквизит ИЗ МД.Реквизиты Цикл

                    ТЗШапка.Колонки.Добавить(МДРеквизит.Имя, МДРеквизит.Тип);

             КонецЦикла;

             //Берем ссылку

             ТЗШапка.Колонки.Добавить("Ссылка", ТипСсылка);

             //СтрокаШапки.Ссылка = ДокументОбъект.Ссылка;

             //Берем номер

             Если МД.ТипНомера = Метаданные.СвойстваОбъектов.ТипНомераДокумента.Строка Тогда

                    ТЗШапка.Колонки.Добавить("Номер", Новый ОписаниеТипов("Строка",,Новый КвалификаторыСтроки(МД.ДлинаНомера)));

             Иначе

                    ТЗШапка.Колонки.Добавить("Номер", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(МД.ДлинаНомера)));

             КонецЕсли;

             //СтрокаШапки.Номер = ДокументОбъектНовый.Номер;

             //Берем дату

             ТЗШапка.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата",,, Новый КвалификаторыДаты(ЧастиДаты.ДатаВремя)));

             //СтрокаШапки.Дата = ДокументОбъектНовый.Дата;

            

             ЗаполнитьЗначенияСвойств(СтрокаШапки, ДокументОбъектНовый);

            

             ЗапросТМП.Текст = "Выбрать * ПОМЕСТИТЬ " + ИмяВТ + " Из &Таб Как Т";

             ЗапросТМП.УстановитьПараметр("Таб", ТЗШапка);

             ЗапросТМП.Выполнить();

       КонецЕсли;

 

 

      

       Возврат ДокументОбъектНовый;

      

КонецФункции

Скачать файлы

Наименование Файл Версия Размер
down.zip
.zip 10,52Kb
15.02.12
19
.zip 10,52Kb 19 Скачать

См. также

Добавить вознаграждение
Комментарии
1. Модератор раздела Артур Аюханов (artbear) 17.02.12 10:09 Сейчас в теме
Подход давно известен, конечно, применимость его очень редкая :)
Но для начинающих подойдет.
Но обязательно нужно упомянуть, что печать незаписанных документов может приводить к расхождениям бумажных документов и документов в базе.
ИМХО Название "виртуальный документ" нужно заменить на более точный термин - типа "Незаписанный документ" и т.п.
2. Осипов Сергей (fixin) 3437 17.02.12 10:34 Сейчас в теме
(1) не знаю, не знаю. я допёр сам до этого "широко известного подхода".

Здесь вроде бы были еще комменты про то, как начать транзакцию, изменить и распечатать. У меня глюки, происки модеров или глюк форума?
3. Александр Зубцов (iov) 358 17.02.12 13:01 Сейчас в теме
(0) Конечно подход интересен но учитывая присутствие в типовых механизмов проверки на модифицированность объекта
сводит на нет многие потуги. и приходится добавлять разнообразно извращенные механизмы.
Почти согласен с применением серийных номеров/серий/характеристик и прочая типовая_геммороидальная_супер_нано_техноголия которая дает нам работу (можно как молитву перед едой читать) но самый частый вопрос - кто изменил документ и что там изменилось.
Но это нисколько не принижает достоинства приведенного метода.
+ в карму
4. Модератор раздела Сергей Лунев (luns) 22.02.12 13:02 Сейчас в теме
(2) когда сообщение скрыто, нумерация остается: