Go to DotNetFunda.com
 Online : 1562 |  Welcome, Guest!   Login
 
Home > Articles > C# > Passing data between layers using Generic list collection

  • Download the OOPS, ASP.NET and ADO.NET Training Videos for FREE, click here.

Submit Article | Articles Home | Search Articles |

Passing data between layers using Generic list collection

 Posted on: 7/19/2009 7:28:40 AM by SheoNarayan | Views: 14543 | Category: C# | Level: Beginner | Print Article
This simple article describes how to pass data between different layers of your application using Generic list collections.

.NET Training Videos!
Buy online comprehensive training video pack just for $35.00 only, see what's inside it.

Update:

After going through this article, please read my response below. It's better to use Collection<T> than List<T>.

Introduction

This article is for beginners who want to know how to use .NET generics to pass data between different layers. If you do not know about generic list, please go thorugh this article http://www.dotnetfunda.com/articles/article152.aspx. In brief, List class is a generic equivalent of ArrayList class.

If you want to learn about how to develop 3-tier architecture application, please go through http://www.dotnetfunda.com/articles/article18.aspx and how to develop 4-tier architecture, please go through http://www.dotnetfunda.com/articles/article18.aspx. To show the use of generics, I have used downloadable source code available for 4-Tier architecure article.

There were discussion earlier and probably now also on whether we should use DataTable or generic List collection class to pass data between layers, you can read through http://weblogs.asp.net/bsimser/archive/2007/04/04/datatable-vs-bindinglist-t.aspx post to learn more about that but now I feel its evident that using Generic list to pass data between layers is the way to go. I personally prefer Genericl List over DataTable as I have seen its beneifts working in different projects.

There are different views on where the actual conversion of data from DataTable or DataReader to list should happen, some suggest to have a separate translation layer that accepts DataTable or DataReader and converts them into the list of desired objects. Normally people do it into Data Access Layer itself and pass the generic list objects to Presentation Layer through Business Layer. In this demonstration, I shall do the same.

Ideally, if you have preferred to use generic list to pass data between differenet layers you should prefer using entity layer (or I have called BO - Business Objects layer as described in the 4-Tier architecture application article referenced above). In this example, I have a Person business object / entity object that have properties related to a person, I am trying to fill into generic list.

Below code is the Data Access Layer code that gets data from database and convert them into generic list collection. Please note that I have used latest version of C# (3.0) that supports var keyword and other features I have used in below code snippets.

/// <summary>

/// Load records from the database using DataReader

/// </summary>

/// <returns></returns>

public List<Person> LoadThroughDataReader()

{

var list = new List<Person>();

using (SqlConnection conn = new SqlConnection(connStr))

{

using (SqlCommand cmd = new SqlCommand("LoadAll", conn))

{

cmd.CommandType = CommandType.StoredProcedure;

conn.Open();

using (SqlDataReader reader = cmd.ExecuteReader())

{

while (reader.Read())

{

Person p = new Person()

{

Age = reader.GetInt32(reader.GetOrdinal("Age")),

FirstName = reader.GetString(reader.GetOrdinal("FirstName")),

LastName = reader.GetString(reader.GetOrdinal("LastName"))

};

list.Add(p);

}

}

conn.Close();

}

return list;

}

}

 

/// <summary>

/// load returns from database using DataTable

/// </summary>

/// <returns></returns>

public List<Person> LoadThroughDataTable()

{

var list = new List<Person>();

using (SqlConnection conn = new SqlConnection(connStr))

{

using (SqlCommand cmd = new SqlCommand("LoadAll", conn))

{

cmd.CommandType = CommandType.StoredProcedure;

using (SqlDataAdapter ad = new SqlDataAdapter(cmd))

{

DataTable table = new DataTable();

conn.Open(); // open the connection

ad.Fill(table);

conn.Close(); // close the connection

// loop through all rows

foreach (DataRow row in table.Rows)

{

Person p = new Person()

{

Age = int.Parse(row["Age"].ToString()),

FirstName = row["FirstName"].ToString(),

LastName = row["LastName"].ToString()

};

list.Add(p);

}

}

}

return list;

}

}

