Introduction
This application helps in dynamically assigning values of the result retrieved from a database to the object (class type). In short, create a business object from each row of data dynamically. This will be helpful in creating business object collections in the business layer of a simple framework.
DynamicDataMapping class
- Maps the column name of the resultant retrieved from the database to the properties of the class.
- It sets the value to the object's properties from the resultant.
How to apply
- Add the
DynamicDataMapping class to your application.
- Create a business object with specific properties (for example: class
User).
- Execute your
Select query which is relevant to this object and get the resultant (normally, a resultant may be either a DataSet, DataTable, or DataReader (collection of rows)).
- Call the
Copy method of DynamicDataMapping and pass the resultant and the business object instance .
- This will return you the business items with the state (attribute) of the object being filled with the values from the resultant rows.
- Collect the item in a container.
Using the code
User class methods returning collection object
#region GetInstanceCollection (2 -Overloads)
private SortedList<int, User> GetInstanceCollection(DataTable dtResultTable)
{
try
{
SortedList<int, User> itemList =null;
if (dtResultTable != null)
{
itemList = new SortedList<int, User>(dtResultTable.Rows.Count);
foreach (DataRow dataRow in dtResultTable.Rows)
{
User objUser = new User();
DynamicDataMapping dmap = new DynamicDataMapping();
dmap.Copy(dataRow, objUser, false, null);
itemList.Add(objUser.UserID, objUser);
}
}
return (itemList);
}
catch { throw; }
}
public SortedList<int, User> GetUsers(DataTable ds)
{
try
{
if (ds != null && ds.Rows.Count > 0)
{
return GetInstanceCollection(ds);
}
return null;
}
catch (Exception ex)
{
throw ex;
}
}
DynamicDataMapping class
Mapping
The Map method of the DynamicDataMapping class maps the source DataRow's columns with the target object's (class) properties. If the column name matches the property name, it sets the values to the properties. You may retrieve N number of columns from the database, but it doesn't mean you should have all the properties in your designed class. In case you do not have the specific column name as a property in your designed class, then add the column names in the IgnoreList. Here, the source DataRow's column name and the value of the column are retrieved and sent to the Set property method.
#region Map (DataRow - Object of type Class)
private void Map(System.Data.DataRow objSource, Object objTarget,
bool blnSuppressExceptions, params string[] strIgnoreList)
{
List<string> ignore =null;
if(strIgnoreList !=null)
ignore = new List<string>(strIgnoreList);
for (int intcolcount = 0;
intcolcount <= objSource.ItemArray.Length - 1; intcolcount++)
{
string strPropertyName = objSource.Table.Columns[intcolcount].ColumnName;
if (ignore==null || (ignore != null && !ignore.Contains(strPropertyName)))
{
try
{
SetPropertyValue(objTarget, strPropertyName,
objSource[strPropertyName]);
}
catch (Exception ex)
{
if (!blnSuppressExceptions)
throw new Exception(string.Format("Error while " +
"assigning value to the property : {0}",
strPropertyName), ex);
}
}
}
}
#endregion
SetPropertyValue method
Actually, only the exact mapping and setting of values to the properties takes place here.
- Source
DataRow's column name, value of the column, and the target object are taken as input.
- Get the property with that column name in the class.
- Get the property's type (data type).
- Get the value type (value of that column).
- If the value is
null, then set the property's value as Dbnull.
- If the value is not
null, then compare the property's type with the value's type.
- If property's type matches the value's type, then copy the value to the property of the object.
- If it doesn't match, try to coerce and set to the property.
#region SetPropertyValue
public static void SetPropertyValue(object objTarget,
string strPropertyName, object objValue)
{
PropertyInfo propertyInfo =
objTarget.GetType().GetProperty(strPropertyName);
Type pType = GetPropertyType(propertyInfo.PropertyType);
Type vType = GetPropertyType(objValue.GetType());
if (objValue == null)
propertyInfo.SetValue(objTarget, DBNull.Value, null);
else if (objValue.Equals(System.DBNull.Value))
{
if (pType.Equals(typeof(System.DateTime)))
propertyInfo.SetValue(objTarget, DateTime.MinValue, null);
else if (pType.Equals(typeof(System.Double)))
propertyInfo.SetValue(objTarget, 0, null);
else if (pType.Equals(typeof(System.Int32)))
propertyInfo.SetValue(objTarget, 0, null);
else if (pType.Equals(typeof(System.Byte[])))
propertyInfo.SetValue(objTarget, new byte[0], null);
}
else
{
if (pType.Equals(vType))
{
propertyInfo.SetValue(objTarget, objValue, null);
}
else
{
if (pType.Equals(typeof(Guid)))
propertyInfo.SetValue(objTarget, new Guid(objValue.ToString()), null);
else if (pType.IsEnum && vType.Equals(typeof(string)))
propertyInfo.SetValue(objTarget,
Enum.Parse(pType, objValue.ToString()), null);
else
propertyInfo.SetValue(objTarget,
Convert.ChangeType(objValue, pType), null);
}
}
}
Conclusion
This will help in making your business layer more generic.
Note: The property name of the class should match either the column name or the alias name in the SQL Select statement.