0

The error message that I'm receiving at runtime is:

Unmapped members were found. Review the types and members below. Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type

For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters

List'1 -> MobileRoot (Destination member list) System.Collections.Generic.List'1[[Strata.CS.Jazz.Biz.Dashboard.MobileInfo, Strata.CS.Jazz.Biz, Version=2019.10.0.0, Culture=neutral, PublicKeyToken=null]] -> Strata.Jazz.Web.Controllers.MobileController+MobileRoot (Destination member list)

Unmapped properties: Users


From what I can tell from the error message is that AutoMapper needs to know how to handle the ForMember Users create in the MobileRoot, and then propagate that for each of the subsequent lists down the chain. Can anyone tell me how to do this efficiently using AutoMapper? I know how to do this with Linq using GroupBy and Select, so it is my thought that this should be do-able with AutoMapper.


The query I have returns this class:

public class MobileInfo
{
    public string NameFull { get; set; }
    public string EmailAddress { get; set; }
    public string SolutionName { get; set; }
    public int SortOrder { get; set; }
    public string Name { get; set; }
    public bool IsLegacy { get; set; }
    public string Description { get; set; }
    public string WidgetName { get; set; }
    public int Row { get; set; }
    public int Col { get; set; }
    public int Height { get; set; }
    public int Width { get; set; }
    public string WidgetClassName { get; set; }
    public string  Data { get; set; }
}

I would like to use Automapper with profiles to have it return this:

    internal class MobileRoot
    {
        public IEnumerable<MobileUser> Users { get; set; }
    }

    internal class MobileUser
    {
        public string NameFull { get; set; }
        public string EmailAddress { get; set; }
        public IEnumerable<MobileSolution> Solutions { get; set; }
    }

    internal class MobileSolution
    {
        public string Solution { get; set; } // MobileInfo.SolutionName
        public int SortOrder { get; set; }
        public IEnumerable<MobileDashboard> Dashboards { get; set; }
    }

    internal class MobileDashboard
    {
        public string Dashboard { get; set; } // MobileInfo.Name
        public bool IsLegacy { get; set; }
        public string Description { get; set; }
        public IEnumerable<MobileWidget> Widgets { get; set; }
    }

    internal class MobileWidget
    {
        public string Widget { get; set; } // MobileInfo.WidgetName
        public int Row { get; set; }
        public int Col { get; set; }
        public int Height { get; set; }
        public int Width { get; set; }
        public string WidgetClassName { get; set; }
        public string Data { get; set; }
    }

The Profiles I have defined so far are:

    public class ProfileMobileRoot : Profile
    {
        public ProfileMobileRoot()
        {
            CreateMap<MobileInfo, MobileRoot>();
        }
    }

    public class ProfileMobileUser : Profile
    {
        public ProfileMobileUser()
        {
            CreateMap<MobileInfo, MobileUser>();
        }
    }

    public class ProfileMobileSolution : Profile
    {
        public ProfileMobileSolution()
        {
            CreateMap<MobileInfo, MobileSolution>();
        }
    }

    public class ProfileMobileDashboard : Profile
    {
        public ProfileMobileDashboard()
        {
            CreateMap<MobileInfo, MobileRoot>();
        }
    }

    public class ProfileMobileWidget : Profile
    {
        public ProfileMobileWidget()
        {
            CreateMap<MobileInfo, MobileWidget>();
        }
    }
0

1 Answer 1

0

You can do something like below. It's a little late so my solution isn't so sophisticated... but it works ;)

public class ProfileMobileRoot : Profile
{
    public ProfileMobileRoot()
    {
        CreateMap<MobileInfo, MobileWidget>()
            .ForMember(x=>x.Name, opt=>opt.MapFrom(x=>x.WidgetName));
        CreateMap<IEnumerable<MobileInfo>, IEnumerable<MobileDashboard>>()
            .ConvertUsing<DashboardConverter>();

        CreateMap<IEnumerable<MobileInfo>, IEnumerable<MobileSolution>>()
            .ConvertUsing<SolutionConverter>();
        CreateMap<IEnumerable<MobileInfo>, IEnumerable<MobileUser>>()
            .ConvertUsing<UserConverter>();

        CreateMap<IEnumerable<MobileInfo>, MobileRoot>()
            .ForMember(x => x.Users, opt => opt.MapFrom(x => x.ToList()));
    }
}
class UserConverter : ITypeConverter<IEnumerable<MobileInfo>, IEnumerable<MobileUser>>
{
    public IEnumerable<MobileUser> Convert(IEnumerable<MobileInfo> source, IEnumerable<MobileUser> destination, ResolutionContext context)
    {
        var groups = source.GroupBy(x => new { x.NameFull, x.EmailAddress});
        foreach (var v in groups)
        {
            yield return new MobileUser()
            {
                EmailAddress = v.Key.EmailAddress,
                NameFull = v.Key.NameFull,
                Solutions = context.Mapper.Map<IEnumerable<MobileSolution>>(source.Where(x =>
                    v.Key.NameFull == x.NameFull && v.Key.EmailAddress== x.EmailAddress)).ToList()
            };
        }
    }
}
class SolutionConverter : ITypeConverter<IEnumerable<MobileInfo>, IEnumerable<MobileSolution>>
{
    public IEnumerable<MobileSolution> Convert(IEnumerable<MobileInfo> source, IEnumerable<MobileSolution> destination, ResolutionContext context)
    {
        var groups = source.GroupBy(x => new { x.SolutionName, x.SortOrder});
        foreach (var v in groups)
        {
            yield return new MobileSolution()
            {
                Solution = v.Key.SolutionName,
                SortOrder = v.Key.SortOrder,
                Dashboards= context.Mapper.Map<IEnumerable<MobileDashboard>>(source.Where(x =>
                    v.Key.SolutionName== x.SolutionName&& v.Key.SortOrder== x.SortOrder)).ToList()
            };
        }
    }
}

class DashboardConverter : ITypeConverter<IEnumerable<MobileInfo>, IEnumerable<MobileDashboard>>
{
    public IEnumerable<MobileDashboard> Convert(IEnumerable<MobileInfo> source, IEnumerable<MobileDashboard> destination, ResolutionContext context)
    {
        var groups = source.GroupBy(x => new {x.Name, x.IsLegacy, x.Description});
        foreach (var v in groups)
        {
            yield return new MobileDashboard()
            {
                Dashboard = v.Key.Name,
                Description = v.Key.Description,
                IsLegacy = v.Key.IsLegacy,
                Widgets = context.Mapper.Map<IEnumerable<MobileWidget>>(source.Where(x =>
                    v.Key.IsLegacy == x.IsLegacy && v.Key.Name == x.Name && v.Key.Description == x.Description))
            };
        }
    }
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.