Crystal Reports Online Training

Learn Online, Anytime, Anywhere

Step-by-step online tutorials.

17.16 Object Collections and LINQ

Reporting from an Object Collection

One of the data types that the SetDataSource() method accepts is System.Collections.IEnumberable. This lets you print data that is stored within an object collection. For example, it’s easy to report from an ArrayList because it implements the IEnumerable interface. You can even create a custom collection class as a data source as long as it follows this rule.

There are two requirements for using an object collection. The first is that the project declares a class with public properties. Crystal Reports uses the public class properties to define the fields in the report. The second requirement is that the collection class implements the IEnumerable interface. Let’s walk through an example to see how this works.

In the Solution Explorer, right-click on the project name and select Add > New Item. In the Add New Item window, select Class and enter the name User. Then click the Add button to add it to your project.

For this simple example, there will only be two properties: FirstName and Lastname. Enter the following code for the class.

Listing 17-10. Code for the User class.
[VB.NET]
Public Class User
Private _FirstName As String
Private _LastName As String
Sub New(ByVal FirstName As String, ByVal LastName As String)
_FirstName = FirstName
_LastName = LastName
End Sub
Public Property FirstName() As String
Get
Return _FirstName
End Get
Set(ByVal value As String)
_FirstName = value
End Set
End Property
Public Property LastName() As String
Get
Return _LastName
End Get
Set(ByVal value As String)
_LastName = value
End Set
End Property
End Class
[C#]
public class User
{
private string _FirstName;
private string _LastName;
public User(string FirstName, string LastName)
{
_FirstName = FirstName;
_LastName = LastName;
}
public string FirstName
{
get { return _FirstName; }
set { _FirstName = value; }
}
public string LastName
{
get { return _LastName; }
set { _LastName = value; }
}
}

The next step is to create a report and use this class as the data source. Right-click on the project and select Add > New Item and choose Crystal Report. In the Report Wizard, get to the Data tab and open the Project Data node. Then open the .NET Objects node. Find the name of the User class in this list and double-click it to add it to the Selected Tables list on the right.

Crystal Reports doesn’t always recognize when you add a new class to the project. If the new class isn’t shown in the .NET Objects list, right-click on that node and select Refresh. Selecting Refresh forces it to re-examine your project and rebuild the list of classes.

After adding the class to the Selected Tables list, click the Next button and add the fields to the Fields To Display list. Click the Next button or the Finish button, depending upon whether you want to customize the report or not.

At this point, you have a report that was built using the class properties to define the fields that will be displayed. Now you need to create an array to store a collection of those objects and pass this array to the SetDataSource() method of the ReportDocument object. The code in listing 17-11 should can be put in the form’s Load() event or attached to a button. Make sure the form has a viewer control on it as well.

Listing 17-11. Create an object collection and pass it to the report.
[VB.NET]
Imports System.Collections

'Create the list of names
Dim UserNames As New ArrayList
UserNames.Add(New User("Cesar", "Serna"))
UserNames.Add(New User("Napolean", "Serna"))
UserNames.Add(New User("Brian", "Bischof"))
'Load the report
Dim myReport As CrystalDecisions.CrystalReports.Engine.ReportDocument
myReport = New CrystalDecisions.CrystalReports.Engine.ReportDocument
myReport.Load("..\..\CrystalReport1.rpt")
'Pass the collection to the report's data source
myReport.SetDataSource(UserNames)
'Preview the report
CrystalReportViewer1.ReportSource = myReport
[C#]
using System.Collections;

//Create the list of names
List UserNames = new List{
new User("Cesar", "Serna"),
new User("Napolean", "Serna"),
new User("Brian", "Bischof")
};
//Load the report
CrystalDecisions.CrystalReports.Engine.ReportDocument myReport;
myReport = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
myReport.Load(@"..\..\CrystalReport1.rpt");
//Pass the collection to the report's data source
myReport.SetDataSource(UserNames);
//Preview the report
crystalReportViewer1.ReportSource = myReport;

In this listing, the UserNames variable is the array list for storing the collection of User objects. The first part instantiates this variable and fills it with sample names using the Add() method. For your own reports, you would build the collection in whatever way is appropriate for your application.

After creating the list of names, the report is loaded into memory and passes the UserNames collection to the report using the SetDataSource() method. The last line passes the report to the viewer and it displays the data in the UserNames collection on the report.

As you can see, the SetDataSource() method makes it easy to builds reports using object collections.

Reporting From LINQ Objects

Microsoft created LINQ (.NET Language Integrated Query) so that programmers can query data sources within their application. This lets you apply SQL-like queries to non-traditional data sources such as a data view or an object collection. Being able to easily filter data within an object collection is quite powerful!

The LINQ libraries give you numerous ways for querying data from different data sources. It is a complex topic and beyond the scope of this book to discuss in detail. If you search the internet for “scott guthrie linq pdf”, you will find a free online book that gives you a complete tutorial on how to implement LINQ in your own applications.

Microsoft released the LINQ language features for both .NET 2005 and .NET 2008. In .NET 2005 it is an optional install, and in .NET 2008 it is installed by default. Crystal Reports only added support for LINQ in .NET 2008. The code in this section will not work for .NET 2005.

LINQ lets you query a data source in your application and it returns the result set in an IEnumerable collection. As you learned in the previous section, Crystal Reports can report from IEnumerable. Consequently, it is very easy to build reports using LINQ.

Reporting from a LINQ query is almost identical to reporting from an object collection. With LINQ you use the LINQ query syntax to select data from a data source and return it in an IEnumerable collection. Pass this collection to the SetDataSource() method to generate a report with it.

In this example, we are going to create a UserNames collection like we did in Listing 17-11. But this time we will use LINQ to filter the data on last name and sort it by first name. Afterwards, we will assign it to the report and preview it.

Follow all the steps in the previous section, “Reporting From an Object Collection”, but replace Listing 17-11 with the code in Listing 17-12.

Listing 17-12.
[VB.NET]
'Create the list of names
Dim UserNames As New ArrayList
UserNames.Add(New User("Cesar", "Serna"))
UserNames.Add(New User("Napolean", "Serna"))
UserNames.Add(New User("Brian", "Bischof"))
'Use LINQ query to filter and sort the array list
Dim NewUsers = From myUser In UserNames _
Where myUser.LastName = "Serna" _
Order By myUser.FirstName _
Select myUser
'Load the report
Dim myReport As CrystalDecisions.CrystalReports.Engine.ReportDocument
myReport = New CrystalDecisions.CrystalReports.Engine.ReportDocument
myReport.Load("..\..\CrystalReport1.rpt")
'Pass the collection to the report's data source
myReport.SetDataSource(NewUsers)
'Preview the report
CrystalReportViewer1.ReportSource = myReport
[C#]
using System.Collections;
using System.Linq;

//Create the list of names
List UserNames = new List{
new User("Cesar", "Serna"),
new User("Napolean", "Serna"),
new User("Brian", "Bischof")
};
//Use LINQ query to filter and sort the array list
IEnumerable NewUsers;
NewUsers = from myUser in UserNames
where myUser.LastName == "Serna"
orderby myUser.FirstName
select myUser;
//Load the report
CrystalDecisions.CrystalReports.Engine.ReportDocument myReport;
myReport = new CrystalDecisions.CrystalReports.Engine.ReportDocument();
myReport.Load(@"..\..\CrystalReport1.rpt");
//Pass the collection to the report's data source
myReport.SetDataSource(NewUsers);
//Preview the report
crystalReportViewer1.ReportSource = myReport;

The code first creates the list of names, UserNames. Secondly, it declares the LINQ variable, NewUsers, that stores the results of our LINQ query and assigns it the query text. You can see that the last name is filtered to only show “Serna” and the list is ordered by first name. The PreviewReport() method takes the NewUsers object and passes it to the report object using the SetDataSource() method. Lastly, it passes it to the viewer to preview it.

The VB.NET code is a little less intuitive than the C# code. First of all, the NewUsers object variable is not strongly typed. This is because VB.NET automatically assigns the LINQ query type to it. Second, the UserNames variable is a generic ArrayList object and it doesn’t have the User class properties exposed. When entering the LINQ query, intellisense will not work for the FirstName and LastName properties. Nonetheless, type them in and the compiler will recognize them during runtime when the LINQ query executes.

You can see in this example, that it is very easy to create a report using LINQ.