Search code examples
c#asp.net-mvcasp.net-coreautomapperviewmodel

Mapping viewmodel children with parameter AutoMapper


I'm pretty new using AutoMapper and i run into an issue

I have a model like this.

public class StepUp {
    public string Example {get;set;}
    public string Example2 {get;set;}
    public decimal? auxValue { get;set; }
}

But i have two ViewModels as destination

public class NuevoStepUpViewModel()
{
    public bool TieneAuxiliar { get; set; }
    public string Example { get;set; }
    public CargaDatosElectricos CargaDatosElectricos { get; set; }
}

public class CargaDatosElectricos {
    public CargaDatosElectricos(bool tieneAuxiliar)
    {
        TieneAuxiliar = tieneAuxiliar;
    }
    public readonly bool TieneAuxiliar;
    public string Example2 { get; set; }
}

I think some like this:

CreateMap<StepUp,NuevoStepUpViewModel()
    .ForMember(x => x.TieneAuxiliar, x => x.MapFrom(c => c.auxValue.HasValue))
    .ForMember(x => x.Example, x => x.MapFrom(c => c.Example))
    .ForMember(x => x.CargaDatosElectricos.Example2, x => x.MapFrom(c => c.Example2))
    .BeforeMap((x,y) => {
        x.CargaDatosElectricos = new CargaDatosElectricos(c.auxValue.HasValue);
    });

But i'm getting

Expression 'x => x.CargaDatosElectricos.Example2' must resolve to top-level member and not any child object's properties

How should i create my mapper configuration to do this type of mapping?


Solution

  • There are some errors on your code. You could configure better your mapping using the AfterMap scope instead of BeforeMap to provide a complex configuration. (I am not sure but I think the) AutoMapper will not instance a property where the type is a class. So, you have to do it on the construtor of the destination class (VIewModel) or do it on AfterMap.

    The TieneAuxiliar property will not allow you to set a value when it is readonly, so, you will not able to configure a map to this property. I change it to a public classic property.

    See the working sample here:

    https://dotnetfiddle.net/HSyUVv

    using System;
    using AutoMapper;
    
    public class Program
    {
        public static void Main()
        {
            var config = new MapperConfiguration(cfg => 
            {
                cfg.CreateMap<StepUp, NuevoStepUpViewModel>()
                    .ForMember(vm => vm.TieneAuxiliar, opt => opt.MapFrom(e => e.auxValue.HasValue))
                    .ForMember(vm => vm.Example, opt => opt.MapFrom(e => e.Example))
                    .AfterMap((e, vm) => 
                              {
                                  vm.CargaDatosElectricos.Example2 = e.Example2;
                              });
            });
    
            var mapper = config.CreateMapper();
    
            var stepUp = new StepUp()
            {
                Example = "Example 1",
                Example2 = "Example 2",
                auxValue = 10m
            };
    
            var viewModel = mapper.Map<StepUp, NuevoStepUpViewModel>(stepUp);
    
            Console.WriteLine("SteUp was converted to ViewModel");
            Console.WriteLine("TieneAuxiliar: {0}", viewModel.TieneAuxiliar);
            Console.WriteLine("Example: {0}", viewModel.Example);
            Console.WriteLine("CargaDatosElectricos.TieneAuxiliar: {0}", viewModel.CargaDatosElectricos.TieneAuxiliar);
            Console.WriteLine("CargaDatosElectricos.Exemple2: {0}", viewModel.CargaDatosElectricos.Example2);
    
        }
    
        public class StepUp 
        {
            public string Example { get; set; }
            public string Example2 { get; set; }
            public decimal? auxValue { get; set; }
        }
    
        public class NuevoStepUpViewModel
        {
            public bool TieneAuxiliar { get; set; }
            public string Example { get;set; }
            public CargaDatosElectricos CargaDatosElectricos { get; set; }
    
            public NuevoStepUpViewModel() 
            {
                this.CargaDatosElectricos = new CargaDatosElectricos();
            }
        }
    
        public class CargaDatosElectricos 
        {
            public CargaDatosElectricos()
            {
            }
            public bool TieneAuxiliar { get; set; }
            public string Example2 { get; set; }
        }
    }