Search code examples
c#asp.netmodelautomapperdto

How to use AutoMapper and DTO's with two connected tables in ASP.NET 6?


I have this code below(2 connected models one to one)

public partial class Dish
    {
        public int Id { get; set; }
        public string DishName { get; set; }
        public decimal Price { get; set; }

        [Newtonsoft.Json.JsonIgnore]
        [System.Text.Json.Serialization.JsonIgnore]
        public DishDescription DishDescription { get; set; }

        [Newtonsoft.Json.JsonIgnore]
        [System.Text.Json.Serialization.JsonIgnore]
        public ICollection<OrderDish> Orders { get; set; }
        [Newtonsoft.Json.JsonIgnore]
        [System.Text.Json.Serialization.JsonIgnore]
        public ICollection<DishCategory> Categories { get; set; }
    }

and

    public partial class DishDescription
    {
        public int Id { get; set; }
        public int Calories { get; set; }
        public int Protein { get; set; }
        public int Fats { get; set; }
        public int Carbohydrates { get; set; }
        public int DishId { get; set; }

        public Dish Dish { get; set; }
    }

DTO:

public class GetAllDishesDto
    {
        public string DishName { get; set; }
        public decimal Price { get; set; }

        public DishDescription DishDescription { get; set; }
    }

and

public class DishDescriptionDto
    {
        public int Calories { get; set; }
        public int Protein { get; set; }
        public int Fats { get; set; }
        public int Carbohydrates { get; set; }
    }

AutoMapper:

    public class AutoMapperProfile : Profile
    {
        public AutoMapperProfile()
        {
            CreateMap<Dish, GetAllDishesDto>();
            CreateMap<DishDescription, DishDescriptionDto>();
        }
    }

Service:

public async Task<ICollection<GetAllDishesDto>> GetAllDishes()
        { 
            return await _dishDeliveryContext.Dishes
                .Include(d => d.DishDescription)
                .Select(d => _mapper.Map<GetAllDishesDto>(d))
                .ToListAsync();
        }

at the result i have responce below

enter image description here

BUT I NEED THIS ONE

enter image description here

help please

i tried to do this

 public async Task<ICollection<GetAllDishesDto>> GetAllDishes()
        { 
            return await _dishDeliveryContext.Dishes
                .Include(d => _mapper.Map<DishDescriptionDto>(d))
                .Select(d => _mapper.Map<GetAllDishesDto>(d))
                .ToListAsync();
        }

but it was a bad idea... i want to learn more about automapper and dto's, but now i cant understand how it works, maybe i should not using method Map() with second DTO, i think i houl use another one instead of it...


Solution

  • The key point is that you mismatched the nested model name for your Dto. It should contain DishDescriptionDto rather than DishDescription in your another Dto model.

    public class GetAllDishesDto
    {
        public string DishName { get; set; }
        public decimal Price { get; set; }
    
        public DishDescriptionDto DishDescription { get; set; }
    }
    

    Another point is that it's nice to use .ProjectTo() before ToListAsync() so Automapper helps EntityFramework to reduce the sql query and exclude unused fields. The query should look like this

    public async Task<ICollection<GetAllDishesDto>> GetAllDishes()
    { 
        return await _dishDeliveryContext.Dishes
            .ProjectTo<GetAllDishesDto>(configuration)
            .ToListAsync();
    }