Mapping From IDataReader/IDataRecord with AutoMapper

A while ago, I submitted a patch to AutoMapper that added basic support for mapping data from an IDataReader/IDataRecord to an object. For those of us who don’t have the luxury to use NHibernate in their projects, this feature can save you from writing lots of repetitive and tedious code.

Its usage is pretty much the same as with regular object-to-object mapping using AutoMapper. Lets show a very simple example.

Suppose we have a view object like the one shown below:

public class SomeView
{
    public Int32 SomeNumber { get; private set; }
    public Guid AnId { get; private set; }
    public Double OrNothing { get; private set; }
}

Now when we can execute a query like this,

SELECT ColumnA AS SomeNumber,
       ColumnB AS AnId,
       ColumnC AS OrNothing
FROM SomeTable
WHERE ...

and read the results using a data reader. Now we can use AutoMapper to map the results to instances of our view class:

var dataReader = ... // Execute a data reader
var views = Mapper.Map<IDataReader, IEnumerable<SomeView>>(_dataReader);

This results in a collection of one of or more view objects. When our query is guaranteed to always return one record, we can use the following syntax:

var dataRecord = ... // Execute data reader and read first record
var = Mapper.Map<IDataRecord, SomeView>(_dataRecord);

This approach expects that a convention is followed whereby the name of a field returned by the query matches the name of a property on the target class. Its also possible to use projection as already provided for regular object-to-object mapping.

Suppose we add a new property to our view,

public class SomeView
{
    ...
    public DateTime SomeDate { get; private set; }
}

and we modify the query so that we retrieve the corresponding date value from the database:

SELECT ...
       ColumnD AS BirthDay
FROM SomeTable

Notice that we’ve broken the convention here and we need to use projection to ensure that the retrieved date value is mapped to the correct property.

Mapper.CreateMap<IDataRecord, SomeView>()
    .ForMember(dest => dest.SomeDateAndTime, 
               options => options.MapFrom(
               src => src.GetDateTime(src.GetOrdinal("BirthDay"))));

var dataRecord = ...    // Execute data reader and read first record
var = Mapper.Map<IDataRecord, SomeView>(_dataRecord);

Using projection we’re able to manually map from a data reader or data record. In some sense,  we’re back to square one if we have to do this for all fields. Trying to follow the convention is of course the most useful. 

I know it’s not much, but I think it can be helpful for those cases where you actually need to map from a data reader or a data record to an object.

9 thoughts on “Mapping From IDataReader/IDataRecord with AutoMapper

  1. Allright, great contribution. This will save me a bunch of mapping classes. It’s small things like these that make your life so much better if you can’t use NHibernate.

  2. Excellent Addition. I have a question, perhaps this a wrong place to ask but let me try anyway : Can it be tweaked to run under Compact Framework 3.5 ?

  3. Please, any helper for Ent.Library Data Block 4.1, for reduce code lines and write elegant code ?? any suggestions ??

    Database db = DatabaseFactory.CreateDatabase(“ConnectionStrings.Oracle.D04PES01”);
    using (DbCommand cm = db.GetStoredProcCommand(“TBL_POC_TEST_TIPOS.TBL_POC_TEST_TIPOS_FBY_PK”))
    {
    db.AddInParameter(cm, “P_ID_TEST_TIPOS”, DbType.String, id);
    cm.Parameters.Add(CreateCursorParameter(“P_REFCURSOR”));

    // Using “using” will cause both the DataReader and connection to be
    // closed. (ExecuteReader will close the connection when the
    // DataReader is closed.)
    using (IDataReader dataReader = db.ExecuteReader(cm))
    {
    if (dataReader.Read())
    {
    factory.Add(dataReader);
    }
    //while (dataReader.Read())
    //{
    // factory.Add(dataReader);
    // break;
    //}
    return factory.Entity;
    }
    }
    thanks in advance…

  4. Many years I use a great bltoolkit library for mapping and dataaccess:

    public class SomeView
    {
    public Int32 SomeNumber { get; private set; }
    public Guid AnId { get; private set; }
    public Double OrNothing { get; private set; }
    }

    // for getting list entities
    using(var db = new DbManager())
    var list = db.SetCommand(SqlQueryHere).ExecuteList();

  5. Could you do it with List instead of IEnumerable like so?

    var views = Mapper.Map<IDataReader, List>(_dataReader);

  6. When I map IDataReader to IEnumerable, it fails with null reference exception in DataReaderMapper.cs at line 106 inside the following methid:

    private static void MapPropertyValues(ResolutionContext context, IMappingEngineRunner mapper, object result)
    {
    // this is where it is failing… right at the first line
    foreach (var propertyMap in context.TypeMap.GetPropertyMaps())
    {
    MapPropertyValue(context, mapper, result, propertyMap);
    }
    }

Comments are closed.

Proudly powered by WordPress | Theme: Code Blog by Crimson Themes.