Передача результата запроса в таблицу управляемой формы. Мой алгоритм.

Всем, кто начинает работать с 8.2 после 8.1, не сразу становится понятным, зачем было настолько усложнять работу программистам.
На сервере мы можем выполнить запрос, на управляемую форму бросить таблицу значений, но вот передать результат запроса прямо в таблицу возможности нет. Я решил слегка упростить данный момент для разработки. Вот что у меня получилось.

Как всегда — стала задача разработки проекта для работы через http. Руководство сказало — есть 8.2, там есть веб-клиент. Вперед и с песней.

До тех пор, пока на формы бросались динамические списки или таблицы привязывались к регистрам — все было вроде понятно и разработка шла хорошо, но на определенном этапе понадобилось делать выборки и забрасывать результат именно в таблицы. И тут оказалось, что сделать это выгрузкой результата в таблицу невозможно. В результате в коде начало появляться множество функций &НаСервере, которые, по сути, были идентичные. Читабельность кода от этого не повысилась.

В результате мною коллегам был предложен следующий алгоритм.

В общем модуле, который доступен и серверу и управляемой форме (у меня модуль называется ОбщегоНазначенияКлиентСервер) создаем функцию ВыполнитьЗапросВТаблицу. Она будет выполнять полученный запрос, делать обход результата запроса, формировать структуру из каждой строки результата и каждую заполненную структуру добавлять в массив.


&НаСервере
Функция ВыполнитьЗапросВТаблицу(ЗапросТекст, СтруктураПараметров) Экспорт
    З = Новый Запрос(ЗапросТекст);
    Для каждого Параметр из СтруктураПараметров Цикл
        З.УстановитьПараметр(Параметр.Ключ, Параметр.Значение);
    КонецЦикла;
    Результат = З.Выполнить().Выгрузить();
    СтрокаСтруктуры = «»;
    МассивКолонок = Новый Массив;
    Для каждого Рез из Результат.Колонки Цикл
        Если НЕ СтрокаСтруктуры = «» Тогда
            СтрокаСтруктуры = СтрокаСтруктуры + «, «;
        КонецЕсли;
        СтрокаСтруктуры = СтрокаСтруктуры + Рез.Имя;
        МассивКолонок.Добавить(Рез.Имя);
    КонецЦикла;
    МассивСтрок = Новый Массив;
    Для каждого Рез из Результат Цикл
        СтруктураСтроки = Новый Структура(СтрокаСтруктуры);
        Для каждого кол из МассивКолонок Цикл
            СтруктураСтроки.Вставить(кол, Рез[кол]);
        КонецЦикла;
        МассивСтрок.Добавить(СтруктураСтроки);
    КонецЦикла;
    Возврат МассивСтрок;
КонецФункции


В управляемой форме нам понадобится одна функция на &НаСервере на всю форму, которая будет вызывать функцию общего модуля и передавать ей параметры, потому что из процедуры или функции &НаКлиенте управляемой формы сделать это не получается.


&НаСервере
Функция ПолучитьДанныеЗапроса(ТекстЗапроса, СтруктураПараметров)
    Возврат ОбщегоНазначенияКлиентСервер.ВыполнитьЗапросВТаблицу(ТекстЗапроса, СтруктураПараметров);
КонецФункции


Далее нам нужна еще одна процедура на управляемой форме &НаКлиенте, с помощью которой мы будем полученный результат вставлять в таблицу на форме.


&НаКлиенте
Процедура ПоместитьДанныеЗапросаВТаблицу(ТекстЗапроса, СтруктураПараметров, _ТаблицаПолучатель)
    _РезультатЗапроса = ПолучитьДанныеЗапроса(ТекстЗапроса, СтруктураПараметров);
    _ТаблицаПолучатель.Очистить();
    Для каждого Рез из _РезультатЗапроса Цикл
        НоваяСтрока = _ТаблицаПолучатель.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, Рез);
    КонецЦикла;
КонецПроцедуры


Все. Подготовительная часть закончена. После этого для заполнения таблицы значений на управляемой форме результатом запроса нужно в коде вписать вызов последней процедуры следующим образом:


ТекстЗапроса = «ВЫБРАТЬ … далее текст запроса … «;
СтруктураПараметров = Новый Структура(«Параметр1, Параметр2, Параметр3», ЗначениеПараметра1, ЗначениеПараметра2, ЗначениеПараметра3);
// Будем считать, что на форме есть ТаблицаЗначений с именем НашаТаблица
ПоместитьДанныеЗапросаВТаблицу(ТекстЗапроса, СтруктураПараметров, НашаТаблица);


Важно: Запрос должен быть составлен таким образом, чтобы возвращаемый результат был структурно идентичен нашей таблице значений, то есть типы значений колонок в результате запроса должны совпадать с типами значений колонок нашей таблицы значений и имена колонок в результате запроса должны совпадать с именами колонок таблицы значений.

Вот такой вот алгоритм. Код разжевывать не буду, по-моему там и так все понятно. Мега-гуру просьба не пинать сильно.

