Страница 1 из 1

Totals.ForEach ?

Добавлено: 08 ноя 2016, 13:47
DmitryRu
Здравствуйте.
Дано:
есть несколько отчетов, которые получают данные из SQL server.
Допустим, в отчете источником данных является таблица из 10 полей, Field1..Field10
Надо в этих отчетах вывести агрегаты total1, total2, формула рассчета примерно такая:

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

var total1 = 0;
var total2 = 0;
Для каждой строки Dataset: 
  total1 = total1 OR Field1;
  if (Field1 = 0) {
    total2 = total2 or Field2;
  }
И так повторяется 3 раза, для полей
  • Field1, Field2
  • Field3, Field4
  • Field5, Field6
Можно конечно разместить на отчете скрытый Databand и в нем все закодить вот это.
Но хочется написать одну свою функцию, и ее просто вызвать из всех отчетов.
Для этого мне нужен итератор по всем строкам источника данных Стимулсофт.
Я правильно понимаю, что мне подойдет любая из функций в классе Totals, например, Totals.Max()?
Или, может существует что-то, что только итерирует датасет и может вызывать мой callback?
Мне бы понравилась функция Totals.ForEach() :-)
Сосчитать эти агрегаты на стороне сервера не получится.

Заранее спасибо,
Дмитрий

Re: Totals.ForEach ?

Добавлено: 08 ноя 2016, 21:01
Aleksey
Здравствуйте,

Вы можете создать свою функцию, в которую передавать data source, и дальше в ней пробегать по всей таблице:

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

public double MyFunc(Stimulsoft.Report.Dictionary.StiDataSource dataSource)
{
	foreach (DataRow row in dataSource.DataTable.Rows)
	{
		// ваш код
	}
}
Спасибо.

Re: Totals.ForEach ?

Добавлено: 09 ноя 2016, 09:17
DmitryRu
Проблема в том, что интересующие данные находятся в другой таблице.
И если уж на то пошло, я в реальности работаю не с таблицами, а хранимой процедурой SQL Server, которая возвращает несколько таблиц. По этой причине связи между таблицами я прописываю в Стимулсофт.
И до интересующих данных я добираюсь с помощью Relation, который в .cs файле отчета выглядит так:

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

            public virtual ParentGroupDetailsRelation GroupDetails
            {
                get
                {
                    return new ParentGroupDetailsRelation(this.GetParentData("GroupDetailsRelation"));
                }
            }
Если я перейду на работу с датасетами .NET, я не очень понимаю как мне обращатся к связанным Dataset.
Кроме того, источники данных Стимулсофт дают мне "строгую типизацию", что мне нравится.

В принципе я посмотрел, как в .cs файле прописано вычисление Totals, и воспользовался для своих целей функцией Totals.MaxI, в callback'е этой функции провожу нужные мне вычисления. Вроде работает, но как-то не документированно

С уважением,
Дмитрий.

Re: Totals.ForEach ?

Добавлено: 10 ноя 2016, 10:06
Aleksey
Здравствуйте Дмитрий,

Можно в Totals, в выражение, передать сложную логическую конструкцию, но нужен пример отчета с данными, т.к. не совсем понятна структура данных и вообще порядок вычисления. Под конкретный пример проще написать.

Спасибо.

Re: Totals.ForEach ?

Добавлено: 10 ноя 2016, 11:11
DmitryRu
Пример отчета в сильно упрощенном виде

Таблица 1: Названия точек.
  • Point_ID int not null
  • PointName varchar(max)
Таблица 2: Суммы по точкам за период отчета
  • Point_ID int not null
  • Сумма1 double
  • Статус1 int
  • ДополнительныйСтатус1 int
  • Сумма2 double
  • Статус2 int
  • ДополнительныйСтатус2 int
  • Сумма3 double
  • Статус3 int
  • ДополнительныйСтатус3 int
