I am using AutoMapper to map between different entities in ASP.NET Core Web API. However, it's not showing results, but if I do the mapping manually, it works - I want to know why that is.
I have entities Order
and OrderProduct
as a middle table to join the many-to-many relationship between Order
and Product
.
I have created a DTO for (Order, OrderProduct, Product
) and do the mapping profile for them.
public class Order
{
public Order()
{
OrderDate = DateTime.Now;
}
public int Id { get; set; }
public DateTime OrderDate { get; set; }
public AppUser AppUser { get; set; }
public ICollection<OrderProduct> OrderProducts { get; set; } = new HashSet<OrderProduct>()
}
public class OrderProduct
{
public int Id { get; set; }
public int OrderId { get; set; }
public Order Order { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
}
public class Product
{
public int Id { get; set; }
[Required, MaxLength(150)]
public string PName { get; set; }
[Required, MaxLength(250)]
public string PDescription { get; set; }
public decimal Price { get; set; }
}
And this is the DTO:
public class OrderDTO
{
public int OrderId { get; set; }
public DateTime OrderDate { get; set; }
public string ProductName { get; set; }
public List<OrderProductDTO> OrderProductDTO { get; set; } = new List<OrderProductDTO>();
}
public class OrderProductDTO
{
public int OrderId { get; set; }
public ProductDTO Products { get; set; }
public int ProductId { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
}
public class ProductDTO
{
public int productID { get; set; }
public string productName { get; set; }
public decimal productPrice { get; set; }
public int productRating { get; set; }
public string productImageURL { get; set; }
}
// MAPPING Profile
CreateMap<Order, OrderDTO>()
.ForMember(dest => dest.OrderId, opt => opt.MapFrom(src => src.Id))
.ReverseMap();
CreateMap<OrderProduct, OrderProductDTO>()
.ForMember(dest => dest.ProductName, opt => opt.MapFrom(src => src.Product.PName))
.ForMember(dest => dest.OrderId , opt => opt.MapFrom(src => src.OrderId))
.ForMember(dest => dest.ProductId, opt => opt.MapFrom(src => src.Product.Id))
.ReverseMap();
CreateMap<Product, ProductDTO>()
.ForMember(dsc => dsc.productID, src => src.MapFrom(src => src.Id))
.ForMember(dsc => dsc.productName, src => src.MapFrom(src => src.PName))
.ForMember(dsc => dsc.productPrice, src => src.MapFrom(src => src.Price))
.ForMember(dsc => dsc.productImageURL, src => src.MapFrom(src => src.ImageUrl))
.ForMember(dsc => dsc.productRating, src => src.MapFrom(src => src.Rate))
.ReverseMap();
Order controller (I am using a repository pattern)
public async Task<IReadOnlyList<Order>> GetOrdersByUsernameAsync(string username)
{
return await _context.Set<Order>()
// .Include(o => o.AppUser)
.Include(o => o.OrderProducts)
.ThenInclude(op => op.Product)
.Where(o => o.AppUser.Id == username)
.ToListAsync();
}
[HttpGet("{userID}")]
public async Task<IActionResult> GetOrdersByUserId(string userID)
{
var orders = await unitOfWork.Orders.GetOrdersByUsernameAsync(userID);
if (orders == null)
{
return BadRequest($"There is no order yet or not found..");
}
// var result = _mapper.Map<IEnumerable<OrderDTO>>(orders);
// return Ok(orders);
// return Ok(result);
var orderDTOs = new List<OrderDTO>();
foreach (var order in orders)
{
var orderDTO = new OrderDTO
{
OrderId = order.Id,
OrderProductDTO = new List<OrderProductDTO>()
};
foreach (var orderProduct in order.OrderProducts)
{
var orderProductDTO = new OrderProductDTO
{
ProductId = orderProduct.ProductId,
ProductName = orderProduct.Product.PName, // manual mapping to product name
Price = orderProduct.Product.Price,
Quantity = orderProduct.Product.Quantity,
};
orderDTO.OrderProductDTO.Add(orderProductDTO);
}
orderDTOs.Add(orderDTO);
}
return Ok(orderDTOs);
}
The returned order without mapping
[
{
"id": 1017,
"orderDate": "2023-04-13T21:38:19.2123593",
"status": 0,
"appUser": null,
"orderProducts": [
{
"id": 0,
"orderId": 1017,
"productId": 1,
"product": {
"id": 1,
"pName": "Nike Men Running Shoes Revolution 5",
"pDescription": "Shoes",
"price": 2000,
"quantity": 50
}
},
{
"id": 0,
"orderId": 1017,
"productId": 2,
"product": {
"id": 2,
"pName": "Supernova",
"pDescription": "Shoes",
"price": 2200,
"quantity": 50
}
}
]
}
]
with manual mapping;
[
{
"orderId": 1017,
"orderDate": "0001-01-01T00:00:00",
"productName": null,
"orderProductDTO": [
{
"orderId": 0,
"products": null,
"productId": 1,
"productName": "Nike Men Running Shoes Revolution 5",
"price": 2000,
"quantity": 50
},
{
"orderId": 0,
"products": null,
"productId": 2,
"productName": "Supernova",
"price": 2200,
"quantity": 50
}
]
}
]
With AutoMapper automatic mapping:
[
{
"orderId": 1017,
"orderDate": "2023-04-13T21:38:19.2123593",
"productName": null,
"orderProductDTO": [] // Why is not Mapping Right?
}
]
I am expecting mapped result even when using AutoMapper ...
I have modified your code for the better readability in the answer per se.
As @Drewskis mentioned , you need to rename the field in OrderDTO.
And another one in the OrderProductDTO.
Order
public class Order
{
public Order()
{
OrderDate = DateTime.Now;
}
public int Id { get; set; }
public DateTime OrderDate { get; set; }
public AppUser AppUser { get; set; }
public ICollection<OrderProduct> OrderProducts { get; set; } = new HashSet<OrderProduct>()
}
public class OrderDTO
{
public int OrderId { get; set; }
public DateTime OrderDate { get; set; }
public string ProductName { get; set; }
public List<OrderProductDTO> OrderProducts { get; set; } = new List<OrderProductDTO>(); // Renamed from OrderProductDTO
}
CreateMap<Order, OrderDTO>()
.ForMember(dest => dest.OrderId, opt => opt.MapFrom(src => src.Id))
.ReverseMap();
Order Product
public class OrderProduct
{
public int Id { get; set; }
public int OrderId { get; set; }
public Order Order { get; set; }
public int ProductId { get; set; }
public Product Product { get; set; }
}
public class OrderProductDTO
{
public int OrderId { get; set; }
public ProductDTO Product { get; set; } // Renamed from Products
public int ProductId { get; set; }
public string ProductName { get; set; }
public decimal Price { get; set; }
public int Quantity { get; set; }
}
CreateMap<OrderProduct, OrderProductDTO>()
.ForMember(dest => dest.ProductName, opt => opt.MapFrom(src => src.Product.PName))
.ForMember(dest => dest.OrderId , opt => opt.MapFrom(src => src.OrderId))
.ForMember(dest => dest.ProductId, opt => opt.MapFrom(src => src.Product.Id))
.ReverseMap();
Product
public class Product
{
public int Id { get; set; }
[Required, MaxLength(150)]
public string PName { get; set; }
[Required, MaxLength(250)]
public string PDescription { get; set; }
public decimal Price { get; set; }
}
public class ProductDTO
{
public int productID { get; set; }
public string productName { get; set; }
public decimal productPrice { get; set; }
public int productRating { get; set; }
public string productImageURL { get; set; }
}
CreateMap<Product, ProductDTO>()
.ForMember(dsc => dsc.productID, src => src.MapFrom(src => src.Id))
.ForMember(dsc => dsc.productName, src => src.MapFrom(src => src.PName))
.ForMember(dsc => dsc.productPrice, src => src.MapFrom(src => src.Price))
.ForMember(dsc => dsc.productImageURL, src => src.MapFrom(src => src.ImageUrl))
.ForMember(dsc => dsc.productRating, src => src.MapFrom(src => src.Rate))
.ReverseMap();