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

7

44

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.

Thiele answered 13/12, 2011 at 14:8 Comment(0)
F
50

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.

Fin answered 13/12, 2011 at 21:24 Comment(5)
link to "Why is the ... " is not accessible anymore. Login & password is required.Batch
Why is the first record missing from my subreport is available again without a login.Swain
i've posted a solution that prevents the "record missing" issue and lets use the subreport as main report (using the subreport datasource and fields)Eventual
see also #29943970Shiah
How to actually use the "cast" parameter in the subReport?Pederson
P
4

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>
Plotter answered 10/5, 2012 at 14:0 Comment(0)
B
2

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; 
    } 
}
Buller answered 13/12, 2011 at 18:11 Comment(0)
X
1

"REPORT_DATA_SOURCE" is a consumable object, You can used as much time as you want.

I have test the datasource as xml File dataSource, and won't be appeared as ALEX said.

"this will not be loosing the first row in subreport."

I think may be i use the xpath to select, so every time won't be loss records.

If you use JDBC Database as the datasource, pealse pass the sql as parameter to subreport.

If you use ResultSet as the parameter, maybe loss one record as you definition the subreport in detail bands.

Xena answered 7/11, 2013 at 7:43 Comment(0)
E
1

It's an old question already answered but i get to pass the undelying bean to the subreport, avoiding the loss of the first record or passing all the records to subreport. This solution has the advantage that the subreport can be used as main report and is "simply" pass the actual record as subreport datasource (using groovy as report lang):

<subreport>
    <reportElement x="261" y="25" width="200" height="100"/>
    <dataSourceExpression><![CDATA[new JRBeanCollectionDataSource(
       $P{REPORT_DATA_SOURCE}.data.toList().subList($V{REPORT_COUNT}-1,$V{REPORT_COUNT})]]></dataSourceExpression>
    <subreportExpression><![CDATA[$P{SUBREPORT_DIR} + "subreport.jasper"]]></subreportExpression>
</subreport>
Eventual answered 10/3, 2017 at 9:41 Comment(2)
In my old version with Java, at least, .data is not a visible field.Compellation
yeah, groovy allows you to access private fields, not sure if there is a way to read it with javaEventual
A
1

I had a situation where I had a table in a subreport. The subreport only has a title band and a summary band, with the table in the summary. I wanted to use the subreport datasource for the table as well, but could not get either of the approaches in the accepted answer to work. So here as an alternative approach that is working great in version 6.6.0:

In the main report:

        <subreport>
            <reportElement x="0" y="0" width="468" height="0" uuid="c057b890-3889-43dd-8634-bbf2e857cc0d"/>
            <subreportParameter name="partsList">
                <subreportParameterExpression><![CDATA[$F{drawingRevision}.getPartsList()]]></subreportParameterExpression>
            </subreportParameter>
            <subreportExpression><![CDATA["static/engineering/drawings/subreports/DrawingPartsList.jasper"]]></subreportExpression>
        </subreport>

The key here is that the List is being passed as a parameter and NOT as a datasource like:

<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{drawingRevision}.getPartsList())]]></dataSourceExpression>

The subreport then includes:

...
<parameter name="partsList" class="java.util.List" isForPrompting="false"/>
...
<summary>
    <band height="60" splitType="Stretch">
        <componentElement>
            <reportElement key="table" style="table" x="0" y="0" width="468" height="60" uuid="09499b35-b122-4fe4-a2b3-d91d6a19b2ab"/>
            <jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" whenNoDataType="AllSectionsNoDetail">
                <datasetRun subDataset="PartList" uuid="87fcbcc9-f0f0-4397-87f2-237201fc1857">
                    <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($P{partsList})]]></dataSourceExpression>
                </datasetRun>
...

Note that in the subreport you also need to include the property whenNoDataType="AllSectionsNoDetail" or something like that, otherwise the subreport will be blank because it has no data.

Ashil answered 29/10, 2018 at 17:49 Comment(0)
E
0

Just to complete Alex K's answer, what really made it work for me was to clone the data source as follows:

<dataSourceExpression><![CDATA[((net.sf.jasperreports.engine.data.JRBeanCollectionDataSource) $P{REPORT_DATA_SOURCE}).cloneDataSource()]]></dataSourceExpression>
Ezarra answered 7/7, 2020 at 12:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.