Introduction
This approach helps us not to customize our Data Access Layer for different types of data classes. Consider we have some "Data class" in our application, and we want the data class to act as a collection. Generally, what we do is declare a "Generic List" (New feature in 2.0) of that data class type and populate our data list from the database. For populating the list, we loop through the data class with customized code and add the class to our list collection. This will be tedious and time-consuming if we have hundreds of classes where we need to rewrite the same code again and again.
To avoid that, I have conceived a new approach where we can pass the object of the class as a parameter, and as an output, we get a Generic Data List. Then we can typecast the Generic list back to our custom List collection. This is accomplished using reflection.
In the below example, I will explain how to do it, considering we have a data class called Person.
Data Class Person Data Object
public class Person
{
// Required to create multiple instance through reflection
public object Clone()
{
Person person = new Person();
return (object)person;
}
private string _Name;
public string Name
{
set{_Name=value;}
get { return _Name; }
}
private string _Address;
public string Address
{
set { _Address = value; }
get { return _Address; }
}
private string _City;
public string City
{
set { _City = value; }
get { return _City; }
}
private string _State;
public string State
{
set { _State = value; }
get { return _State; }
}
private string _Country;
public string Country
{
set { _Country = value; }
get { return _State; }
}
In UI, create the instance of the Data object and pass it to the method "ExecuteGenericList". ExecuteGenericList method process the passed object and creates a collection of the object depending on the number of rows we get from our select query. A little bit of type casting has to be done to the returned Generic List to convert it to our typed data list Person.
// Create an instance of the data object
Person person = new Person();
DAL dal = new DAL();
// dal.ExecuteGenericList(person) returns a Generic data list of the type person
// Cast the generic list to List<Person> using LINQ's Cast and ToList methods
List<Person> lstPerson = dal.ExecuteGenericList(person).Cast<Person>().ToList();
// Assuming lstPerson is already populated
GridView1.DataSource = lstPerson;
GridView1.DataBind();
Our DAL class "ExecuteGenericList" uses reflection to iterate through all the properties of the class and creates a generic list collection for each and every row.
DAL, Where our object is read and returned as a List.
/// <summary>
/// ExecuteGenericList is used to fill all properties of any passed data object
/// Author :Sridhar Subramanian
/// </summary>
/// <param name="objectClass">Object which type has to be filled and returned as Generic List</param>
/// <param name="parameter1">SQL query parameter,you can use SP </param>
/// <returns>Generic List of the passed type </returns>
public List<Object> ExecuteGenericList(object objectClass)
{
List<Object> lstGenric = null;
try
{
sqlConnection = new SqlConnection(@"Server=SridharDev;Database=EntLibTest;Uid=Test;Pwd=Test;");
sqlConnection.Open();
sqlCommand = new SqlCommand("SELECT * FROM PERSON", sqlConnection);
sqlDataReader = sqlCommand.ExecuteReader();
lstGenric = new List<Object>();
Type theType = objectClass.GetType();
PropertyInfo[] p = theType.GetProperties();
MethodInfo m = theType.GetMethod("Clone");
ConstructorInfo ci = theType.GetConstructor(Type.EmptyTypes);
object cunInv = ci.Invoke(null);
object newObject = null;
object[] custAttr = null;
while (sqlDataReader.Read())
{
newObject = m.Invoke(cunInv, null);
foreach (PropertyInfo pi in p)
{
try
{
custAttr = pi.GetCustomAttributes(true);
if ((sqlDataReader[pi.Name] != System.DBNull.Value) && (custAttr.Length ==
pi.SetValue(newObject, sqlDataReader[pi.Name], null);
}
catch (System.IndexOutOfRangeException) { }
}
lstGenric.Add(newObject);
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
if (sqlDataReader.IsClosed == false)
sqlDataReader.Close();
if (sqlConnection.State == ConnectionState.Open)
sqlConnection.Close();
sqlConnection.Dispose();
}
return lstGenric;
}
Download Source code to see the worked out example.