Reporting Data Source Factory
  • Updated on 06 Jun 2017
  • 3 minutes to read
  • Print
  • Dark
    Light

Reporting Data Source Factory

  • Print
  • Dark
    Light

Overview

Creating custom data sources for reports is useful when you know ahead of time what all of the data sources will be. When the list of data sources can only be known at runtime, it's useful to create a data source factory that can create the necessary list of data sources at runtime. The Decisions SDK provides classes that help you create data source factories. An example of doing that is detailed below.
Please review the documentation on creating a Custom Reporting Data Source if necessary, as it describes the type of data source that the data source factory will provide for Decisions.

A Simple Data Source Factory

Before creating a data source factory class, create the class that represents the various data sources the factory will produce. As an example, let's examine a case where each data source reads its information from a database table.

TableDataSource

The class below is a Data Source that takes a database table name as a parameter in its constructor.  Based on that, the class returns the columns it wants to provide to reports in the ReportFields property, and the report data from the GetData() method.

 using System.Data;
using DecisionsFramework.Design.ConfigurationStorage.Attributes;
using DecisionsFramework.Design.Report;

namespace MyNamespace
{    
    [Writable]
    public class TableDataSource : AbstractCustomDataSource, ISpecifiedCategoryReportFilter
    {
        public string TableName { get; set; }

        public TableDataSource(string tableName)
        {
            TableName = tableName;
        }

        public override bool Applies(ReportDefinition definition)
        {
            return definition.HasDataSourcesOrFilters() == false;
        }

        public override ReportFieldData[] ReportFields
        {
            get
            {
                // Here, the class could access the database to discover what the columns are.
                // To simplify this example, we will return two columns of data.
                return new ReportFieldData[] { new ReportFieldData(TableName, "Column1", typeof(int)),
                                               new ReportFieldData(TableName, "Column2", typeof(string))};
            }
        }

        public override DataTable GetData(DataTable table, IReportFilter[] filters, int? limitCount, int pageIndex)
        {
            // create the DataTable if it doesn't exist yet
            if (table == null) table = new DataTable();

            // set up the columns in the DataTable based on the ReportFields
            table.Columns.AddRange(GetColumnsFromReportFields(ReportFields));

            // At this point, the class would read the rows from the database and fill the DataTable
            // [CODE OMITTED]

            return table;
        }

        // This property, implemented as part of ISpecifiedCategoryReportFilter,
        // allows the class to specify which category it belongs in.
        public string[] Category
        {
            // For this example, specify a sample category name.
            get { return new string[] { "My Database Table Sources" }; }
        }

        // When used with a Data Source Factory, Data Sources have their names pulled from the ToString() method.
        public override string ToString()
        {
            return TableName;
        }
    }
}

Note that this class has the [Writable] attribute applied to it.  This is required when a data source is used by a data source factory.  Because a data source factory will be registering instances of this data source class, the [AutoRegisterReportElement] attribute mentioned in the Custom Reporting Data Source example is not used.

TableDataSourceFactory

Now a data source factory can be created, which creates objects of the TableDataSource class and returns them:

 using System.Collections.Generic;
using DecisionsFramework.Data.ORMapper;
using DecisionsFramework.Design.Report;

namespace MyNamespace
{    
    [AutoRegisterReportElementFactory("My Database Table Sources", "Sample Factory")]
    class TableDataSourceFactory : IFilterFactory
    {
        // This method returns the data sources that Decisions should use.
        public IReportFilter[] GetFilters(CompositeSelectStatement compositeSelectStatement, IReportFilter[] currentFilters)
        {
            List<ireportfilter> results = new List<ireportfilter>();

            // Here, the class would determine which database tables should be made available as data sources
            // based on whatever logic is required.
            // As an example, two tables are used as parameters for TableDataSource objects.
            results.Add(new TableDataSource("dog"));
            results.Add(new TableDataSource("cat"));

            return results.ToArray();
        }

        // This method is part of the IFilterFactory interface, but not necessary for this example.
        // DataSources that implement the ICustomFilter also implement an IncludeRow(DataRow row) method,
        // which allows them to filter out individual rows from the report.
        public ICustomFilter[] GetCustomFilters(ReportDefinition def, IReportFilter[] currentFilters)
        {
            return null;
        }
    }
}
</ireportfilter></ireportfilter>

The [AutoRegisterReportElementFactory] attribute tells Decisions that this class is a factory that provides Reporting Data Sources.  Decisions will call the GetFilters() method to retrieve the data sources and make them available in the selection list for report designers to pick from.  After building these two classes in a project with the Decisions SDK and installing it (for details, see Creating a Module ), the two TableDataSources appear:
DataSourceFactory1.png

Was this article helpful?