Reduce a list down to a field with runtime parameter

95 Views Asked by At

Is it possible to configure Automapper so it can map from a collection to a single instance based on a run-time parameter?

In our application our entities have labels for each language. Depending on the preference of the current user, a single value should be shown.

DepartmentEntity
  Labels: Label[]
    Value: string
    Culture: CultureInfo

DepartmentViewModel
  Label: string

Given I know the current user culture when I map my entities, could I configure Automapper so it can map from DepartmentEntity to DepartmentViewModel?

Something like

var department = Mapper.Map<DepartmentEntity, DepartmentViewModel>(user.Culture);

Other answers like this one seem to want to pass a parameter to use as target value straight up. I want to use it as a way to reduce a list to a single field.

1

There are 1 best solutions below

1
On

You can do it the same as the answer you mentioned:

var department = Mapper.Map<DepartmentEntity, DepartmentViewModel>(departmentEntity,
  opt => opt.AfterMap((src, dest) => dest.Label = src.Labels.FirstOrDefault(x=> 
                                       x.CultureInfo.Name == user.Culture.Name)?.Value));

Keep in mind that you have to make the ignore call when defining the map.

UPDATE

You are correct and after some more research it's actually possible and fairly easy to achieve this with Automapper. The feature I got it from this SO answer.

cfg.CreateMap<DepartmentEntity, DepartmentViewModel>().ForMember(x => x.Label, opt => 
opt.ResolveUsing((src, dest, member, context) => 
                  src.Labels.FirstOrDefault(x=> x.Culture.Name == 
                           context.Items["userCulture"].ToString())?.Value));

And when converting objects use

var userCulture = new CultureInfo("en-US");
var department = Mapper.Map<DepartmentViewModel>(depEntity,
            opt => opt.Items["userCulture"] = userCulture.Name);