Skip to main content Skip to footer

Using Parameters and Multiple Data Sources in FlexReport

When creating reports with FlexReport, there are a few things to consider when it comes to accessing your data. There are cases where you want to provide a full database or table of information on a report but there are others where you want to limit that information. For example, if you’re creating an invoice report, you wouldn’t want an invoice for every order in your database. Just a specific order.

There are two ways you can restrict the amount of information loaded in FlexReport: parameters and filtering. The primary difference between the two is when the manipulation occurs. Parameters are included in a WHERE clause in your SQL command and, therefore, only pull the records from the server you need. Filters require you to load all the data and then only include the specified records in the report. There are definitive scenarios where each is useful.

To give a practical example of both methods, I have created a demo application that produces an invoice report based on the orders table in the sample NorthWind AccessDB provided with our samples.

Please note: Since I’m using an AccessDB for this sample, I have to use the 32bit version of FlexReportDesigner because the Microsoft JET provider is only 32bit. If you want to modify the InvoiceFlexReport.flxr in the sample, you will need to open it with the 32-bit version of FlexReportDesigner.

You can find that version here:

C:\Program Files (x86)\ComponentOne\Apps\v4.5.2\C1FlexReportDesigner32.4.5.2.exe

If you're using a SQL database, you can use either a 32bit or 64bit FlexReportDesigner as there are SQL data providers for both.

Establishing the Main Data Source

First, we need to create a new FlexReport report definition. Open FlexReportDesigner and click “New Report." Now we need to establish the data for our report. I am using the C1NWind.mdb that we provide in the Documents/ComponentOne Samples/Common folder.

I am using the following Connection String:

Provider=Microsoft.Jet.OLEDB.4.0;Data Source=?(SpecialFolder.MyDocuments)\ComponentOne Samples\Common\C1NWind.mdb;Persist Security Info=False

Note: I’m using “?(SpecialFolder.MyDocuments)” since the documents’ folder path is dependent on the login of the machine (IE C:\Users\andrew.paxinos\Documents)

Now we need to figure out what data we need. The orders table includes the OrderID I want to report on, as well as most of the details. However, it only includes a CustomerID foreign key reference. To get both the orders and customer table in the same Data Source, I’m going to have to use a join.

SELECT Orders.OrderID, Orders.OrderDate, Orders.ShippedDate, Orders.ShipName, Orders.ShipAddress, Orders.ShipCity, Orders.ShipRegion, Orders.ShipPostalCode, Customers.CompanyName, Customers.Address, Customers.City, Customers.Region, Customers.PostalCode FROM Orders INNER JOIN Customers ON Orders.CustomerID=Customers.CustomerID

Using Parameters and Multiple Data Sources in FlexReport

Creating a Parameter

Next, I need to establish a parameter so I can provide a specific OrderID to report on. Right-click on “Parameters” in the “Data” tab and click “Add Parameter."

Using Parameters and Multiple Data Sources in FlexReport

Name the new parameter: pOrderID.

Using Parameters and Multiple Data Sources in FlexReport

Now, right-click on the main data source we created earlier and select “Edit."

Using Parameters and Multiple Data Sources in FlexReport

We need to add a WHERE clause to the SQL SELECT statement that uses the parameter we just created. In our case, we will add WHERE OrderID = pOrderID to the end.

SELECT Orders.OrderID, Orders.OrderDate, Orders.ShippedDate, Orders.ShipName, Orders.ShipAddress, Orders.ShipCity, Orders.ShipRegion, Orders.ShipPostalCode, Customers.CompanyName, Customers.Address, Customers.City, Customers.Region, Customers.PostalCode FROM Orders INNER JOIN Customers ON Orders.CustomerID=Customers.CustomerID WHERE OrderID = pOrderID

Desigining the Report

Next, we will lay out the report header using the fields from both tables in a Sold To/Shipped To arrangement.

Using Parameters and Multiple Data Sources in FlexReport

For the Detail section of the report, we need to pull the individual line items for each order from the order details table related to the OrderID. In this case, it will make sense to utilize a subreport so let’s create a new empty report and name it "InvoiceSubReport."

Using Parameters and Multiple Data Sources in FlexReport

Click over the “Data” tab, right-click on “Main”, and select “Edit." Use the same connection string. In this case, we will need all the fields from the order details table. However, it only includes a ProductID foreign key so we will use another join to pull in the ProductName from the products table.

SELECT [Order Details].OrderID, Products.ProductName, [Order Details].UnitPrice, [Order Details].Quantity, [Order Details].Discount FROM [Order Details] INNER JOIN Products ON [Order Details].ProductID = Products.ProductID;

Please note: I am including the order details ProductID column even though I’m not displaying it in the subreport. I’m doing this so I can link the main and subreport via that field. Also, you do not need to include a parameter or WHERE clause in the subreport. Then, I laid out the fields in the subreport (see below).

Using Parameters and Multiple Data Sources in FlexReport

Click back to the “InvoiceReport” and click the “Insert" tab in the ribbon at the top and select "SubReport > InvoicesSubReport." Then, draw the subreport into the details section of the report.

Using Parameters and Multiple Data Sources in FlexReport

Using Parameters and Multiple Data Sources in FlexReport

Right-click on the “Subreport” and select “Link Subreport."

Using Parameters and Multiple Data Sources in FlexReport

Ensure the “OrderID” column is selected for both master and child report and click “OK."

Using Parameters and Multiple Data Sources in FlexReport

For this sample, I will be modifying the subreport’s datasource at runtime (for the filtering example) so I will also rename the field “subInvoiceSubReport” to more easily identify it later.

Using Parameters and Multiple Data Sources in FlexReport

Using FlexReport and FlexViewer in a .NET Application for Display

Since the report is finished, let's build the application. I’m going to be doing a Winforms app for this sample, but the same concepts will work on any platform.

I’m going to emulate a common design I’ve seen our customers use. There will be a main form with a grid displaying all the orders from the orders table. A user can select one of the orders in the grid and there will be a button that loads a new form with a report version of the invoice.

First, I’m going to drop a C1FlexGrid on the form and 2 .NET buttons. One button will generate a FlexReport via the parameter, and the other will use filtering and an XML/DataTable datasource.

Using Parameters and Multiple Data Sources in FlexReport

Next, I’m going to fetch the orders table from the AccessDB we used for the report, place that data in a .NET DataTable, and bind the FlexGrid to it. I will also disable editing for FlexGrid and add the following code for the button click events:

        public Form1()  
        {  
            InitializeComponent();  
            // Find the current users Documents folder  
            string documentsfolder = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);  
            // Establish connection string for Northwind Access DB in the ComponentOne Samples/Common folder  
            string connString = @"Provider=Microsoft.Jet.OLEDB.4.0;Data Source="+ documentsfolder +@"\ComponentOne Samples\Common\C1NWind.mdb";

            // Create a DataTable and fill it with the contents of the Orders table  
            DataTable dt = new DataTable();  
            using (OleDbConnection conn = new OleDbConnection(connString))  
            {  
                OleDbCommand cmd = new OleDbCommand("Select * FROM Orders", conn);  
                conn.Open();  
                OleDbDataAdapter adapter = new OleDbDataAdapter(cmd);  
                adapter.Fill(dt);  
            }  
            // Bind the FlexGrid to the Orders table  
            c1FlexGrid1.DataSource = dt;  
            // Disable editing (grid being used a selector only)  
            c1FlexGrid1.AllowEditing = false;  
        }

        private void btnParameter_Click(object sender, EventArgs e)  
        {  
            // Get the value of the cell in the currently selected row and column OrderID  
            int OrderID = (int)c1FlexGrid1[c1FlexGrid1.Row, c1FlexGrid1.Cols["OrderID"].Index];  
            // Create an instance of frmFlexReport and pass OrderID  
            frmFlexReport Report = new frmFlexReport(OrderID);  
            Report.Show();  
        }

        private void btnFilter_Click(object sender, EventArgs e)  
        {  
            // Get the value of the cell in the currently selected row and column OrderID  
            int OrderID = (int)c1FlexGrid1[c1FlexGrid1.Row, c1FlexGrid1.Cols["OrderID"].Index];  
            // Create an instance of frmFlexReportFilter and pass OrderID  
            frmFlexReportFilter Report = new frmFlexReportFilter(OrderID);  
            Report.Show();  
        }  

