AutoMapper 在地图中引用地图

AutoMapper referencing a map within a map

我真的在为如何实现这一点而苦苦挣扎,我基本上是在尝试为我的 Index 查看 ClubViewModel 列表,但要做到这一点,我需要匹配我的 [= 列表15=]。我正在使用 AutoMapper,除了 CalendarEntry 之外的所有东西都运行良好,它是我的数据库模型中的列表和我的视图模型中的扁平化 class。

我真的不想改变我的视图模型,因为我以我想要的方式创建了视图(每天的布尔值和关联的 start/finish 次)。

首先是 控制器,它成功映射了大部分 class:

    public ActionResult Index()
    {   
        var clubsList = _service.GetAllClubs();
        IList<ClubViewModel> clubsViewModelList = new List<ClubViewModel>();

        foreach (var item in clubsList)
        {
            clubsViewModelList.Add(AutoMapper.Mapper.Map<ClubViewModel>(item));                
        }               
        return View(clubsViewModelList);
    }

这是我的 Repository ModelsEnums 以及我的 Web ViewModels

   public class Club
    {        
        public int ClubId { get; set; }        
        public string Organisation { get; set; }
        public List<CalendarEntry> MeetingDays { get; set; }        
    }

    public class CalendarEntry
    {
        public int CalendarEntryId { get; set; }
        public int ClubId { get; set; }
        public Days Day { get; set; }
        public DateTime From { get; set; }
        public DateTime To { get; set; }      
    }

    public enum Days
    {
        Monday,
        Tuesday,
        Wednesday,
        Thursday,
        Friday,
        Saturday,
        Sunday
    }

    public class ClubViewModel
    {
        public int ClubId { get; set; }
        public string Organisation { get; set; }
        public CalendarEntryViewModel CalendarEntryViewModel { get; set; }      
    }

    public class CalendarEntryViewModel
    { 
        public bool IsMonday { get; set; }
        public bool IsTuesday { get; set; }
        public bool IsWednesday { get; set; }
        public bool IsThursday { get; set; }
        public bool IsFriday { get; set; }     
        public DateTime? MondayFrom { get; set; }        
        public DateTime? MondayTo { get; set; }        
        public DateTime? TuesdayFrom { get; set; }        
        public DateTime? TuesdayTo { get; set; }        
        public DateTime? WednesdayFrom { get; set; }        
        public DateTime? WednesdayTo { get; set; }        
        public DateTime? ThursdayFrom { get; set; }        
        public DateTime? ThursdayTo { get; set; }        
        public DateTime? FridayFrom { get; set; }        
        public DateTime? FridayTo { get; set; }
    }

最后是我的AutoMapper 配置方法:

public static void RegisterMappings()
        {
            Mapper.CreateMap<Club, ClubViewModel>()                

                .ForMember(dest => dest.CalendarEntryViewModel,
                opts => opts.Ignore());

                Mapper.CreateMap<CalendarEntry, CalendarEntryViewModel>()

                    .ForMember(dest => dest.IsMonday, opts => opts.Equals(true))
                    .ForMember(dest => dest.IsTuesday, opts => opts.Equals(true))
                    .ForMember(dest => dest.IsWednesday, opts => opts.Equals(true))
                    .ForMember(dest => dest.IsThursday, opts => opts.Equals(true))
                    .ForMember(dest => dest.IsFriday, opts => opts.Equals(true))

                    .ForMember(dest => dest.MondayFrom, opts => opts.Equals(DateTime.Now))
                    .ForMember(dest => dest.MondayTo, opts => opts.Equals(DateTime.Now))
                    .ForMember(dest => dest.TuesdayFrom, opts => opts.Equals(DateTime.Now))
                    .ForMember(dest => dest.TuesdayTo, opts => opts.Equals(DateTime.Now))
                    .ForMember(dest => dest.WednesdayFrom, opts => opts.Equals(DateTime.Now))
                    .ForMember(dest => dest.WednesdayTo, opts => opts.Equals(DateTime.Now))
                    .ForMember(dest => dest.ThursdayFrom, opts => opts.Equals(DateTime.Now))
                    .ForMember(dest => dest.ThursdayTo, opts => opts.Equals(DateTime.Now))
                    .ForMember(dest => dest.FridayFrom, opts => opts.Equals(DateTime.Now))
                    .ForMember(dest => dest.FridayTo, opts => opts.Equals(DateTime.Now));

                Mapper.AssertConfigurationIsValid();
        }

