Automapper nested entity configuration best practices

Viewed 101

I am using Automapper to flatten a few nested EF classes down to a DTO that contains all the relevant properties, as well as a dictionary for localization lookup. See sample code below.

Entity classes:

public class DbClass
{
  public int PropA { get; set; }
  
  public DbDetails Details { get; set; }
}
public class DbDetails
{
  public int PropB { get; set; }
  public ICollection<DbResource> Resources { get; set; }
}
public class DbResource
{
  public string Language { get; set; }
  public string DisplayText { get; set; }
}

DTO Class:

public class DTO
{
  public int PropA { get; set; }
  public int PropB { get; set; }

  /// Lookup by language code
  public IDictionary<string, string> DisplayText { get; set; }
}

Automapper config:

CreateMap<DbClass, DTO>().IncludeMembers(c => c.Details);
CreateMap<DbDetails, DTO>().IncludeMembers(d => d.Resources);
CreateMap<ICollection<DbResource>, IDictionary<string, string>>()
    .ConstructUsing(src => src.ToDictionary(r => r.Language, r => r.DisplayText));
CreateMap<ICollection<DbResource>, DTO>()
    .ForMember(dest => dest.DisplayText, opts => opts.MapFrom(src => src));

I'm new to automapper, but this seems to be working correctly.

My question is, is there a cleaner or more condensed way to define the required mapping?

1 Answers

There are certainly a variety of ways to accomplish the same thing in AutoMapper. Here are a couple more condensed options with a more direct handling of DbDetails.Resources.

CreateMap<DbClass, DTO>()
    .IncludeMembers(dest => dest.Details);
CreateMap<DbDetails, DTO>()
    .ForMember(dest => dest.DisplayText, opt => opt.MapFrom(src => src.Resources));
CreateMap<ICollection<DbResource>, IDictionary<string, string>>()
    .ConstructUsing(src => src.ToDictionary(r => r.Language, r => r.DisplayText));

If you don't need to reuse the last map above (i.e. it is only used in the context of mapping DbDetails -> DTO), the configuration can be shortened to:

CreateMap<DbClass, DTO>()
    .IncludeMembers(dest => dest.Details);
CreateMap<DbDetails, DTO>()
    .ForMember(dest => dest.DisplayText, 
        opt => opt.MapFrom(src => src.Resources.ToDictionary(r => r.Language, r => r.DisplayText)));
Related