I am trying to use Automapper to return a navigation property ViewModel
Models:
public class Month
{
public int Id { get; set; }
public string MonthName { get; set; }
public int YearId { get; set; }
public Year Year { get; set; }
}
public class Year
{
public int Id { get; set; }
public string YearName { get; set; }
}
ViewModels:
public class MonthViewModel
{
public int Id { get; set; }
public string MonthName { get; set; }
Display(Name = "Financial Year")
public int YearId { get; set; }
public YearViewModel Year { get; set; }
}
public class YearViewModel
{
public int Id { get; set; }
Display(Name = "Financial Year Name")
public string YearName { get; set; }
}
I am currently have a ASP.NET MVC
view Mapping displaying a list of Months in a table and I need to inlcude the Year Name as a column
public IActionResult Index()
{
var months = _monthRepo.GetAll().Include(m=>m.Year);
IEnumerable<MonthViewModel> monthsVms = MonthViewModel.MapToViewModel(months);
return View(monthsVms);
}
public static IEnumerable<MonthViewModel> MapToViewModel(IEnumerable<Month> dm)
{
Mapper.CreateMap<Month, MonthViewModel>();
Mapper.CreateMap<Year, YearViewModel>();
return Mapper.Map<IEnumerable<Month>, IEnumerable<MonthViewModel>>(dm);
}
//However in my view when I want to refer to the year name like below:
@foreach (var item in Model)
{
@Html.EditorFor(modelItem => item.YearViewModel.YearName)
}
However item.YearViewModel
is null
.
Question:
There is a 1 to 0/1 relation between the main class and its navigation property. e.g. I want to display a list of Months with Columns Month Name and Year Name next to each other. (because I want to only use ViewModels Data Annotations)
I found a similar question here but I couldn't get it to work
Mapper.CreateMap<Month, MonthViewModel>().ForMember(dest => dest.YearViewModel.YearName, opt => opt.MapFrom(src => src.Year.YearName));
Mapper.CreateMap<Year, YearViewModel>();
return Mapper.Map<IEnumerable<Month>, IEnumerable<MonthViewModel>>(dm);
but I get
ArgumentException: Expression 'dest => dest.FinancialYearViewModel.FinancialYearName' must resolve to top-level member and not any child object's properties. Use a custom resolver on the child type or the AfterMap option instead. Parameter name: lambdaExpression
I get the same problem when I try
Mapper.CreateMap<Year, YearViewModel>();
AutoMapper.Mapper.CreateMap<Month, MonthViewModel>()
.ForMember(a => a.YearViewModel.YearName, b => b.ResolveUsing(c => c.Year.YearName));
Solution provide in answer was to map the whole navigation property:
Mapper.CreateMap<Year, YearViewModel>();
AutoMapper.Mapper.CreateMap<Month, MonthViewModel>()
.ForMember(a => a.YearViewModel, b => b.ResolveUsing(c => c.Year));
Possibly this is what you want -
AutoMapper.Mapper.CreateMap<Year, YearViewModel>();
AutoMapper.Mapper.CreateMap<Month, MonthViewModel>()
.ForMember(a => a.Year, b => b.ResolveUsing(c => c.Year));
var o = AutoMapper.Mapper.Map<MonthViewModel>(new Month
{
Id = 1,
MonthName = "January",
YearId = DateTime.Now.Year,
Year = new Year
{
Id = DateTime.Now.Year,
YearName = DateTime.Now.Year.ToString()
}
}); // should map year as well.