19 Comments

  1. Stepa86

    Я не понял, а что мешает на стороне сервера написать тзНаФорме.Загрузить( Запрос.Выполнить.Выгрузить() ) ?

    Reply
  2. Ivon

    (1) Ошибка с текстом «Нельзя изменять поле, содержащее объект данных формы».

    Reply
  3. Stepa86

    (2) а у меня вот это нормально работает:

    &НаКлиенте
    Процедура ЗаполнитьТЗ(Команда)
    
    ЗаполнитьОстаткиНоменклатуры();
    
    КонецПроцедуры
    
    Процедура ЗаполнитьОстаткиНоменклатуры()
    
    Запрос = Новый Запрос;
    Запрос.Текст = «ВЫБРАТЬ
    | ТоварыНаСкладахОстатки.Номенклатура,
    | ТоварыНаСкладахОстатки.КоличествоОстаток КАК Остаток
    |ИЗ
    | РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки»;
    
    тзНаФорме.Загрузить( Запрос.Выполнить().Выгрузить() );
    
    КонецПроцедуры
    

    Показать

    Reply
  4. Ivon

    (3). А у меня стабильно выдает ошибку. Какая у тебя версия платформы? У меня 8.2.14.528.

    Reply
  5. Stepa86

    (4) 8.2.14.537

    ты б обновился, а то какие то старые версии 14ой ключики жгут…

    Reply
  6. Ivon

    (5). У тебя база файловая или серверная? А то у меня на файловой тоже отрабатывает. А вот на серверной нет.

    Reply
  7. Stepa86

    (6) на серверной смотрел, да и не сталкивался я с такой ошибкой раньше ни разу ни на каких базах

    Reply
  8. Поручик

    Сложно сказать, сам пока не сталкивался. На всякий случай в закладки.

    Reply
  9. andboss

    Ну вы даете! Все гораздо проще: создается реквизит формы «ДанныеТЗ», тип(ТаблицаЗначений) которая связана с полем на самой форме, и в серверном вызове

    ТЗ = РеквизитФормыВЗначение(«ДанныеТЗ») — имеем обычную ТЗ

    заполняем как нам нужно

    и возврат

    ЗначениеВРеквизитФормы(ТЗ , «ДанныеТЗ»);

    ВСЕ!

    А мат. часть учите)

    Reply
  10. Ivon

    (9). Знаю-знаю про ЗначениеВРеквизитФормы. Только вот не всегда оно срабатывает. У меня вот не захотело отрабатывать и вылетало по ошибке. Почему-то. Потому и пришлось вот так вот извращаться. Вот у Stepa86 тзНаФорме.Загрузить(Запрос.Выполнить.Выгрузить()) работает. У меня опять же выдает ошибку.

    Если бы все было так просто, то не было бы так сложно.

    Reply
  11. necropunk

    ДЕйствительно, тожк пока не сталкивался, чтобы в реквизит загрузить не получалось. Но да, на всякий случай, в закладки закину, пожалуй…

    Reply
  12. Trofimov_M

    (10) Все должно работать

    Reply
  13. Арах

    а можно еще проще… да ошибка «Нельзя изменять поле, содержащее объект данных формы». присутствует но решается очень просто.

    Выборка = Запрос.Выполнить().Выбрать();

    Пока Выборка.Следующий() Цикл

    новаяСтрока = ТзФормы.Добавить();

    ЗаполнитьЗначенияСвойств(новаяСтрока , Выборка);

    КонецЦикла;

    Reply
  14. lukyan

    Чтобы не городить такой огород существуют штатные функции РеквизитФормыВЗначение(<ИмяРеквизита>, <Тип>), ЗначениеВРеквизитФормы(<Значение>, <ИмяРеквизита>).

    Reply
  15. Valerich

    (10) Попробовал, вот что получил:

    Делаю внешнюю обработку (может это тоже важно, не знаю). Задача — собрать некий массив информации и вывести его в файлы определенной структуры.

    В обработке добавил реквизит «Товары» с типом «ТаблицаЗначений». Из команды, которая на клиенте вызывается сервеерная функция формирования таблиц данных, которые потом буду выводить в файлы. Отображать эти таблицы на экране не обязательно, но с точки зрения понять как это можно сделать, не помешало бы.

    Далее собирался вызвать несколько процедур формирования файлов.

    Что имею:

    Таблица значений запросом получается на «ура» — через Товары = Запрос.выполнить().Выгрузить();, где Товары, очевидно, локальная переменная.

    Далее вызываю ЗначениеВРеквизитФормы( товары, «Объект.Товары»);

    При возврате на клиента Объект.Товары содержит нужное количество строк, но ни одной колонки.

    Если далее вызываю серверную функцию, в которой пишу Товары = РеквизитФормыВЗначение(«Объект.Товары»), то вижу то же самое — строки есть, а колонок (а значит и данных нужных мне) нет.

    Пробовал изначально задать колонки в клиенте, но нет свойства Объект.товары.Колонки… Тупик какой-то однако.

    Вывод — либо я дурак, либо одно из двух?

    Reply
  16. Ivon

    (15). Мой код выдает в результате массив структур, где элементы массива — строки, а элементы структуры — ячейки определенной колонки.

    Reply
  17. Valerich

    (16) сорри, Вашу идею я понял, вопрос хотел задать (9)

    Reply
  18. DDos76

    Ну хоть посмеялся. Вспомнил как в 7.5, когда еще не было таблицы значений, сохраняли списки в списки…

    Reply
  19. user_2010

    up

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *