Hello all!
I have a method which in essence converts a datatable to a list of objects which I call 'Bags'. This code is called many times per session, with many sessions concurrently running and with sometimes thousands of rows. Because of this I need it to be as quick as possible. I have an xml file which contains the DataColumn to Property mappings. The main method to optimize is ConvertRowToBag
- the type parameter passed in is a type which derives from BagBase
.
It's a long bit of code, but any tips would be much appreciated.
public class BagBase
{
/// <summary>
/// Dictionary of properties and names
/// </summary>
private static Dictionary<string, PropertyInfo> propertyDictionary = new Dictionary<string, PropertyInfo>();
/// <summary>
/// Table of column/property mappings
/// </summary>
private static DataTable mappings = new DataTable("Mappings");
/// <summary>
/// Returns true if the map exists
/// </summary>
/// <param name="columnName"></param>
/// <param name="type"></param>
/// <returns></returns>
private static bool MappingExists(string columnName, Type type)
{
DataRow [] rows = BagBase.mappings.Select(String.Format("Type = '{0}' and ColumnName = '{1}'", type.Name, columnName));
return (rows != null && rows.Length > 0);
}
/// <summary>
/// Converts the table to bags.
/// </summary>
/// <param name="table">The table.</param>
/// <param name="outputType">Type of the output.</param>
/// <returns></returns>
protected static List<BagBase> ConvertTableToBags(DataTable table, Type outputType)
{
Trace.TraceInformation(String.Format("ConvertTableToBags : table={0} Type={1}", table.TableName, outputType.Name));
// Create an empty list
List<BagBase> result = new List<BagBase>();
// Iterate through the rows
foreach (DataRow row in table.Rows)
{
// Add to the list
result.Add(ConvertRowToBag(outputType, row));
}
Trace.TraceInformation("ConvertTableToBags Finished.");
return result;
}
/// <summary>
/// Converts the row to bag.
/// </summary>
/// <param name="outputType">Type of the output.</param>
/// <param name="row">The row.</param>
/// <returns></returns>
protected static BagBase ConvertRowToBag(Type outputType, DataRow row)
{
// Create an instance of the child class and store in the base
BagBase bag = Activator.CreateInstance(outputType) as BagBase;
// Iterate through the columns
foreach (DataColumn column in row.Table.Columns)
{
// If this column has been mapped
if (BagBase.MappingExists(column.ColumnName, outputType))
{
PropertyInfo property;
string columnProperty = String.Format("{0}={1}", column.ColumnName, outputType.Name);
// Get the property as defined in the map
if (!propertyDictionary.ContainsKey(columnProperty))
{
// Get the property
property = outputType.GetProperty(BagBase.GetColumnMapping(column.ColumnName, outputType));
// Add the property to the dictionary
propertyDictionary.Add(columnProperty, property);
}
else
{
property = propertyDictionary[columnProperty];
}
if (property != null)
{
if (!row.IsNull(column))
{
// Set the value to the in the table
if (property.PropertyType.BaseType != null && property.PropertyType.BaseType == typeof(Enum))
{
if (column.DataType != typeof(String))
{
property.SetValue(bag, Enum.ToObject(property.PropertyType, row[column]), null);
}
else
{
property.SetValue(bag, Enum.ToObject(property.PropertyType, Convert.ToChar(row[column])), null);
}
}
else if (property.PropertyType == typeof(DateTime?))
{
property.SetValue(bag, (DateTime?)row[column], null);
}
else
{
property.SetValue(bag, Convert.ChangeType(row[column], property.PropertyType), null);
}
}
else // No nulls
{
if (column.DataType == typeof(String))
{
property.SetValue(bag, String.Empty, null);
}
}
// Generate the unique class.property name
string propertyKey = String.Format("{0}.{1}", outputType.Name, property.Name);
if (!columnCaptions.ContainsKey(propertyKey))
{
// Add to the caption map
columnCaptions.Add(propertyKey, column.Caption);
}
}
}
else
{
// If this column isn't mapped, add it to Other information
if (bag.OtherInformation == null)
{
bag.OtherInformation = new Dictionary<string, string>();
}
bag.OtherInformation.Add(column.ColumnName, !row.IsNull(column) ? row[column].ToString() : String.Empty);
}
}
return bag;
}
}