Search code examples
c#azurenestedinversion-of-controlautomapper

Automapper - Unable to map nested objects/collecions


I've tried numerous examples on here and from the automapper wiki and I am still unable to get this issue resolved. I am trying to map a nested object and a nested collection and no matter what I do it always throws an error. The only way I can get the controller to return data is by turning on option.ignore for the two properties.

These are the business layer objects I am trying to map

public class LocationBL
{
    public int Id { get; set; }        
    public string Name { get; set; }
    public string Address { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zipcode { get; set; }
    public string Country { get; set; }

    public DbGeography Coordinates { get; set; }

    public int LocationType_Id { get; set; }

    public virtual LocationTypeBL LocationType { get; set; }

    public virtual ICollection<SportBL> Sports { get; set; }
}

public class LocationTypeBL
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<LocationBL> Locations { get; set; }
}
public class SportBL
{

    public int Id { get; set; }

    public string Name { get; set; }

    public virtual ICollection<LocationBL> Locations { get; set; }

    public virtual ICollection<UserBL> Users { get; set; }
}

These are the data layer objects

public class Location : EntityData
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    [ForeignKey("Company")]
    public int? CompanyId { get; set; }

    [Required]
    public string Name { get; set; }
    public string Address { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zipcode { get; set; }
    public string Country { get; set; }
    [Required]
    public DbGeography Coordinates { get; set; }
    [ForeignKey("LocationType")]
    public int LocationType_Id { get; set; }

    public virtual LocationType LocationType { get; set; }

    public virtual ICollection<Sport> Sports { get; set; }
    public virtual Company Company { get; set; }
}

public class LocationType : EntityData
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Location> Locations { get; set; }
}

public class Sport : EntityData
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }

    public virtual ICollection<Location> Locations { get; set; }

    public virtual ICollection<User> Users { get; set; }
}

This is my mapping profile

public class LocationProfile : Profile
{
    public LocationProfile()
    {
        CreateMap<LocationType, LocationTypeBL>();
        CreateMap<LocationTypeBL, LocationType>();
        CreateMap<Location, LocationBL>()
            .ForMember(Dest => Dest.Sports,
            opt => opt.MapFrom(src => src.Sports))
            .ForMember(Dest => Dest.LocationType,
            opt => opt.MapFrom(src => src.LocationType));

        CreateMap<LocationBL, Location>()
            .ForMember(Dest => Dest.Sports,
            opt => opt.MapFrom(src => src.Sports))
            .ForMember(Dest => Dest.LocationType,
            opt => opt.MapFrom(src => src.LocationType));




    }
}

UPDATE ******* This is my LocationType profile

public class LocationTypeProfile : Profile
{
    public LocationTypeProfile()
    {
        CreateMap<LocationType, LocationTypeBL>();
        CreateMap<LocationTypeBL, LocationType>();
    }
}

This is my Sport profile

    public class SportProfile : Profile
{
    public SportProfile()
    {
        CreateMap<Sport, SportBL>();
        CreateMap<SportBL, Sport>();
    }
}

Not sure if it matters but this is an Azure Mobile App backend using Autofac, WebAPI, and OWIN. This is my first time using AutoMapper and Autofac so please forgive me as I am still learning. The profiles are all registered and if I set the nested objects to ignore, the controller returns the proper data.

Thank you in advance!!!


Solution

  • You are almost there. You need to instruct AutoMapper on how to map the nested objects as well. So you need to create a map for the Sport to SportBL, and vice-versa, also.

    // use ForMember if needed, but you know how to do that so I won't
    // show it.
    CreateMap<Sport, SportBL>(); 
    

    Then AutoMapper will use that mapping when it mapping nested complex types.

    Another note, if your classes have the same properties, you can just call the ReverseMap() method and it will do bidirectional mapping for you.

    So instead of this:

    CreateMap<LocationType, LocationTypeBL>();
    CreateMap<LocationTypeBL, LocationType>();
    

    You can just do this to accomplish the same thing:

    Mapper.CreateMap<LocationType, LocationTypeBL>().ReverseMap();