I have a problem when using AutoMapper to map my DTO on a POST Action to my database entity, since my database entity contains multiple references to other database entities, I used also multiple DTOs in my "WrapperDTO". But after mapping the Country/Address references on my Hotel-Model class are null.I can't figure out why, to me the mapping of the DTO -> Models seems to be right. Help would be highly appreciated.
Here are my Models and my DTOs:
Hotel Model:
public class Hotel
{
public int Id { get; set; }
public string Name { get; set; }
public double Rating { get; set; }
[ForeignKey(nameof(AddressId))]
public int AddressId { get; set; }
public Address Address { get; set; }
[ForeignKey(nameof(CountryId))]
public int CountryId { get; set; }
public Country Country { get; set; }
}
Hotel DTOs:
public class CreateHotelDto : BaseHotelDto
{
public CreateAddressDto AddressDto { get; set; }
public CreateCountryDto CountryDto { get; set; }
}
public class BaseHotelDto
{
public string Name { get; set; }
public double Rating { get; set; }
}
Then my Address Model:
public class Address
{
public int Id { get; set; }
public string StreetAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
}
And my Address DTOs:
public class CreateAddressDto : BaseAddressDto
{
}
public abstract class BaseAddressDto
{
public string StreetAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
}
And at last my Country Model:
[Index(nameof(Country.Name), IsUnique = true)]
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
public string CountryCode { get; set; }
public string ShortName { get; set; }
public virtual IList<Hotel> Hotels { get; set; }
}
And my Country DTOs:
[Index(nameof(CreateCountryDto.Name), IsUnique = true)]
public class CreateCountryDto : BaseCountryDto
{
[Required]
public string CountryCode { get; set; }
}
public abstract class BaseCountryDto
{
[Required]
public string Name { get; set; }
public string ShortName { get; set; }
}
I also have this code in my "MapperConfig"-Class to map the DTOs to my Models:
public MapperConfig()
{
#region CountryDbContext
CreateMap<CreateCountryDto, Country>().ReverseMap();
CreateMap<UpdateCountryDto, Country>().ReverseMap();
CreateMap<CountryDetailsDto, Country>().ReverseMap();
CreateMap<GetCountryDto, Country>().ReverseMap();
#endregion
#region AddressDbContext
CreateMap<GetAddressDto, Address>().ReverseMap();
CreateMap<UpdateAddressDto, Address>().ReverseMap();
CreateMap<CreateAddressDto, Address>().ReverseMap();
#endregion
#region HotelDbContext
CreateMap<HotelDetailsDto, Hotel>().ReverseMap();
CreateMap<GetHotelDto, Hotel>().ReverseMap();
CreateMap<CreateHotelDto, Hotel>().ReverseMap();
CreateMap<UpdateHotelDto, Hotel>().ReverseMap();
#endregion
}
And of course I injected the AutoMapper Service using this:
builder.Services.AddAutoMapper(typeof(MapperConfig));
And in my controller I mapped the CreateHotelDto (where the CreateHotelDto is provided through a parameter) -> Hotel with this:
var mappedHotel = _mapper.Map<Hotel>(createHotelDto);
I used the following Dummy-JSON as data for the endpoint:
{
"name": "Hotel Cirrus Shake",
"rating": 3.0,
"addressDto": {
"streetAddress": "87 North Bear Hill St.",
"city": "New York City",
"state": "NY",
"zipCode": "11756"
},
"countryDto": {
"name": "USA",
"shortName": "US",
"countryCode": "840"
}
}
The properties "Name" and "Rating" of the HotelDto are mapped correctly, however the AddressDto/CountryDto are not mapped correctly to their Model counterparts they are just null, the Ids are 0 but that's fine because they are auto incremented values on the SQL-Server and are therefore not needed.
Here's also a screenshot of my Debugger containing the relevant information about those objects:
CodePudding user response:
Change your MapperConfig
like below:
public class MapperConfig : Profile
{
public MapperConfig()
{
CreateMap<CreateCountryDto, Country>().ReverseMap();
CreateMap<CreateAddressDto, Address>().ReverseMap();
CreateMap<CreateHotelDto, Hotel>()
.ForPath(a=>a.Address,o=>o.MapFrom(dto=>dto.AddressDto)) //add this...
.ForPath(a=>a.Country, o=>o.MapFrom(dto=>dto.CountryDto)) //add this...
.ReverseMap();
}
}
Result: