Рендеринг отчёта с разными параметрами

Обсуждение Stimulsoft Reports.NET
Леонид
Сообщения: 329
Зарегистрирован: 23 июл 2009, 09:53
Откуда: Moscow

Рендеринг отчёта с разными параметрами

Сообщение Леонид »

Добрый день!

Возникла такая ситуация: необходимо распечатать пакет документов, в частности счетов-фактур.
Мы решили её примерно таким способом:

Код: Выделить всё

      // create main report
      StiReport stiReport = new StiReport()
      {
        NeedsCompiling = false,
        IsRendered = true,
      };

      // clear blank page
      stiReport.RenderedPages.Clear();

      // create sub report
      StiReport subReport = new StiReport();      
      subReport.Load("test.mrt"); // load report <--- если перенести эту строку в первую строку цикла foreach, то всё работает, как ожидалось

      // numbers list for a test
      List<int> numbers = new List<int>() { 111, 222, 333 };

      // traverse through the list
      foreach (int x in numbers)
      {
        subReport.Dictionary.Variables["AVar_0"].Value = x.ToString(); // set report variable
        subReport.Dictionary.Synchronize(); // synch dictionary

        // render sub report
        subReport.Render(false);

        // add rendered pages
        foreach (StiPage repPage in subReport.RenderedPages)
        {
          repPage.Report = stiReport; // set main report as a container
          stiReport.RenderedPages.Add(repPage); // add each page of the report to the main report
        }

        subReport.RenderedPages.Clear(); // drop rendered pages
        subReport.IsRendered = false; // drop rendered flag
      }

      // show final report
      stiReport.Show();
Собственно вопрос в том, почему при выполнении вышеуказанного кода метод Render выполняется, но данные остаются те же, что были, когда он вызывался первый раз.
При это, если вызывать метод Load каждый раз перед рендерингом (методом Render), то всё работает, как ожидалось.

В вышеуказанном примере на каждой из трёх страниц будет выводится 111, а должно выводится 111 на первой странице, 222 на второй и 333 на третьей. Что мы делаем не так?
Aleksey
Сообщения: 2907
Зарегистрирован: 22 апр 2010, 06:57

Re: Рендеринг отчёта с разными параметрами

Сообщение Aleksey »

Здравствуйте,

Пожалуйста, попробуйте использовать следующий код:

Код: Выделить всё

...
subReport.Load("e:\\1.mrt"); // load report <--- если перенести эту строку в первую строку цикла foreach, то всё работает, как ожидалось
subReport.Compile();
// numbers list for a test
List<int> numbers = new List<int>() { 111, 222, 333 };

// traverse through the list
foreach (int x in numbers)
{
    subReport["AVar_0"] = x; // set report variable
    //subReport.Dictionary.Synchronize(); // synch dictionary

    // render sub report
    subReport.Render(false);
...
Спасибо.
Леонид
Сообщения: 329
Зарегистрирован: 23 июл 2009, 09:53
Откуда: Moscow

Re: Рендеринг отчёта с разными параметрами

Сообщение Леонид »

Очень круто!

Работает!!! Огромное спасибо! :)

P.S. Единственное, что

Код: Выделить всё

subReport["AVar_0"] = x;
Вызывает Object of type 'System.Int32' cannot be converted to type 'System.String'., поэтому писать нужно

Код: Выделить всё

subReport["AVar_0"] = x.ToString();
Ivan
Сообщения: 641
Зарегистрирован: 10 авг 2006, 05:40
Откуда: Stimulsoft Office

Re: Рендеринг отчёта с разными параметрами

Сообщение Ivan »

Здравствуйте.

Дайте нам знать, если вам понадобится ещё какая-нибудь помощь.

Спасибо.
Леонид
Сообщения: 329
Зарегистрирован: 23 июл 2009, 09:53
Откуда: Moscow

Re: Рендеринг отчёта с разными параметрами

Сообщение Леонид »

Добрый вечер!

В процессе работы выяснился некоторый неприятный нюанс - если в отчёте есть Connection (в нашем случае это подключение к Oracle) и DataSource, то отчёт выполняется верно, т.е. данные выводятся, но все корректно.

Поясню на том же простом примере. У нас есть простой массив из чисел 111, 222, 333, 444 и 555, его мы выводим в переменную на DataBand1, - всё работает корректно.
Дальше, у нас есть Connection (к Oracle) и DataSource с таким вот (для примера, разумеется) простым select'ом:

Код: Выделить всё

select (case when :DOC_CODE = 111 then 'Номер 1'
             when :DOC_CODE = 222 then 'Номер 2'
             when :DOC_CODE = 333 then 'Номер 3'
             when :DOC_CODE = 444 then 'Номер 4'
             when :DOC_CODE = 555 then 'Номер 5'
        end) as caption_field
  from dual
При этом здесь есть входящий параметр DOC_CODE типа decimal, его мы используем в событии объекта Report BeginRender() так:

Код: Выделить всё

Field1 = AVar_0;

// set param value
DataSource1.Parameters["DOC_CODE"].ParameterValue = decimal.Parse(AVar_0);

// connect to data source
DataSource1.Connect();