Таблица 3: Детальные данные по точкам за период отчета
  • Point_ID int not null
  • DT DateTime not null
  • Значение1 double
  • Статус1 int
  • ДополнительныйСтатус1 int
  • Значение2 double
  • Статус2 int
  • ДополнительныйСтатус2 int
  • Значение3double
  • Статус3 int
  • ДополнительныйСтатус3 int
Надо вывести сначала таблицу с суммами по точкам, а потом графики с детальными данными.
У каждого значения 2 статуса. Каждый статус - битовая маска. Причем если в основном статусе не ноль, то значение дополнительного статуса неважно.
Если основной статус не ноль, то значение должно быть нарисовано красным цветом, а если дополнительный статус не ноль - то желтым цветом.
Поэтому перед отчетом надо написать легенду "Красные значения наверняка некорректные, а желтые - требуют повышенного внимания".
Причем легенду надо спрятать, если все значения корректные, как обычно и бывает.

И такая логика со статусами есть во многих отчетах, потому хочется написать одну функцию, которая сможет взять таблицу, пробежать по ней и сказать:
"В данной таблице результат OR над всеми плохими статусами == 0xXXXXX, а результат OR над всеми подозрительными статусами = 0xXXXX". Причем дополнительные статусы надо вычислять, только если основные статусы не ноль.

Произвести данное вычисление на сервере не получится.
Сейчас я для этих целей вызываю функцию Totals.MaxI, и передаю ей callback, который для каждой строки источника данных проверяет поля статусов и накапливает из в локальной переменной класса. Т.е. мое вычисление является "побочным эффектом" по отношении к функции Max. Так как на функцию MaxI я не нашел описания на уровне "для программиста", я решил уточнить, корректно ли мое предположение, что ее можно использовать как аналог оператора ForEach

Re: Totals.ForEach ?

Добавлено: 16 ноя 2016, 04:12
Ivan
Здравствуйте.
И такая логика со статусами есть во многих отчетах, потому хочется написать одну функцию, которая сможет взять таблицу, пробежать по ней и сказать:
"В данной таблице результат OR над всеми плохими статусами == 0xXXXXX, а результат OR над всеми подозрительными статусами = 0xXXXX". Причем дополнительные статусы надо вычислять, только если основные статусы не ноль.
В таком случае одним, даже сложным, выражением не обойтись. Надо использовать дополнительные функции.
Например, если в отчёте используется наша тестовая база данных Demo, в которой содержатся связанные таблицы Products и Categories, можно на закладке "Code" отчета написать вот такую функцию, которая будет суммировать все CategoryID из подчинённой таблицы через relation.

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

public double MyFunc()
		{
			double sum = 0;
			Products.SaveState("MyFuncState");
			Products.First();
			Products.ResetData();
			Products.ResetDetailsRows();
			while (!Products.IsEof)
			{
				sum += Products.Categories.CategoryID;
				Products.Next();
			}
			Products.RestoreState("MyFuncState");
			return sum;
		}
Приведённый пример только для демонстрации принципа работы с источниками данных.
Сейчас я для этих целей вызываю функцию Totals.MaxI, и передаю ей callback, который для каждой строки источника данных проверяет поля статусов и накапливает из в локальной переменной класса. Т.е. мое вычисление является "побочным эффектом" по отношении к функции Max. Так как на функцию MaxI я не нашел описания на уровне "для программиста", я решил уточнить, корректно ли мое предположение, что ее можно использовать как аналог оператора ForEach
Вообще по такому принципу работают все функции Totals, т.е. внутри находится только один метод для перебора всех записей, разница в том, что в разных перегрузках создаются разные аггрегатные функции.
Внутрь метода передаётся эта аггрегатная функция и callback-метод, который вызывается для каждой записи для получения текущего значения выражения, затем это значение передаётся в метод Calc аггрегатной функции для обработки.
Таким образом можно, например, наследовать свою функцию от стандартной, и перегрузить метод Calc.
При наличии исходников вы можете добавить новую свою аггрегатную функцию, которая в методе Calc будет делать необходимые вычисления.

Спасибо.