Using Parameters

For the parameter version, I created an additional Windows form named frmFlexReport and modified it’s constructor to accept an int value being passed (the OrderID from the FlexGrid’s selected row OrderID column). Next, I load the Invoice.flxr file in the reports folder and the InvoiceReport report, set the parameter pOrderID to the value passed in, and load the FlexViewer.

    public partial class frmFlexReport : Form  
    {  
        // Note, modified constructor to accept int to be passed  
        public frmFlexReport(int pOrderID)  
        {  
            InitializeComponent();  
            // Load the Report  
            c1FlexReport1.Load(."./../Reports/Invoice.flxr", "InvoiceReport");  
            // Set the parameter with the value selected in the grid  
            c1FlexReport1.Parameters["pOrderID"].Value = pOrderID;  
            // Load the FlexViewer  
            c1FlexViewer1.DocumentSource = c1FlexReport1;  
        }  
    }

Using Filters

For the filter version, I have created 2 XML files in the /Data folder of the sample that contain the same columns and data that were included in the AccessDB. That data is loaded into two .NET DataTables. I load the same FLXR and InvoiceReport. Next, I modify the loaded report’s main DataSource.RecordSet to point to the appropriate DataTable. Then I capture the FlexReport’s.Fields[“subInvoiceSubReport”] field as a SubReportField object and that allows me to set the subreport’s DataSource.RecordSet to the other DataTable.

Then, clear the parameter collection because we no longer have a datasource with a WHERE clause so we cannot use parameters. Finally, we set the DataSource.Filter property to a string of OrderID, equal the value passed in the constructor, and load the FlexViewer control,which renders the report.

    public partial class frmFlexReportFilter : Form  
    {  
        // Note, modified constructor to accept int to be passed  
        public frmFlexReportFilter(int pOrder)  
        {  
            InitializeComponent();

            // Load dataTables from .xml files in the /Data folder  
            DataTable dtOrdersCustomer = new DataTable();  
            dtOrdersCustomer.ReadXml(."./../Data/OrdersCustomer.xml");  
            DataTable dtOrderDetailsProducts = new DataTable();  
            dtOrderDetailsProducts.ReadXml(."./../Data/OrderDetailsProduct.xml");

            // Load the Invoice Report  
            c1FlexReport1.Load(."./../Reports/Invoice.flxr", "InvoiceReport");

            // Replace the existing SQL data source by pointing directly to the DataTable  
            c1FlexReport1.DataSources["Main"].Recordset = dtOrdersCustomer;

            // Capture the SubReport field from the InvoiceReport and create a .NET object named subInvoiceSubReport  
            C1.Win.FlexReport.SubreportField subInvoiceSubReport = c1FlexReport1.Fields["subInvoiceSubReport"] as C1.Win.FlexReport.SubreportField;  
            // Set the SubReport's DataSource RecordSet to the other DataTable  
            subInvoiceSubReport.Subreport.DataSources["Main"].Recordset = dtOrderDetailsProducts;

            // Clear the Parameter collection (since we're not using it anymore)  
            c1FlexReport1.Parameters.Clear();  
            // Set the Filter String  
            c1FlexReport1.DataSources["Main"].Filter = "OrderID = " + pOrder.ToString();  
            // Load the FlexViewer  
            c1FlexViewer1.DocumentSource = c1FlexReport1;  
        }  
    }

Hopefully, this will give you a better understanding of how you can use and manipulate data when working with FlexReport. Depending on the size and access speed of your data source using parameters will normally result in better performance because you are only pulling down the data you need for the report. However, if you’re in a situation where you can’t utilize a WHERE clause or if you need to manipulate the data before presenting it on the report (but don’t want to push those changes to the data source), filter may be a good option.

Andy Paxinos

Junior Product Manager
comments powered by Disqus