It is a regular situation when a developer has to deal with the input data having the structure not really suitable for the report output. Of course, it would be a lot more convenient for the developer if the input data was initially converted to a proper format, but this could cause a number of problems. First of all, if the data is presented by the subsystem the developer cannot affect, it would cause difficulties in data coordination. Secondly, as we know, many various reports can use the same data and this would make the generation of specific input data for each particular report quite an uncomfortable task . Thirdly, the report structure can vary easily and rewriting the data subsystem each time is not the best thing a developer can think of. On the other hand, the developer can use the initial data format without modifying it, but this can also be unacceptable as the report complexity would increase without a necessity.
The most acceptable approach in this situation would be modifying the raw data into the easy-to-use structure. To do this, a couple of things should be taken into consideration. The first is that report’s CommonScript property makes possible describing our own classes. And the second one is that by using DataObjects.Add method we can register our own data sources on par with other report data sources.
A study case.
Let’s look into the sample from our first article (http://blogs.perpetuumsoft.com/dotnet/taming-the-crossband/) and assume we receive the data in the following view, which looks pretty similar to picking the data from an ordinary database:
- public class RawData
- {
- public int Year { get; set; }
- public String ParameterName { get; set; }
- public double Value { get; set; }
- }
If you managed to read the first article of the series, you possibly noticed the fact that the idea of our success is using the convenient data structures, rather than RawData as such. It appears the RawData would not let us create anything so easy and so simple for our test cases. But basically, we are not limited to anything, that’s why we can easily transform the data to look the same way as it was in our first article.
To begin with, we should declare those ‘comfy’ data structures in CommonScript of our sample report. Please note, the constructors of our classes allow creating the whole matrix by passing the parameter names and year values which will come in handy when filling declared data structures:
- public class TableData
- {
- public TableData(string[] parameterNames, string[] columnNames)
- {
- Rows = new System.Collections.Generic.List<TableRow>();
- ColumnNames = new System.Collections.Generic.List<string>(columnNames);
- for(int i = 0;i < parameterNames.Length;i++)
- {
- TableRow row = new TableRow(columnNames.Length);
- row.Name = parameterNames[i];
- Rows.Add(row);
- }
- }
- public System.Collections.Generic.List<string> ColumnNames {get;set;}
- public System.Collections.Generic.List<TableRow> Rows { get; private set; }
- }
- public class TableRow
- {
- public string Name { get; set; }
- public TableRow(int columnsCount)
- {
- Values = Enumerable.Repeat(0d, columnsCount).ToList();
- }
- public System.Collections.Generic.List<double> Values { get; set; }
- }
Further we get our data source in GenerateScript of the document:
- System.Collections.Generic.List rawData = DataObjects["rawData"] as System.Collections.Generic.List;
At this point we should convert this data into a structure defined in CommonScript. Let’s assume the data subsystem developers overlooked the aspect of grouping the data, and occasionally we come across multiple data for the same combination of parameters. In this case we should sum this data up.
For simplicity’s sake we can use Linq (please refer to the article under the link for more information http://helpcenter.perpetuumsoft.com/KB/a496/using-linq-in-complex-scenarios-in-sharpshooter-reports.aspx). We would get the years and parameter lists, create the matrix and fill it in by iterating through the data:
- var years = rawData.Select(x => x.Year.ToString()).Distinct().OrderBy(x=>x).ToArray();
- var parameters = rawData.Select(x => x.ParameterName).Distinct().OrderBy(x=>x).ToArray();
- var data = new TableData(parameters, years);
- for(int i = 0;i < rawData.Count;i++)
- {
- int rowIndex = Array.IndexOf(parameters, rawData[i].ParameterName);
- int columnIndex = Array.IndexOf(years, rawData[i].Year.ToString());
- data.Rows[rowIndex].Values[columnIndex] += rawData[i].Value;
- }
Finally, we should add a newly created data source to our report data sources list:
- DataObjects.Add(“data”, data);
…and see the result.
The sample for the article can be found under the following link:
http://perpetuumsoft.com/Support/samples/CrossBandSampleDataConvertation.zip