17 April 2009

Using Reflection to fill a Business Layer object

Getting tired of endlessly assigning properties for business objects, I decided to try to make life easier on myself. So I developed a handy class, which takes a DataRow and fills a Business Layer object with that data. So now every one of my business object constructors is as simple as this:




public MyItem(DataRow Row)
{
Converter.Fill(this, Row);
}


The class that does all the conversion is as follows:




using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;

namespace MyNamespace.Data
{
class Converter
{
public static void Fill(object LogicObject, DataRow Row)
{
Dictionary<string, PropertyInfo> props = new Dictionary<string,PropertyInfo>();
foreach (PropertyInfo p in LogicObject.GetType().GetProperties())
props.Add(p.Name, p);
foreach (DataColumn col in Row.Table.Columns)
{
string name = col.ColumnName;
if (Row[name] != DBNull.Value && props.ContainsKey(name))
{
object item = Row[name];
PropertyInfo p = props[name];
if (p.PropertyType != col.DataType)
item = Convert.ChangeType(item, p.PropertyType);
p.SetValue(LogicObject, item, null);
}
}

}
}
}


The full class for MyItem could look something like this:




using System;
using System.Data;

namespace MyNamespace.Data
{
public class MyItem
{
public int item_id { get; set; }
public string item_name { get; set; }
public DateTime item_expiry { get; set; }

public MyItem(DataRow Row)
{
Converter.Fill(this, Row);
}

public static MyItem Select(int item_id)
{
DataRow row;
// code to perform query and get row
...
return new MyItem(row);
}
}
}


In this implementation of Converter, your business object properties have to have the same names as the column names in the database. However, the Converter could be modified to also accept a Dictionary (or array of KeyValuePair) that provides a mapping from database column names to object property names.