I have written a generic method that generates a collection of generic types from a Datatable. I have looked for different implementations, but most of them were performing very poorly performance wise when dealing with lots of properties and a lot of records. This one is performing quite well so far.
I tried to improve the method by adding a custom attribute ( DataField ) on top of the properties, this way I could just include it on the properties and I can skip matching it up with the columns, or specify a custom name for the property that will match the datatable's column name.
I looked at the code and it looks like a huge mess now I'm really not proud of it and I want to have a nicer implementation. Can anyone give me some tips? Would appreciate it a lot.
Tried to include comments not sure how much it helped. Thank you, here is the code:
private static void SetItemFromRow<T>(T item, DataRow row) where T : new()
{
// Get all properties with attributes.
PropertyInfo[] propWithAttributes = item.GetType().GetProperties().Where(x => Attribute.IsDefined
(x, typeof(DataField))).ToArray();
foreach (DataColumn col in row.Table.Columns)
{
// Find property that matches the column name.
PropertyInfo p = item.GetType().GetProperty(col.ColumnName);
bool ignoreProperty = false;
if (p != null)
{
// If no attribute exists set the property value. Break out from the loop to go to the next column (Property).
if (!propWithAttributes.Contains(p))
{
if (row[col] != DBNull.Value)
{
p.SetValue(item, row[col], null);
continue;
}
}
// If the property has a custom attribute then check if its ignore property is true. If so we break out from the loop and go to the next column (Property).
var attrs = p.GetCustomAttributes(typeof(DataField), false).ToArray() as DataField[]; ;
if (attrs != null)
foreach (var attr in attrs)
{
if (attr.Ignore)
ignoreProperty = true;
}
if (ignoreProperty) continue;
}
SetPropertyWithCustomName(item, propWithAttributes, row, col);
}
}
Now we have all properties set on the object that had a matching column name, also we skipped all the properties that we wanted to ignore. Final step is to set the properties that have a DataField attribute with the Name defined.
private static void SetPropertyWithCustomName<T>(T item, PropertyInfo[] propWithAttributes, DataRow row, DataColumn col)
where T : new()
{
foreach (var prop in propWithAttributes)
{
// Get the attributes for the property.
var attrs = prop.GetCustomAttributes(typeof(DataField), false).ToArray() as DataField[];
bool match = false;
if (attrs != null)
{
foreach (var attr in attrs)
{
// Check if the column name matches the custom name on the property.
if (col.ColumnName == attr.Name)
{
var p = item.GetType().GetProperty(prop.Name);
if (row[col] != DBNull.Value)
{
p.SetValue(item, row[col], null);
match = true;
break;
}
}
}
if (match) break;
}
}
}
Aucun commentaire:
Enregistrer un commentaire