暂时我只是硬编码了 bools/dates 的值,同时尝试让事情正常进行。

我是否可以以某种方式将第二个 CalendarEntryCalendarEntryViewModel 映射添加到 ClubClubViewModel 映射作为附加成员,或者我是否完全这样做错了?

您应该解压缩 CalendarEntryViewModel 以便它更接近地代表您域中的日历条目。您目前正在尝试将列表推入扁平化的对象中。这会让您以后更加痛苦。

在开始之前,我不得不提一下:

foreach (var item in clubsList)
{
    clubsViewModelList.Add(AutoMapper.Mapper.Map<ClubViewModel>(item));                
}

Automapper 可以处理列表...因此可以是:

var clubsViewModelList = Mapper.Map<IList<Club>, IList<ClubViewModel>>(clubsList);

解压视图模型

我知道这是你说的你不想做的..但你真的应该。它将使您的域和视图之间的映射更加简单。出于很多原因,我完全赞成将它们分开,但我认为您尝试将这种域模型扁平化为单个视图模型并没有给自己带来任何好处。所以将它解压到多个视图模型:

public class ClubViewModel
{
    public int ClubId { get; set; }
    public string Organisation { get; set; }
    public IList<CalendarEntryViewModel> CalendarEntries { get; set; } // <--- a list of them      
}

您的地图将变为:

.ForMember(dest => dest.IsMonday, opt => opt.MapFrom(src => src.Day == Days.Monday))
.ForMember(dest => dest.IsTuesday, opt => opt.MapFrom(src => src.Day == Days.Tuesday))
/* etc... */

然后,删除所有可为空的日期并只用两个字段表示此条目:

public DateTime? From { get; set; }        
public DateTime? To { get; set; }

然后您可以按天订购:

foreach (var club in clubsViewModelList) {
    club.CalendarEntries = club.CalendarEntries.OrderBy(x => x.Day).ToList();
}

那么在你看来..只需按顺序渲染它们:

@foreach (var calendarEntry in club.CalendarEntries) {
    Day: @calendarEntry.Day.ToString()
    From: @calendarEntry.From.ToString("D")
}

..等

当需要创建时..您只需根据需要呈现您的条目:

public class ClubCalendarEntryCreateViewModel {
    /* other properties here */
    public IList<CalendarEntryViewModel> Days { get; set; }
}

然后在你的控制器中:

viewModel.CalendarEntries = new ClubCalendarEntryCreateViewModel {
    Days = new List<CalendarEntryViewModel>() {
        new CalendarEntryViewModel {
            IsMonday = true
        },
        new CalendarEntryViewModel {
            IsTuesday = true
        },
        /* etc... */
    }
};

然后您只需渲染它们并在您的 POST 方法中接受它。您对该方法的映射变为:

club.CalendarEntries = Mapper.Map<IList<CalendarEntryViewModel>, IList<CalendarEntry>>(viewModel.CalendarEntries.Days);

我在这里遗漏了一点(比如你将如何改造你的 CalendarEntry 域对象).. 希望你能填空并理解我的意思。我知道这看起来工作量很大——但你以后会做得更好。您的映射不会像现在这样成为您的敌人(它们永远不应该成为您的敌人)并且您的代码将变得更加清晰。

希望对您有所帮助...这可能不是您想听到的,但绝对是我会怎么做(或类似的,如果有更多要求)。