AutoMapper - include/replace 使用 ReverseMap() 映射回源列表中的单个项目

AutoMapper - include/replace a single item in source list while mapping back with ReverseMap()

我当前的地图:

CreateMap<Item, ItemDetailsViewModel>()
  .ForMember(x => x.ActiveChildItem, d => d.MapFrom(z => z.ChildItems.FirstOrDefault(f => f.IsActive)))
  .ReverseMap()
  .ForMember(x => x.ChildItems, d => /*How I can find and replace item in source list 
                                                        items(ChildItems) to ActiveChildItem?*/)

从单个项目到项目集合的映射的最佳方法是什么?
我不想在我的视图模型中使用集合...

有一个完整的例子会更容易帮助你。还有一点你没有考虑到

当您从单个项目映射回集合时会发生什么?该集合是否应由具有单个项目的新集合替换?是否应该更改现有列表以及如果更改列表会发生什么情况,但在模型列表中找不到视图模型项。应该加吗?

所以不管这些悬而未决的问题,下面是一个关于如何替换整个列表的例子。

如果您需要不同的行为,请查看最后一个 CreateMap() 方法。第三个参数dest指向目标对象的当前属性值。所以它包含模型列表。您可以根据需要操作现有的 dest 列表,而不是返回一个值(就像我对新列表所做的那样)。

using System;
using System.Collections.Generic;
using System.Linq;
using AutoMapper;

namespace ConsoleApp
{
    public static class Program
    {
        public static void Main()
        {
            var config = new MapperConfiguration(conf => conf.AddProfile<MyProfile>());
            var mapper = config.CreateMapper();

            var model = new Model { Items = new[] { new ModelItem { Name = "NotActive Item", IsActive = false }, new ModelItem { Name = "Active Item", IsActive = true } } };

            var viewModel = mapper.Map<ViewModel>(model);
            var newModel = mapper.Map<Model>(viewModel);

            Console.WriteLine(viewModel.ActiveItem.Name);
            Console.WriteLine(newModel.Items.Count);
            Console.WriteLine(newModel.Items.First().Name);
            Console.WriteLine(newModel.Items.First().IsActive);
        }
    }

    public class MyProfile : Profile
    {
        public MyProfile()
        {
            CreateMap<ModelItem, ViewModelItem>();
            CreateMap<Model, ViewModel>()
                .ForMember(view => view.ActiveItem, conf => conf.MapFrom(model => model.Items.FirstOrDefault(item => item.IsActive)));

            CreateMap<ViewModelItem, ModelItem>().ForMember(item => item.IsActive, conf => conf.MapFrom(_ => true));
            CreateMap<ViewModel, Model>()
                .ForMember(model => model.Items, conf => conf.MapFrom((view, model, dest, context) => view.ActiveItem == null
                                                                                                    ? Array.Empty<ModelItem>()
                                                                                                    : new[] { context.Mapper.Map<ModelItem>(view.ActiveItem) }));
        }
    }

    public class Model
    {
        public IReadOnlyList<ModelItem> Items { get; set; }
    }

    public class ModelItem
    {
        public string Name { get; set; }
        public bool IsActive { get; set; }
    }

    public class ViewModel
    {
        public ViewModelItem ActiveItem { get; set; }
    }


    public class ViewModelItem
    {
        public string Name { get; set; }
    }
}

从技术上讲,这不是映射操作。当 属性 映射完成后,您应该执行此操作。

为此使用AfterMap方法-

CreateMap<Item, ItemDetailsViewModel>()
  .ForMember(x => x.ActiveChildItem, d => d.MapFrom(z => z.ChildItems.FirstOrDefault(f => f.IsActive)))
  .ReverseMap()
  .AfterMap((s, d) =>
    {
        // add or find-and-replace child item here
    });

或者,

CreateMap<Item, ItemDetailsViewModel>()
  .ForMember(x => x.ActiveChildItem, d => d.MapFrom(z => z.ChildItems.FirstOrDefault(f => f.IsActive)))
  .ReverseMap()
  .AfterMap<MyCoolAction>();

其中 MyCoolActionIMappingAction 的实现,例如 -

public class MyCoolAction : IMappingAction<ItemVM, Item>
{
    public void Process(ItemVM source, Item destination, ResolutionContext context)
    {
        // add or find-and-replace child item here
    }
}

有关更多信息,请查看文档 - Before and After Map Action