Search code examples
c#.netautomappervalueinjecter

Is it possible to map a IDataReader to a nested DTO using automapper?


I was hoping that I could map a flat datareader into a nested DTO. Running the following code the name is null. Am I doing something wrong or is this just not possible?

class Program
{
    public class Person
    {
        public int id { get; set; }
        public Name name { get; set; }
    } 

    public class Name
    {
        public string first_name { get; set; }
        public string last_name { get; set; }
    }

    static void Main(string[] args)
    {
        DataTable table = CreateSampleDataTable();
        Mapper.CreateMap<IDataReader, Person>();
        Mapper.CreateMap<IDataReader, Name>();

        var results = Mapper.Map<IDataReader, IList<Person>>(table.CreateDataReader());           
    }

    private static DataTable CreateSampleDataTable()
    {
        var table = new DataTable();

        table.Columns.Add("id", typeof(int));
        table.Columns.Add("first_name", typeof(string));
        table.Columns.Add("last_name", typeof(string));

        table.Rows.Add(100, "Jeff", "Barnes");
        table.Rows.Add(101, "George", "Costanza");
        table.Rows.Add(102, "Stewie", "Griffin");
        table.Rows.Add(103, "Stan", "Marsh");
        table.Rows.Add(104, "Eric", "Cartman");
        return table;
    }
}

Solution

  • possible with the ValueInjecter:

    public class DanRyan
    {
        [Test]
        public void Main()
        {
            var persons = new List<Person>();
            var table = CreateSampleDataTable();
            var reader = table.CreateDataReader();
    
            while (reader.Read())
            {
                var p = new Person();
    
                p.InjectFrom<ReaderInjection>(reader);
    
                p.name = new Name();
                p.name.InjectFrom<ReaderInjection>(reader);
    
                persons.Add(p);
            }
    
            persons.Count.IsEqualTo(5);
            persons[0].id.IsEqualTo(100);
            persons[0].name.first_name.IsEqualTo("Jeff");
            persons[0].name.last_name.IsEqualTo("Barnes");
        }
    
        public class Person
        {
            public int id { get; set; }
            public Name name { get; set; }
        }
    
        public class Name
        {
            public string first_name { get; set; }
            public string last_name { get; set; }
        }
    
        private static DataTable CreateSampleDataTable()
        {
            var table = new DataTable();
    
            table.Columns.Add("id", typeof(int));
            table.Columns.Add("first_name", typeof(string));
            table.Columns.Add("last_name", typeof(string));
    
            table.Rows.Add(100, "Jeff", "Barnes");
            table.Rows.Add(101, "George", "Costanza");
            table.Rows.Add(102, "Stewie", "Griffin");
            table.Rows.Add(103, "Stan", "Marsh");
            table.Rows.Add(104, "Eric", "Cartman");
            return table;
        }
    
        public class ReaderInjection : KnownSourceValueInjection<IDataReader>
        {
            protected override void Inject(IDataReader source, object target)
            {
                for (var i = 0; i < source.FieldCount; i++)
                {
                    var activeTarget = target.GetProps().GetByName(source.GetName(i), true);
                    if (activeTarget == null) continue;
    
                    var value = source.GetValue(i);
                    if (value == DBNull.Value) continue;
    
                    activeTarget.SetValue(target, value);
                }
            }
        }
    }