In the above code snipeet, I have two method called LoadDataThroughDataReader and LoadDataThroughDataTable. In both method, I have declared a variable for List<Person> that is filled with the Person records returned from the database. The first method LoadDataThroughDataReader use cmd.ExecuteReader() method to get the SqlDataReader and read through all the records in the reader and add the Person object into the List. The second method is slightly different and use DataTable instead of DataReader to fetch data from database, loop through all the rows of the DataTable and add Person objects into the list.

You may wonder why these two methods when both are doing the same thing. I prefer using DataReader when I have lesser amount of data from the database and loop through because DataReader expect live connection when it loops through all the records. For large amount of data, it may be a bottleneck for the database to keep the connection alive and loop through. So for large amount of data I prefer to fill the DataTable, close the database connection and then loop through all the records do the required operation.

Once you have your Data Access Layer method ready to return the generic list collection, you can call it through your business layer (My business layer class name is PersonBAL) as follows:

/// <summary>

/// load records through data reader

/// </summary>

/// <returns></returns>

public List<Person> LoadThroughDataReader()

{

return new PersonDAL().LoadThroughDataReader();

}

 

/// <summary>

/// load records through datatable

/// </summary>

/// <returns></returns>

public List<Person> LoadThroughDataTable()

{

return new PersonDAL().LoadThroughDataTable();

}

As I do not have any logic in the Business Layer, so I have simply instantiated the PersonDAL data access layer object and called the respective methods.

Subsequently, this business layer methods can be called from presentation layer as follows:

GridView g1 = new GridView();

g1.DataSource = new PersonBAL().LoadThroughDataReader();

g1.DataBind();

PlaceHolder1.Controls.Add(g1);

 

GridView g2 = new GridView();

g2.DataSource = new PersonBAL().LoadThroughDataTable();

g2.DataBind();

 

// I have a place holder control in the .aspx page in which both above gridview is added

PlaceHolder1.Controls.Add(g2);

As GridView DataSource supports generic list also as data source so we can directly assign the business layer method as the GridView datasource and all the records from the generic list collection will be populated as rows into the GridView. All the properties of the Person object will be treated as the column of the GridView unless you have explictely assigned the columns in the GridView.

Hope you find this article interesting, please subscribe for the subsequent article alert directly in your email box. Happy coding!


 


If you like this article, subscribe to our RSS Feed. You can also subscribe via email to our Interview Questions, Codes and Forums section.

Interesting?   Share and Bookmark this kick it on DotNetKicks.com


About Sheo Narayan

Experience:8 year(s)
Home page:http://www.snarayan.com
Member since:Tuesday, July 08, 2008
Level:HonoraryPlatinum
Status: [Administrator]
Biography:Throughout 1st in all educational exams.
Major qualifications: HDCS, ADCA, MCA, MCTS
Developing and architecting applications in Microsoft technologies since year 2001.
Location: Hyderabad, India
 Latest post(s) from SheoNarayan

   ◘ Common operation with Files and Folders in ASP.NET posted on 9/4/2009 4:23:03 PM
   ◘ Working with CustomValidator control in ASP.NET posted on 8/19/2009 9:27:43 AM
   ◘ Backup and Restore database in ASP.NET posted on 8/7/2009 5:30:24 PM
   ◘ Passing data between layers using Generic list collection posted on 7/19/2009 7:28:40 AM
   ◘ jQuery and ASP.NET AJAX UpdatePanel posted on 7/17/2009 6:53:04 PM


 Responses
Posted by: Eti | Posted on: 21 Aug 2009 12:32:26 AM

Hi,

It's generally considered bad practice to return List<T> instances from methods in your public API.

See this:

http://msdn.microsoft.com/en-us/library/ms182142.aspx

and

http://blogs.msdn.com/kcwalina/archive/2005/09/26/474010.aspx

