Monday, May 5, 2008

Showing Reports by ReportViewer Control and NHibernate

Showing Reports by ReportViewer Control and NHibernate

In one of my Projects I was told to show some data using ReportViewer control and NHibernate. I had no idea how to do it.

Started Googling.... But I was quite surprised there was no such postings, even not found any information whether it is possible or not ! Never mind, started doing it and after completion found it pretty simple. Would like to share it with you.


Step 1:

I am using a single table, say Customers with the following schema :

Customers

CustomerID int IDENTITY(1,1) NOT NULL,

FirstName nvarchar(50) default NULL,

LastName nvarchar(50) default NULL,

Address nvarchar(150) default NULL,

PRIMARY KEY (CustomerID)

The Business Class is:

Customer.cs

namespace NHibernate.Example

{

public class Customer

{

public Customer()

{

}

private int id;

private string firstName;

private string lastName;

private string address;

public virtual int Id

{

get { return id; }

set { id = value; }

}

public virtual string FirstName

{

get { return firstName; }

set { firstName = value; }

}

public virtual string LastName

{

get { return lastName; }

set { lastName = value; }

}

public virtual string Address

{

get { return address; }

set { address = value; }

}

}

}

And Here is the Mapping file:

Customer.hbm.xml
(Click to view)



Step 2:

We have to create a Typed Dataset in App_Code folder of our Website (or you can have your separate Project Library for DataSet). The data table of this DataSet will contain the fields which we want to show in our Report. Here, I would like to show all the fields of my Customers table. Therefore my Dataset looks like this :



Step 3 :

Create a RDLC file. Arrange the fields just by dragging and dropping the fileds of Dataset which you will find "Website data Sources" toolbar (to view this toolbar just click the RDLC body, go to the menu "Data" --> "Show Data Sources").



Step 4:

Now the whole environment is ready for coding. Just add a ReportViewer to an aspx page and use the following code and you are done to throw some data on your screen!

using System;

using System.Collections;

using Microsoft.Reporting.WebForms;

using NHibernate;

using NHibernate.Example;

public partial class CustomerReport : System.Web.UI.Page

{

DataSet1 ds = new DataSet1();

NHibernate.Cfg.Configuration newConfig = new NHibernate.Cfg.Configuration();

ISessionFactory sFactory;

protected void Page_Load(object sender, EventArgs e)

{

if (!Page.IsPostBack)

{

newConfig = newConfig.AddAssembly("NHibernate.Example");

sFactory = newConfig.BuildSessionFactory();

rvCustomer.LocalReport.ReportPath = "TestReport.rdlc";

rvCustomer.LocalReport.ReportEmbeddedResource = "ReportViewer.TestReport.rdlc";

rvCustomer.LocalReport.DataSources.Clear();

ISession session = sFactory.OpenSession();

//get the list of customers using NHibernate

IList customers = session.CreateCriteria(typeof(Customer)).List();

//populate the typed Dataset

foreach (Customer customer in customers)

{

ds.Customers.AddCustomersRow(customer.Id.ToString(),

customer.FirstName,

customer.LastName,

customer.Address);

}

rvCustomer.LocalReport.DataSources.Add(

new ReportDataSource("DataSet1_DataTable1", ds.Customers));

}

// data Source name "DataSet1_DataTable1" generally made by DataSet name + "_"

// + DataTable name of the DataSet

}

}


Finally the Output :


----------------------------------------------------------

6 comments:

Anonymous said...

Hi there,

After having found out myself how to accomplish this (I also noticed that there are actually no resources on the internet... *sigh*), I also found your blog entry.

There's one step though, that you did more than I and I guess I know why:
You not only define the typed dataset so that you are able to design the report, you also fill it with the data you retrieve with NHibernate and use it as data source for your report.

I believe this is not necessary. When you look at the rdlc file with a text editor, you notice that it only needs the dataset (xsd) for getting to know the structure of the data that is about to be passed. Since you defined the structure already exactly as it looks like from NHibernate's point of view, you don't need the dataset anymore.

You can simply pass the data access object you get from NHibernate directly to the report and voila, it works. ;-)

Actually, after you got all this to work, you could even delete the xsd file. However, ... of course editing the rdlc by hand is not really comfortable, so it might be better to leave it.

Best regards,
Chris.

Koushik Das said...

Yes Christian, you are right. I have wrote this in my another blog.
It is definitely possible but it has some limitation like you have to have the dataset(xsd) fieldname same as your NHibernate object's property name.

-- Koushik

Anonymous said...

Quite true. ;)

Btw. do you have any experiences in working with stored procedures with NHibernate?

Cheers,
Chris

Koushik Das said...

No exactly... but why do you need stored procs while using NHibernate itself?

-- Koushik

Anonymous said...

Because I am replacing the data access layer of a legacy application. We extract quite complex information from the database of another application by using stored procedures. Unfortunately this cannot be changed to to technical and political reasons. So I need to either get access to those sp's through NHibernate or code side by side.

Anonymous said...

Hi Koushik and Chris

I have a complex NHibernate business obecjt that returns an IList of Employees. The Employee class has a List of Rules. Each employee has a list of rules associated with him. How do I go about doing this. Tried creating a dataset, but the report still does not show one-many relationship. Any help is greatly apprecitaed. Thanks.