Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass main report data source to subreport (JasperReports)?

I'm using JasperReports and I fill the JRDataSource for ther report. Now, I want to pass the main REPORT_DATA_SOURCE to the subreport. How can I do this?

As far as I know the REPORT_DATA_SOURCE is a consumable object, so it can only be used once, right?. Can I copy this data source and pass it?

BTW: I use iReport for creating the layout.

like image 596
adis Avatar asked Dec 13 '11 14:12

adis


People also ask

How do you use data source in Jasper report?

Jaspersoft Studio provides a visual tool to map JavaBean attributes to report fields. To use it, open the query window, go to the tab JavaBean Data Source, insert the full class name of the bean you want to explore, and click Read attributes. The tab is populated with the attributes of the specified bean class.


3 Answers

You can pass datasource via the built-in REPORT_DATA_SOURCE parameter.

The example:

<subreport>     <reportElement x="261" y="25" width="200" height="100"/>     <dataSourceExpression><![CDATA[$P{REPORT_DATA_SOURCE}]]></dataSourceExpression>     <subreportExpression><![CDATA[$P{SUBREPORT_DIR} + "subreport.jasper"]]></subreportExpression> </subreport> 

You can create new instance of datasource based on variable, parameter or field.

The sample:

<variable name="HeadingsCollection" class="java.util.Collection" calculation="System">     <initialValueExpression><![CDATA[new java.util.ArrayList()]]></initialValueExpression> </variable> ... <subreport>     <reportElement x="0" y="0" width="515" height="20"/>     <subreportParameter name="ReportTitle">         <subreportParameterExpression><![CDATA[$P{ReportTitle}]]></subreportParameterExpression>     </subreportParameter>     <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($V{HeadingsCollection})]]></dataSourceExpression>     <subreportExpression class="java.lang.String"><![CDATA["HeadingsReport.jasper"]]></subreportExpression> </subreport> 

Another sample:

<field name="cast" class="java.util.Collection"/> ... <subreport>     <reportElement positionType="Float" x="15" y="25" width="245" height="20" isRemoveLineWhenBlank="true" backcolor="#99CCFF"/>     <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{cast})]]></dataSourceExpression>     <subreportExpression class="java.lang.String"><![CDATA["JRMDbCastSubreport.jasper"]]></subreportExpression> </subreport> 

Or you can pass the datasource via the parameter:

<parameter name="SubreportDataSource" class="net.sf.jasperreports.engine.JRDataSource"/> ... <subreport>     <reportElement positionType="Float" x="15" y="25" width="245" height="20" isRemoveLineWhenBlank="true"/>     <dataSourceExpression>$P{SubreportDataSource}</dataSourceExpression>     <subreportExpression class="java.lang.String"><![CDATA["Subreport.jasper"]]></subreportExpression> </subreport> 

Note: Using the same (with master report) datasource in subreport can cause the effect of loosing the first row in the subreport. You can read Why is the first record missing from my subreport? post for understanding how to avoid this issue.

like image 71
Alex K Avatar answered Sep 23 '22 14:09

Alex K


Yes, you need to be careful about how to pass a data source. With a SQL connection, you can just pass a Connection Expression like $P{REPORT_CONNECTION}. Then the subreport has its own SQL query.

In your case you want to pass the actual data. Depending on the details, it might be as simple as just defining a Parameter Map Expression like $P{REPORT_PARAMETERS_MAP}. It's on a different tab in that same window where you set the subreport connection in iReport. Often this is sufficient to pass the data source.

But you might need a little code to handle things. Consider this example with a CSV data source re-used in subreports. The reason why you can't just use the JRParameter.REPORT_DATA_SOURCE object is because the index row pointer is never reset, so passing that original object into the subreport will bring the recordset to its close prematurely. We solved this with a minimal helper class:

package com.jaspersoft.untested_unsupported; 

import java.io.File; 
import java.io.FileNotFoundException; 
import net.sf.jasperreports.engine.JRDataSource; 
import net.sf.jasperreports.engine.data.JRCsvDataSource; 

public class CsvDataSourceFactory { 
    public static JRDataSource getDataSource(String fileName, boolean firstRowHeaders) throws FileNotFoundException { 
        JRCsvDataSource csvDs = new JRCsvDataSource(new File(fileName)); 
        csvDs.setUseFirstRowAsHeader(firstRowHeaders); 
        return csvDs; 
    } 
}
like image 31
mdahlman Avatar answered Sep 22 '22 14:09

mdahlman


we suppose that the datasource parameter is "dataSourceParam" and the datasource value (list) is "dataSourceList" in java class we put :

final Map<String, Object> params = new HashMap<String, Object>();
JRDataSource dataSource = new ListOfArrayDataSource( dataSourceList, 
                          new String[] {"date", "age", "adress", "email"});
params.put("dataSourceParam",dataSourceList);**

in main report template we put in parameters declaration :

<parameter name="dataSourceParam" class="net.sf.jasperreports.engine.JRDataSource"/>

then in subreport tag we put :

<subreport isUsingCache="true">
    <reportElement key="subreport-1" stretchType="RelativeToTallestObject" isPrintRepeatedValues="false" x="112" y="45" width="338" height="29"/>
    <subreportParameter name="otherParameter">
        <subreportParameterExpression><![CDATA[$P{sumM1}]]></subreportParameterExpression>
    </subreportParameter>
    <dataSourceExpression><![CDATA[$P{dataSourceParam}]]></dataSourceExpression>
    <subreportExpression class="net.sf.jasperreports.engine.JasperReport"><![CDATA[$P{subReportFile}]]></subreportExpression>
</subreport>
like image 45
Shessuky Avatar answered Sep 24 '22 14:09

Shessuky