Posted by: SheoNarayan | Posted on: 21 Aug 2009 12:54:35 AM

@Eti:
Thanks for noticing this Eti and providing useful link.

For readers:


As per below suggestions and with the reference of http://msdn.microsoft.com/en-us/library/ms182142.aspx article, we can use System.Collections.ObjectModel.Collection(T) instead of System.Collections.Generic.List(T).

All the code will look same, instead of return type as List<Person>, please use Collection<Person> and everything will be alright.

So modified Data Access Layer function definition will look like

public Collection<Person> LoadThroughDataReader()

{
var list = new Collection<Person>();
...
...
}


Business Layer function will look like
public Collection<Person> LoadThroughDataReader()


No change is required in presentation layer.

Thanks again Eti!

--
Warm regards,
Sheo Narayan

Posted by: StevenSw | Posted on: 21 Aug 2009 04:17:49 PM

I believe the following will perform a bit faster rather the use of a DataAdapter to populate the DataTabe.. This is untested..

public List<Person> LoadThroughDataTable()

{
var list = new List<Person>();

using (SqlConnection conn = new SqlConnection(connStr))
{
using (SqlCommand cmd = new SqlCommand("LoadAll", conn))
{
cmd.CommandType = CommandType.StoredProcedure;

SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
DataTable dt = new DataTable();
dt.Load(dr);

// loop through all rows
foreach (DataRow row in table.Rows)
{
Person p = new Person()
{
Age = int.Parse(row["Age"].ToString()),
FirstName = row["FirstName"].ToString(),
LastName = row["LastName"].ToString()
};
list.Add(p);
}
}
return list;
}
}

Posted by: SheoNarayan | Posted on: 21 Aug 2009 08:10:48 PM

Thanks Steven,

Yes, I also feel that filling DataTable through reader is faster than DataAdapter. In this sample, I had used DataAdapter just for the sake of demo application. Thanks for modifying the code snippet to use DataReader however, I feel that it can be modified further to ensure that DataReader is closed immediately after loading the rows into DataTable. I have modified the code snippet properly to use DataReader to fill the DataTable and here it goes.

public List<Person> LoadThroughDataTable()

{
var list = new List<Person>();
using (SqlConnection conn = new SqlConnection(connStr))
{
using (SqlCommand cmd = new SqlCommand("LoadAll", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
DataTable table = new DataTable();
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
{
table.Load(reader);
}

// loop through all rows
foreach (DataRow row in table.Rows)
{
Person p = new Person()
{
Age = int.Parse(row["Age"].ToString()),
FirstName = row["FirstName"].ToString(),
LastName = row["LastName"].ToString()
};
list.Add(p);
}
}
return list;
}
}


Thanks again for your feedback.
Regards,
Sheo Narayan

Posted by: Ashoks104 | Posted on: 14 Sep 2009 01:34:00 AM

Is there any advantage of loading the DataReader to DataTable and then accessing its columns. Would it be better to read data directly from DataReader and set values to my business objects?

Posted by: SheoNarayan | Posted on: 14 Sep 2009 02:35:55 AM

Hi Ashoks104,

Thanks for your query.

I have already a method called LoadThroughDataReader that is doing that.

Sometimes its not good to read loads of data into reader and loop through as Reader works in connected architecture and till the time you loop through all records and close the reader, you will have to keep the database connection of the reader open. Also reader is forward only so you can't play with it going forward, backword and getting data of a particular column of a particular row.

Thanks

Submit Article

About Us | The Team | Advertise | Contact Us | Feedback | Privacy Policy | Terms of Use | Link Exchange | Members | Go Top
General Notice: If you found copied contents on this page, please let us know the original source along with your correct email id (to communicate) for further action.
All rights reserved to DotNetFunda.Com. Logos, company names used here if any are only for reference purposes and they may be respective owner's right or trademarks.
(Best viewed in IE 6.0+ or Firefox 2.0+ at 1024 * 768 or higher)