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>();
其中 MyCoolAction
是 IMappingAction
的实现,例如 -
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
我当前的地图:
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>();
其中 MyCoolAction
是 IMappingAction
的实现,例如 -
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