简体   繁体   中英

How can I use Automapper to assign values to fields in destination model but not in source model?

I am getting the hang of Automapper in an ASP.NET MVC 5 application for the purpose of mapping a domain model to a ViewModel. There is a case that I still don't know how to resolve: when the ViewModel (destination) has a property not in the domain model (source).

The two additional properties in the ViewModel are IEnumerables that I need to populate in the Controller.

As I explain in the comments in the Controller block (shown below), the domain model is the source and will be fed into the View table. The additional two IEnumerables in the ViewModel will fill the DropDownLists in the HTML.BeginForm() block.

The examples I have seen using .CreateMap<>().ForMember() deal with calculations or transformations of properties in the source model, and not this case, where I am defining something in the controller based on the Action parameters.

My question is how to map the remaining IEnumerables, as defined in the controller?

Mapping Config in App_Start

public static class MappingConfig
{
    public static void RegisterMaps()
    {
        AutoMapper.Mapper.Initialize(config =>
            {
                config.CreateMap<StudentRoster, StudentRosterViewModel>();
            });
    }
}

Model and ViewModel:

[Table("StudentRoster")]
public partial class StudentRoster
{
    public int ID { get; set; }

    [Required]
    [StringLength(3)]
    public string Campus { get; set; }

    [Required]
    [StringLength(4)]
    public string FiscalYear { get; set; }

    [Required]
    [StringLength(50)]
    public string StudentName { get; set; }

    public int StudentID { get; set; }               

}

// ViewModel

public partial class StudentRosterViewModel
{
    // Automapper successfully mappped the first five fields
    // to the parent class
    public int ID { get; set; }

    public string Campus { get; set; }

    public string FiscalYear { get; set; }

    public string StudentName { get; set; }

    public int StudentID { get; set; }     


    // These two fields are not in the parent class
    public IEnumerable<SelectListItem> CampusListSelect { get; set; }
    public IEnumerable<SelectListItem> FiscalYearSelect { get; set; }
}

Index Action in Controller:

// GET: StudentRosterViewModels
public ActionResult Index(string campus = "MRA", string fy="FY16")
{
    IEnumerable<StudentRoster> query = db.StudentRosters.Where(m=>m.Campus==campus).ToList();

    // This successfully maps the domain model to the viewmodel
    // This IEnumerable will display in the "Table"
    IEnumerable<StudentRosterViewModel> mappedQuery =
        AutoMapper.Mapper.Map<IEnumerable<StudentRoster>, IEnumerable<StudentRosterViewModel>>(query);

    // The two remaining IEnumerables need to be mapped to 'mappedQuery'
    //   CampusListSelect and FiscalYearSelect
    // These two IEnumerables will populate the dropdownlists in Html.BeginForm()
    IEnumerable<SelectListItem> CampusList = new SelectList(new List<string> { "CRA", "DRA", "MRA", "PRA" }, campus);
    IEnumerable<SelectListItem> FiscalYearList = new SelectList(new List<string> { "FY12", "FY13", "FY14", "FY15", "FY16" }, fy);                

    return View(mappedQuery.ToList());
}

You can try to use DynamicMap to populate your items without creating additional classes for mapping.

In case if you're using the old version of AutoMapper (4.1 or below) the you can try something the following:

// GET: StudentRosterViewModels
public ActionResult Index(string campus = "MRA", string fy="FY16")
{
    IEnumerable<StudentRoster> query = db.StudentRosters.Where(m=>m.Campus==campus).ToList();

    // This successfully maps the domain model to the viewmodel
    // This IEnumerable will display in the "Table"
    IEnumerable<StudentRosterViewModel> mappedQuery =
        AutoMapper.Mapper.Map<IEnumerable<StudentRoster>, IEnumerable<StudentRosterViewModel>>(query);

    // The two remaining IEnumerables need to be mapped to 'mappedQuery'
    //   CampusListSelect and FiscalYearSelect
    // These two IEnumerables will populate the dropdownlists in Html.BeginForm()
    IEnumerable<SelectListItem> CampusList = new SelectList(new List<string> { "CRA", "DRA", "MRA", "PRA" }, campus);
    IEnumerable<SelectListItem> FiscalYearList = new SelectList(new List<string> { "FY12", "FY13", "FY14", "FY15", "FY16" }, fy);                

    var objForDynamicMapping = new 
    { 
        CampusListSelect = CampusList,
        FiscalYearListSelect = FiscalYearList
    };

    foreach(var mappedItem in mappedQuery)
    {
        // will create the mapping configuration dynamically
        AutoMapper.Mapper.DynamicMap(objForDynamicMapping, mappedItem);
    }

    return View(mappedQuery.ToList());
}

In case if you're using the AutoMapper 4.2 or high.

Then you just need to put this row:

var config = new MapperConfiguration(cfg => cfg.CreateMissingTypeMaps = true);

in place where you create the mapper configuration and then just use method Map like:

mapper.Map(objForDynamicMapping, mappedItem);

instead of DynamicMap .

Hope it will help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM