Создание Генератора отчета независимого от *.exe и файлов *.fr3

отредактировано 14:42 Раздел: FastReport 4.0
Перечитал массу веток, но так и не смог найти того чего хочу. Проблему кратко описал в теме.
Моя среда: Oracle, DelphiXE, Odac.
Отчеты только из хранимых процедур с In и Out параметрами.
In параметры - для критериев выборки это п.2
Out параметры - для дополнения инфы к отчету это п.3

Теоритическая задумка такова:
1. В репорте, в диалоге в событии клик кнопки переношу значения полей в заранее указанные UserVariables
2. В frxDBDataSet в событии BeforeOpen из UserVariables перекачиваю в In парметры OdacStoredProc и открываю курсор для MasterDataset
3. Возвращенные параметры OdacStoredProc заношу в репорт через событие OdacStoredProc.AfterOpen

Но эта теория.
Пожскажите пожалуйста проф. подход?
Т.е. как положено делать эти операции более красиво? Особенно не нравиться п.3, мне нужно его выполнить перед отображением отчета.
Прошу авторизацию по ADO не предлагать.

Комментарии

  • отредактировано January 2012
    Нашел удобное событие у frxReport.OnBeforePrint
    Оно работаетв аккурат между Диалоговым окном и Запуском отчета.
    Выше описаные операции п.2 и п.3 заложил в это событие, работает отлично.

    procedure TfRep.frRepBeforePrint(Sender: TfrxReportComponent);
    var
    s: string;
    i,k: integer;
    begin
    if pOpen then exit;
    pOpen := true; //Этот флаг сделал, т.к. событие вызывается почему то несколько раз
    //Название процедуры селекта(курсора) в таблице БД, как и сам файл fr3(но его я загрузил в другом методе)
    s := spEdit.FieldByName('proc_select_' + copy(aSp.Name,length(aSp.Name),1)).AsString;
    if s = '' then exit;
    aSp.StoredProcName := s;
    aSp.PrepareSQL;
    //Здесь я выполняю п.2 перекачиваю полученные из диалога значения переменных в параметры вызова процедуры
    for i := 0 to aSp.ParamCount - 1 do
    with aSp.Params do
    begin
    if (ParamType <> ptInput) and (ParamType <> ptInputOutput) then continue;
    k := frRep.Variables.IndexOf(name);
    if k <> -1 then Value := frRep.Variables.Items[k].Value;
    end;
    aSp.Close;
    aSp.Open;
    //Здесь выполняю п.3 закачиваю полученные параметры из процедуры в отчет, типа кто запускал отчет и т.п.
    for i := 0 to aSp.ParamCount - 1 do
    with aSp.Params do
    begin
    if (ParamType <> ptOutput) and (ParamType <> ptInputOutput) then continue;
    k := frRep.Variables.IndexOf(name);
    if k <> -1 then
    begin
    if (DataType = ftString) or (DataType = ftMemo) or (DataType = ftWideString) or (DataType = ftWideMemo) or (DataType = ftFixedChar) or (DataType = ftFixedWideChar) then
    frRep.Variables.Items[k].Value := '''' + VarAsType(Value,varString ) + ''''
    else frRep.Variables.Items[k].Value := Value;
    end;
    end;
    end;

    Теперь осталось совсем ничего чтобы проект был не зависим от exe и fr3 файлов.
    Судя о работоспособности отчета, я выяснил, что MasterData1 на лету цепляет frxDBDataset. Это радует.
    Но теперь уперся в пока не разрешимую проблему. Кажется GroupHeader на лету не цепляет frxDBDataset
    и у меня поэтому щас пока не разрешимая ошибка GroupHeader1: Ошибка в выражении 'dsProc_select_1."ROLENAME"': Identifier expected
    В проекте где все зашито, т.е. нет динамической загрузки отчета и названия процедуры, все ок.
  • отредактировано January 2012
    Проблему решил динамическим созданием всех объектов. Все работает супер!
    Я свободен от exe файла проекта и fr3 файлов!!!
    Сделал так:
    1. В БД Оракл создал таблицу с названием 5 процедур курсоров и 5 процедур lookup, а также файл fr3.
    2. Создаем отчет fr3 с использованием строго опредленных имен компонентов OdacStoredProc1-5.
    - создаем юзер переменные одинаковые с переменными хранимых процедур курсоров
    - в диалог окне по событию Ok кнопки закачиваем параметры окна в юзер переменные
    3. Мой класс делает следующее:
    - создает 5 процедур курсоров и 5 процедур lookup и заполняются названия на основе таблицы п.1.
    - загружает файл fr3
    - в диалог окна заполняем Caption название отчета
    - открываем все 5 lookup процедур(конечно только указанные в таблице), процедуры курсоров пока закрыты
    - запускается отчет frxReport.ShowReport
    - в событии frxReport.BeforePrint которое выполняется после диалога, но до запуска отчета
    + загружаются юзер переменные отчета(в которых уже п.2 залит) в схожие In и InOut параметры всех 5 процедур курсоров(которые заполнены в таблице)
    + открываются методом Open все 5 процедур курсоров
    + перекачиваются Out и InOut параметры в отчет
    Все отчет получен!!! Классы форм не используются!

    В самой программе я просто загружаю из БД список отчетов в опредленное меню "Отчеты", а в tag-ах у меня храниться ID
    Невероятная гибкость и свобода/независимость от обновлений EXE и FR3 файлов.

    Мне достаточно в дизайнере настроить отчет, создать диалог, даже dblookup могу юзать, и залить в БД. Все!!!
    Никаких геморов с перекомпиляцией, копированием fr3 файлов на юзерский комп, вешалкой с окном критериев!
    Если понравилось, то могу позже и исходниками подолиться.
  • gpigpi
    отредактировано 14:42
    Совсем ничего не понял: ни того, что было нужно, ни того, что сделано
    Шаблоны отчётов можно хранить в базе, критерии выборки можно передавать из диалоговой формы отчёта в программу через пользовательскую функцию
    Кроме того, можно использовать internal-датасеты ODAC для FR для создания полностью автономных отчётов (если поддержка хранимых процедур реализована devart)
  • отредактировано 14:42
    to gpi
    Вы не могли бы описать кратко, как вы используете/добавляете отчеты в проекте, не компилируя exe и не копируя fr3 на клиентский комп юзеров?
  • gpigpi
    отредактировано 14:42
    Демо-пример хранения отчётв в базе в конце этого топика:
    http://www.fast-report.com/en/forum/index.php?showtopic=4853
  • отредактировано January 2012
    gpi
    Вы жжете ).
    Стоит ли мне продолжать с вами обсуждать топик, если вы путаете методы с идеей ?
    Причем тут блоб? Или как ложить в БД fr3? Заострение внимания на этих элементарных вещах не было моей целью...
    Что с того что вы сохранили fr3 в БД ? А дальше то что?

    В моей идее идет полная независимость не только от exe или fr3, а также почти САМОЕ важное независимость от многих
    видов отчетов(разных если хотите). Простое хранение в таблице инфы по названиям 5 процедур селектов и 5 процедур lookup-ов в настоящий момент
    позволяет мне разрабатывать РАЗНЫЕ отчеты не зависимо от exe и fr3. Кстати в критериях стали юзеры просить уже более
    5 lookup, много справочников хотят, наверно увеличу до 10. Также перед запуском отчета я передаю список ID, что выбрал
    в гриде юзер, т.к. много отчетов и зависимых от выбора юзера строк. Я работаю с devexpress, вот код получения списка ID,
    при вызове отчета из меню главной формы:

    function TCore.GetGridIDs(aMDIform: TForm): string;
    var
    i,j,k: integer;
    g: TfrGrid;
    vId: integer;
    begin
    Result := '';
    for i := aMDIform.MDIChildCount - 1 downto 0 do
    with aMDIform.MDIChildren do
    if Active then
    for j := 0 to ControlCount - 1 do
    if (Controls[j].ClassType = TfrGrid) and (TfrGrid(Controls[j]).grdGrid.Focused) then
    begin
    g := TfrGrid(Controls[j]);
    vId := g.GetColumnIdx('id');
    if vId = -1 then exit;
    with g.grdGrid.Controller do
    for k := 0 to SelectedRecordCount - 1 do Result := Result + SelectedRows[k].DisplayTexts[vId] + ',';
    Result := copy(Result,1,length(Result)-1);
    exit;
    end;
    end;

    Я знаю, что процедуры мало кто юзают, но тогда теряется вся прелесть гибкости.
    Очень важно различать смысл Param и Field.
    Param я определяю автоматом по названию процедур, а там еще и типы параметров IN, INOUT, OUT.
    Field читаю только после заполнения Param.

    Вот частичный пример отчета в БД состоящий из 1 процедуры селекта и 1 lookup.
    Соответственно 1 селект юзаем в MasterData1, а lookup в DBlookup диалог окна критерия.
    Как видно, что Param хранимой процедуры aSigner мой клиент делфи понимая по признаку OUT читает его из БД и
    заливает потом в отчет. Сами данные отчета это возвращенный курсор хранимой процедуры, открытый в делфях по OraStoredProc.Open

    function rep_1(
    aBegin date,
    aEnd date,
    aBank number,
    aSigner out varchar2
    ) return sys_refcursor
    is
    vCur sys_refcursor;
    begin
    begin
    select name into aSigner from secur u where u.username = user;
    open vCur for
    select r.rolename, u.name, cnt_sign, cnt_nosign, cnt_forsign
    from
    (
    select
    doc_id,
    sign_user,
    ...
    where
    t.sign_user = u.username and
    t.doc_id = r.rfrl_id
    order by 1, 2;
    return vCur;
    exception
    when no_data_found then null;
    end;
    end;

    function rep_1_Bank return sys_refcursor
    is
    vCur sys_refcursor;
    begin
    open vCur for select c.id, c.name from bank c order by name;
    return vCur;
    exception when no_data_found then null;
    end;

    Использование хранимых процедур для в моей идеи решает ряд важных задач:
    - высокая безопасность, т.к. доступ к коду sql запроса исключен
    - исправление логики извлечения данных отчетов можно полностью контролировать(исправлять) в БД
    - унификация/систематизация отчетов(все процедуры отчета описаны в одной таблице). В автономных отчетах искать запрос и или процедуру будет весьма не удобно, как разработчику, так и службе безопасности при делегировании прав...
    - благодаря стандартному универсальному подходу можно реализовать автоматический запуск разных отчетов по расписанию, пока не делал, не требуется

    В MSSQL также можно легко применить мою идею.

    gpi вы там выше написали, что ничего не поняли, могу пояснить по любому открытому вопросу еще детальнее.
  • gpigpi
    отредактировано 14:42
    написал:
    gpi
    Вы жжете ).
    Стоит ли мне продолжать с вами обсуждать топик, если вы путаете методы с идеей ?
    Думаю, что нет
  • отредактировано 14:42
    Вы как то странно повели диалог. Вместо того, что бы объяснить что же Вы всетаки сделали и за что Вас нужно резко похвалить, Вы сходу нагрубили человеку попытавшемуся Вам помочь.
    Объясните "на пальцах" что же Вы сделали. Лично я ничего не понял. Что значит "независимость от exe"? Что это такое? Для чего нужно? А потом уже будем ругаться :)
  • отредактировано 14:42
    Лично я тоже ничего не понял.
    У себя храню отчёте в базе, при старте читаются хранимкой все необходимые отчёты для данного приложения и инициализируются в соответствующие комбобоксы (пока трафик нет смысла экономить). При вызове - создаётся отчет (если в первый раз), запихивается в него шаблон и запускается. Параметры для отчета через переменные
  • отредактировано February 2012
    Yura & Dima,
    Да ладно, никому не собирался грубить, на обиженных воду возят...

    3 и 7 пост являются исчерпывающими для понимания, "что" было сделано.
    Я так понимаю не прояснено более внятно "почему" это было сделано и как следствие много не пониманий о чем
    речь. У меня за плечами 4 летний опыт работы в бизнес интеллидженс, др. словами клепал я отчеты сотнями...

    И так, "почему" я решал проблему независимости.
    Во-первых, чтобы писать программы, а не отчеты.
    Во-вторых, на разработке отчетов люди(часто прогеры) тратят очень много времени, из них только 20% на логику
    и 80% на оформление.
    В третьих, у нас тут по штату есть кому отчеты писать, так почему прогер должен это делать?

    Правила, которые соблюдает уважающий себя репортер:
    1. Не мешать программистам. Не трогать их *.exe проекты. Иметь возможность самостоятельно создавать и
    редактировать отчеты для прогеров. Задачи должны быть раздельными, прогеры пишут, а репортеры зная только
    SQL писали отчеты.
    2. Диалог окно отчета должно иметь в критерях lookup. Lookup - это комбобокс возвращающий данные из БД.
    Т.к. масса отчетов требуют выбора записи из списка.
    3. Никаких сетевых доступов, т.е. не надо чтобы пользователь из-за кривых ручек сисадминов имел гемор с
    файлами лежащими на шарах, например при загрузке отчетов fr3 или dll
    4. Отчет должен получать входящие параметры из текущего грида юзера ID или список ID из программы прогеров
    *.exe. Это очень важно, т.к. находясь например в таблице документов, требуется распечатать именно тот на
    котором стоит курсор.
    5. Репортер должен иметь возможность залить произвольное кол-во "точечных" данных в отчет. Точечные это не
    мастер детаил или гридовые данные, а конкретные переменные, типа Имя пользователя, какие-то специфичные
    данные и т.д.

    Структура и шаги выполнения отчета:
    1. Диалог окно критериев
    2. Заполненное диалог окно юзером
    3. Запуск отчета
    4. Заполнение отчета(результат), как табличными данными, так и точечными.

    Пункты 1 и 4 самые сложные в реализации независимости от exe и fr3. В зависимых проектах эти пункты
    разрабатываются в самом дельфи, неважно полностью или частично, что естественно приводит к постоянной
    перекомпиляции exe, или созданию dll(но тут репортер должен знать делфи).

    Как я решил проблему я уже описал.
    Теперь все понятно? Пишите еслив че.
  • отредактировано 14:42
    Ничего не понял - если честно.
    Как сделано у меня. Сами отчеты лежат в базе. Если пользователю надо, он через справлчник открывает нужный отчет. Или создает новый.
    Выставляет в каких формах и для каких пользователей будет доступен отчет.
    В программе открывается форма - загружаются имена доступных отчетов в меню.
    Если пользователь вызывает отчет. Отчет загружается из БД ему передаются необходимые параметры.
    В том числе и списки выбранных значений. Типа вашего (TCore.GetGridIDs(aMDIform: TForm): string; или массив данных. что доступно для этой формы
    Отчет выводится. какая привязка к EXE ? Создавай сколько хочешь отчетов.
    Если в самом отчете нужно в диалоге нужно LookUP поля выводить - Перейди на вкладку данные - создай запрос и выводи из него
    Или добавь переменные из параметров.
  • отредактировано February 2012
    Я балдею от пипла, что на этом форуме тусуется...везде "не понял" ))) капец... Знаете за что я не люблю депутатов, за их абстрактные разговоры "...мы работаем над этим...", "...это уже выполнено...", "...тут необходима коррекция..." и т.д. Как будто все автоматом все поняли и разжевали. Ведь результат: потеря времени, загаженный форум и раздражение юзеров... Уважаю профи, за их ...не смейтесь это очень важно, за их ДЕТАЛИЗАЦИЮ, но без воды конечно.
    Поэтому я создал эту ветку. Зацените кол-во просмотров и за какой промежуток времени это их собралось ).

    Konst,
    Благодарю за частичное вникание в мою идею.
    Вот перечитал ваш пост, вы хоть представляете сколько вопросов он нагенерил? а вы "ничего не понял".
    И так вам вопросы на вскидку:
    1. Какая БД ?
    2. В каком событии и как передаются "необходимые параметры" ?
    3. Каким образом вы принимаете параметры из п.2 ?
    4. Если вы говорите, что юзер может создавать отчеты, то в каком месте и как вызывается открытие LookUp ? Только без гипотетических слов "можно", а именно практический метод, просто можно многое, а надо то что работает.
    5. Вы используете контролы датасеты fr3 или дельфовский(exe) через провайдер ?
    6. Контрол сессии БД вы юзаете fr3 или дельфовский(exe) ? Если fr3, то как создаете сессию, нет ли дыры в безопасности?
    Буду ждать ответа по пунктам.
  • отредактировано 14:42
    1. Какая разница, если доступ к базе идёт с отчёта
    2. В переменных
    3. Простым
    4. Заполняются при старте отчёта, перед формой диалога
    5. контролы и датасеты fr3
    6. Коннект к базе из программы
  • отредактировано February 2012
    А я вот балдею от программистов, которые не могут сформулировать задачу и описать ее решение. При этом гнут пальцы в спирали.

    1. Оракл
    2. Пишем класс TfrxParams - список объектов типа TfrxParam. Параметр содержит название, тип и значение. Если надо - добавляем еще какие-либо характеристики. Регистрируем класс в движке. Да вообще вариантов масса - хоть передавай в отчет всю свою форму вместе с гридом.
    3. Вариантов несколько. Например, в отчете создаем объект типа TfrxParams. Добавляем в него нужные параметры. Через вызов из отчета некой функции, экзешник заполняет параметры нужными значениями.
    4. Опять же несколько вариантов. Например, у меня для типовых контролов (например, просмотр групп товаров) сделаны свои классы, которые зарегистрированы в движке. Юзер просто бросает их на форму и указывает сессию. Для нетиповых задачь опять же есть класс типа TQuery. Из экзешника передается экземпляр открытой с БД сессии.
    5. Свои. На базе DOA.
    6. Сессия передается из экзешника. Жесткого контроля по безопасности нет, т.к. не требуется задачей. Но не вижу проблем закрутить гайки.

Оставить комментарий

Многофункциональный текстовый редактор. Чтобы отредактировать стиль параграфа, нажмите TAB, чтобы перейти к меню абзаца. Там вы можете выбрать стиль. По умолчанию не выбран ни один стиль. Когда вы выберете текст, появится встроенное меню форматирования. Нажмите TAB, чтобы войти в него. Некоторые элементы, такие как многофункциональные вставки ссылок, картинок, индикаторов загрузки и сообщений об ошибок могут быть вставлены в редактор. Вы можете перемещаться по ним, используя стрелки внутри редактора и удалять с помощью клавиш delete или backspace.