user2829330
user2829330

Reputation: 113

Automapper - mapping simple list to complex nested type

I have a question regarding Automapper, I have an flat list of objects that i must return in transformed DTO object to frontend, let's say, List of

List<Cars> list =
Cars
{
    public string PartCode { get; set; }
    public bool Enabled { get; set; }
    public string CarCode { get; set; }
    public int CarId { get; set; }
    public int PartId { get; set; }
}

and i need to map it to object:

public class CarsDTO
{
    public int CarId;
    public string CarCode;
    public List<PartsDTO> CarParts;
}

public class PartDTO
{
    public Part Id;
    public string PartCode;
    public bool Enabled;
}

And example data:

part_id part_code   car_id  car_code    enabled
1   WINDOW  1   MUSTANG true
2   WHEELS  1   MUSTANG true
3   BUMPER  2   MONDEO  true
4   HOOD    2   MONDEO  false
5   WINDSHIELD  2   MONDEO  true
6   TIRE    3   KA  true
7   STEERING_WHEEL  4   FOCUS   false
8   TRANSMISSION    4   FOCUS   true

And proposed output after mapping in json:

"parts": [
        {
            "carId": 1,
            "carCode": "MUSTANG",
            "carParts": [
                {
                    "id": 1,
                    "partCode": "WINDOW",
                    "enabled": true
                },
                {
                    "id": 2,
                    "partCode": "WHEELS",
                    "enabled": true
                }
            ]
        },
        {
            "carId": 2,
            "carCode": "MONDEO",
            "carParts": [
                {
                    "id": 3,
                    "partCode": "BUMPER",
                    "enabled": true
                },
                {
                    "id": 4,
                    "partCode": "HOOD",
                    "enabled": false
                },
                {
                    "id": 5,
                    "partCode": "WINDSHIELD",
                    "enabled": true
                }
            ]
        },
        {
            "carId": 3,
            "carCode": "KA",
            "carParts": [
                {
                    "id": 6,
                    "partCode": "TIRE",
                    "enabled": true
                },
            ]
        },
        {
            "carId": 4,
            "carCode": "FOCUS",
            "carParts": [
                {
                    "id": 7,
                    "partCode": "STEERING_WHEEL",
                    "enabled": false
                },
                {
                    "id": 8,
                    "partCode": "TRANSMISSION",
                    "enabled": true
                ]
        }
        ]

Ive managed to map object in Linq with following query:

    List<CarParts> carParts = new List<CarParts>();

    List<CarPartsList> list = (from t in carParts
                                 group t by new { t.CarCode, t.CarId }
                                 into grp
                                 select new CarPartsList()
                                 {
                                     GroupCode = grp.Key.CarCode,
                                     GroupId = grp.Key.CarId,
                                     GroupRights = (from
                                                    carPart in carParts
                                                    where userRight.CarCode == grp.Key.CarCode
                                                    select new Part { Id = carPart.PartId, PartCode = carPart.Code, Enabled = carPart.Enabled }).ToList()
                                 }).ToList();

But the project im working on requires Automapper to transform DTO objects, and I dont know the solution:/ Ive read the docs at: https://docs.automapper.org/en/stable/Nested-mappings.html But the example in docs is so simple that i cant make use of it.

Upvotes: 1

Views: 1231

Answers (1)

devNull
devNull

Reputation: 4219

The best answer here would be to not use AutoMapper, since in this case it will just introduce unnecessary complexity instead of simplifying your code. The usage guidelines even state:

DO NOT use AutoMapper except in cases where the destination type is a flattened subset of properties of the source type


However...

If your project requires using AutoMapper here, one way would be to define a Custom Type Converter that essentially does the same LINQ projection that you would have done otherwise:

public class CarPartConverter : ITypeConverter<IEnumerable<Cars>, IEnumerable<CarsDTO>>
{
    public IEnumerable<CarsDTO> Convert(IEnumerable<Cars> source, IEnumerable<CarsDTO> destination, ResolutionContext context)
    {
        return source
            .GroupBy(c => new {c.CarCode, c.CarId})
            .Select(g => new CarsDTO
            {
                CarCode = g.Key.CarCode,
                CarId = g.Key.CarId,
                CarParts = g.Select(v => new PartsDTO
                {
                    Id = v.PartId,
                    PartCode = v.PartCode,
                    Enabled = v.Enabled
                }).ToList()
            });
    }
}

Here's a complete example using that converter:

static void Main(string[] args)
{
    IMapper mapper = new MapperConfiguration(cfg => {
        cfg.CreateMap<IEnumerable<Cars>, IEnumerable<CarsDTO>>().ConvertUsing<CarPartConverter>();
    }).CreateMapper();

    List<Cars> cars = new List<Cars>
    {
        new Cars {PartId = 1, PartCode = "WINDOW", CarId = 1, CarCode = "MUSTANG", Enabled = true},
        new Cars {PartId = 2, PartCode = "WHEELS", CarId = 1, CarCode = "MUSTANG", Enabled = true},
        new Cars {PartId = 3, PartCode = "BUMPER", CarId = 2, CarCode = "MONDEO", Enabled = true}
    };

    IEnumerable<CarsDTO> dtos = mapper.Map<IEnumerable<CarsDTO>>(cars);

    Console.WriteLine(JsonConvert.SerializeObject(dtos, Formatting.Indented));
    Console.ReadLine();
}

Which gives the following results:

enter image description here

Upvotes: 3

Related Questions