How to elegantly map form flat object to complex list object using Automapper?

Viewed 53

I have a flat complex type which I need to map to a complex type within a list. I have achieved it using the below code but it is not elegant. The mapping for each individual item has to be specified explicitly even though the types and names match. I wanted to know if there is a more elegant way of doing this without such verbosity and tight coupling?

using AutoMapper;

MapperConfiguration _config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<FlatObject, MyDTO>()
    .ForMember(dst => dst.ListObject, opt => opt.MapFrom(src => new List<ListObject> {
        new ListObject {
            DTOCustObject = new DTOCustObject {
                MyString = src.CustType.MyString,
                MyInt = src.CustType.MyInt,
                MyBool = src.CustType.MyBool,
                //Others...
                DTOMyObject = new DTOMyObject {
                    SomeString = src.CustType.MyObject.SomeString
                    //Others...
                }
            }
        }
    }));
});

_config.AssertConfigurationIsValid();

var flatObject = new FlatObject();
flatObject.CustType.MyString = "ABC123";
flatObject.CustType.MyInt = 12345;
flatObject.CustType.MyBool = true;
flatObject.CustType.MyObject.SomeString = "Some String Content";

IMapper mapper = new Mapper(_config);
var myDTO = mapper.Map<MyDTO>(flatObject);

Console.ReadKey();

//###############
//Entity - Source
//###############
public class FlatObject
{
    public CustType CustType { get; set; } = new CustType();
}

public class CustType
{
    public string? MyString { get; set; }
    public int MyInt { get; set; }
    public bool MyBool { get; set; }
    public MyObject MyObject { get; set; } = new MyObject();
}

public class MyObject
{
    public string? SomeString { get; set; }
}

//#################
//DTO - Destination
//#################
public class MyDTO
{
    public List<ListObject> ListObject { get; set; } = new List<ListObject>();
}

public class ListObject
{
    public DTOCustObject DTOCustObject { get; set; } = new DTOCustObject();
}

public class DTOCustObject
{
    public string? MyString { get; set; }
    public int MyInt { get; set; }
    public bool MyBool { get; set; }
    public DTOMyObject DTOMyObject { get; set; } = new DTOMyObject();
}

public class DTOMyObject
{
    public string? SomeString { get; set; }
}
1 Answers
public class MyDTO
{
    public List<DTOCustObject> DTOCustObjectList{ get; set; } = new List<DTOCustObject>();
}

public class DTOCustObject
{
    public string? MyString { get; set; }
    public int MyInt { get; set; }
    public bool MyBool { get; set; }
    public DTOMyObject DTOMyObject { get; set; } = new DTOMyObject();

    public DTOCustObject(ICustObjectMapper mapper){
       MyString = mapper.GetMyString();
       MyInt = mapper.GetMyInt();
       MyBool = mapper.GetMyBool();
       DTOMyObject = mapper.GetDTOMyObject();
    }

}

public class DTOMyObject
{
    public string? SomeString { get; set; }

    public DTOMyObject(IDTOmyObjectMapper mapper)
    {
         SomeString = mapper.GetSomeString();
    }
}

Now simply implement the Interfaces and their GetMethods on the source object, in the corresponding classes. And presto. No need for any framework of any kind.

This means, no framework, will try change syntax, and force a rewrite. You aren't locked into keeping it updated, there won't be any dependencies on it, etc. You are free, and the time it takes you to configure, and annotate the code, is equal to the amount of time it takes you to just write the damn interfaces and implementations.

If your objects are autogenerated, simply use the partial keyword, and make the interface implementations in a partial class. Problem solved.

Something to this effect:

public class CustType : ICustObjectMapper 
{
    public string? MyString { get; set; }
    public int MyInt { get; set; }
    public bool MyBool { get; set; }
    public MyObject MyObject { get; set; } = new MyObject();

    string GetMyString(){
         return MyString;
    }

    // etc for the rest of the basic types.

   DTOMyObject GetMyObject(){
      return new DTOMyObject(MyObject)
   } 

}

public class MyObject : IDTOmyObjectMapper 
{
    public string? SomeString { get; set; }

    public string GetSomeString()
    {
         return SomeString;
    }
}

Of course, if you don't know how to declare an interface...

public interface ICustObjectMapper {
    string GetMyString();
    //etc.

}

Now please, for the love of everything on this planet. STOP USING MAPPING FRAMEWORKS IN C#, IT MAKES NO SENSE!

Related