// set result
Caption1 = DataSource1.CAPTION_FIELD;
В результате данные в Field1 (который выводится на DataBand1) отображаются корректно, а данные из select'а "со сдвигом" ровно на одну страницу, т.е. на первой странице они пустые, а со второй отображаются как "Номер 1", на третьей "Номер 2" и т.д., а должно отображаться с первой страницы.

Причём, если установить значение переменной AVar_0 ещё до метода Compile(), то строка "Номер1" выведется на первой странице, как надо, но проблему это не решает, т.к. "Номер1" выведется и на второй странице, и далее, как описано выше.

Полностью рабочий код на C#:

Код: Выделить всё

      // create main report
      StiReport stiReport = new StiReport()
      {
        NeedsCompiling = false,
        IsRendered = true,
      };

      // clear blank page
      stiReport.RenderedPages.Clear();

      // create sub report
      StiReport subReport = new StiReport();      
      subReport.Load("test.mrt"); // load report
//      subReport.Dictionary.Variables["AVar_0"].Value = docCodesList[0].docCode.ToString(); // take first code from list
      (subReport.Dictionary.Databases[0] as StiOracleDatabase).ConnectionString = oraConnectionString; // set connection string before compiling
      subReport.Dictionary.Synchronize();
      subReport.Compile(); // compile report

      // numbers list for a test
      List<int> numbers = new List<int>() { 111, 222, 333, 444, 555 };

      // traverse through the list
      foreach (int x in numbers)
      {
        subReport["AVar_0"] = x.ToString(); // set report variable        

        // render sub report
        subReport.Render(false);

        // add rendered pages
        foreach (StiPage repPage in subReport.RenderedPages)
        {
          repPage.Report = stiReport; // set main report as a container
          stiReport.RenderedPages.Add(repPage); // add each page of the report to the main report
        }
      }

      // show final report
      stiReport.Show();
Рабочий тестовый пример во вложении.
Вложения
test.mrt
(6.67 КБ) 361 скачивание
Aleksey
Сообщения: 2907
Зарегистрирован: 22 апр 2010, 06:57

Re: Рендеринг отчёта с разными параметрами

Сообщение Aleksey »

Здравствуйте,

Не смогли воспроизвести проблему. Пожалуйста, уточните какую версию вы используете.

Спасибо.
Вложения
Снимок.PNG
Снимок.PNG (42.38 КБ) 3829 просмотров
Леонид
Сообщения: 329
Зарегистрирован: 23 июл 2009, 09:53
Откуда: Moscow

Re: Рендеринг отчёта с разными параметрами

Сообщение Леонид »

Добрый день!

Версия отчёта: 2015.2.0.0.

Да, с цифрами на DataBand1 проблем и не было, я говорил о цифрах из select'а Oracle, значения из которого записываются в ReportTitle1 (см. скриношот). Проблема не решена, т.к. Вы её не воспроизвели.
Вложения
Clipboard03.png
Clipboard03.png (22.24 КБ) 3827 просмотров
Aleksey
Сообщения: 2907
Зарегистрирован: 22 апр 2010, 06:57

Re: Рендеринг отчёта с разными параметрами

Сообщение Aleksey »

Здравствуйте,

Вы подключаете данные в BeginRender событии, там еще нет данных. Пожалуйста, перенесите ваш код в событие BeforePrint страницы.

Спасибо.
Леонид
Сообщения: 329
Зарегистрирован: 23 июл 2009, 09:53
Откуда: Moscow

Re: Рендеринг отчёта с разными параметрами

Сообщение Леонид »

Добрый день!

Проверил много раз, в итоге, да, на тестовых данных всё работает, но на наших почему-то по-прежнему нет.
Буду готовить вам отчёт, как он есть с реальными данными, чтобы показать суть. Там будет всего несколько страниц (для теста хватит). Не пойму в чём дело.

Однако, у нас более 190 отчётов, в которых метод .Connect прописан в событии BeginRender объекта отчёта, поэтому конечно, не хотелось бы всё это переносить во всех отчётах в событие BeforePrint.

На данный момент, мы делаем так: получаем список кодов отчётов и кодов документов, затем пробегаемся по всем уникальным кодам отчётов, чтобы загрузить их в MemoryStream из OracleBlob (т.к. они могу повторятся, например, накладных может быть 500 или более, т.к. они печатаются за период для налоговой), и получается, что меняют только данные, а так пока сделали отчёт, который загружает blob'ы (реально это .mrt-файлы) из базы, а потом просто делаем в цикле (как в тестовом примере) .Load(reportBody), где reportBody это просто MemoryStream получаемый из списка типа List<MemoryStream> по коду отчёта.
Однако, это медленно, и ~1000 страниц рендерится таким образом ~11-12 минут вместо одной, как в случае с .Compile().

Так что через какое-то время подготовлю тестовую версию отчёта и попрошу вас помочь разобраться, возможно, я что-то не знаю или не учёл.
Aleksey
Сообщения: 2907
Зарегистрирован: 22 апр 2010, 06:57

Re: Рендеринг отчёта с разными параметрами

Сообщение Aleksey »

Здравствуйте, Леонид

Необходим пример отчета для анализа. Постараемся разобраться.

Спасибо.
Ответить