Introduction
Here is a simple and clean way to convert result set of DataReader
into List of Data Model Objects of your application.
The logic presented below converts IDataReader Result
into IEnumerable<T>
with the help of Property Attribute and Reflection.
Background
There are so many Pattern Based Development Models and Frameworks for Application Development. However, there remains need of some simple, clean yet powerful code to address tiny challenges of small applications, where those giants are not an ideal fit.
So in this case, I have created a class DbHelper
, attribute DataField
and routine extractDataObjects
that can be used along with a Generic Class Type to get enumerable collection of data objects.
Using the Code
There is an Property Attribute DataField
that allows you to associate Source
and Target
element name along with respective data type. There is also a class DbHelper
that exposes routine to perform the task.
[System.AttributeUsage( AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false )]
public class DataField: Attribute {
public string dbField { get; set; }
public string sourceType { get; set; }
public string sourceDataFormatter { get; set; }
public string targetDataFormatter { get; set; }
}
public static class DbHelper {
public static IEnumerable<T> extractDataObjects<T>( IDataReader dataSource )
where T: class, new() {
LinkedList<T> dataList = new LinkedList<T>();
PropertyInfo[] properties = typeof( T ).GetProperties();
T item = null;
Type tAttrib = typeof( DataField );
using ( dataSource ) {
while ( dataSource.Read() ) {
item = new T();
foreach ( PropertyInfo property in properties ) {
var attribute = Attribute.GetCustomAttribute( property, tAttrib ) as DataField;
if ( attribute != null ) {
var value = castValue( dataSource[attribute.dbField
?? property.Name]
, attribute.sourceType
?? "System.String"
, property.PropertyType );
property.SetValue( item, value, null ); }
}
dataList.AddLast( item );
}
dataSource.Close();
dataSource.Dispose();
}
return dataList;
}
private static object castValue( object value, string sourceType, Type targetType ) {
switch ( sourceType ) {
case "System.DateTime":
switch ( targetType.Name ) {
case"TimeSpan":
var dtValue = (DateTime) value;
TimeSpan tsValue = dtValue.TimeOfDay;
value = tsValue;
break;
}
break;
}
return value;
}
}
using ( IDbConnection instConn = dacFactory.getConnection( connectionSource.MSAccess, AppSettings.ConnectionString ) ) {
using ( IDbCommand instCmd = dacFactory.getCommand( "SELECT * FROM PublisherLog"
, instConn ) ) {
dataList = dbHelper.extractDataObjects<publisherLogEntity>(
instCmd.ExecuteReader() );
instCmd.Cancel();
instCmd.Dispose();
}
instConn.Close();
instConn.Dispose();
}
public class publisherLogEntity {
[DataField( dbField="IdPublising", sourceType= "System.Int64")]
public long IdPublising { get; set; }
[DataField( dbField="message", sourceType="System.String" )]
}
Points of Interest
This is an easy application of reflection and generic to meet a common requirement to reduce several lines of code.