C# 递归模型的自动映射条件映射
我有一个递归模型类,定义如下:C# 递归模型的自动映射条件映射,c#,automapper,C#,Automapper,我有一个递归模型类,定义如下: public class ItemFilterBlockGroup { public ItemFilterBlockGroup(string groupName, ItemFilterBlockGroup parent, bool advanced = false) { GroupName = groupName; ParentGroup = parent; Advanced = advanced;
public class ItemFilterBlockGroup
{
public ItemFilterBlockGroup(string groupName, ItemFilterBlockGroup parent, bool advanced = false)
{
GroupName = groupName;
ParentGroup = parent;
Advanced = advanced;
ChildGroups = new List<ItemFilterBlockGroup>();
}
public string GroupName { get; private set; }
public bool Advanced { get; private set; }
public ItemFilterBlockGroup ParentGroup { get; private set; }
public List<ItemFilterBlockGroup> ChildGroups { get; private set; }
}
第一个CreateMap定义返回未触及的层次结构,第二个CreateMap定义(带有Advanced参数)返回修改后的层次结构(所有Advanced=true模型及其子模型都被排除在映射之外):
如何参数化showAdvanced条件并使用单个CreateMap定义实现相同的结果?我已经搜索了很多正确的解决方案,尝试使用ResolveUsing、CustomResolver,但都没有结果。您可以使用自定义转换器,如下所示,您可以自定义映射设置 创建一个convert类
internal class AccountConverter : TypeConverter<PD.IAccount, OD.IAccount>
{
protected override OD.IAccount ConvertCore(PD.IAccount source)
{
var result = new Account()
{
CustomerNumber = source.CustomerNumber,
EAccount = source.EAccount,
EmailAddress = source.EmailAddress
};
return result;
}
}
内部类AccountConverter:TypeConverter
{
受保护的覆盖OD.IAccount ConvertCore(PD.IAccount源)
{
var结果=新帐户()
{
CustomerNumber=source.CustomerNumber,
EAccount=source.EAccount,
EmailAddress=source.EmailAddress
};
返回结果;
}
}
然后像这样添加映射
Mapper.CreateMap<PD.IAccount, OD.IAccount>()
.ConvertUsing(new AccountConverter());
Mapper.CreateMap()
.ConvertUsing(新AccountConverter());
您希望使用不属于对象的外部参数来控制逻辑。我相信最好的方法是使用一个映射,并根据您的标志过滤输入对象。像这样的
var blockGroupsTemp;
如果(显示高级)
blockGroupsTemp=blockGroups;
其他的
{
blockGroupsTemp=blockGroups.Where(x=>x.Advanced==false.ToList();
blockGroupsTemp.ForEach(s=>s.ChildGroups.RemoveAll(y=>y.Advanced==true));
}
var mappedViewModels=Mapper.Map(blockGroupsTemp)代码>您可以使用上下文选项项
集合在运行时将值传递给映射函数:
var showAdvanced = true;
var mappedViewModels = Mapper.Map<ObservableCollection<ItemFilterBlockGroupViewModel>>(
blockGroups,
options => options.Items["includeAdvanced"] = showAdvanced);
如果使用弱类型字典值来传递标志参数对您来说不太合适,我建议将此逻辑封装在两个单独的方法中,如示例所示。这只会过滤根对象的子对象-我需要过滤每个级别的子对象,这就是我问题中的第二个示例CreateMap所做的。我的重点是对源对象进行过滤,而不是使用映射器。我用一个过滤子组的选项更新了答案。你的答案仍然只过滤一个级别的子组-层次结构可能是无限深的。我希望做的是避免手动进行这种模型操作,因为AutoMaper显然能够做到这一点,因为我问题中的第二个CreateMap语句就是这样做的。好的,我看到了您尝试使用AutoMaper进行递归的方式。您是否尝试过像这里这样的配置映射,这如何帮助我在运行时有条件地映射?我需要一个单独的映射,它可以根据输入参数(我的问题示例中的showAdvanced布尔值)的不同表现。您可以在“ItemFilterBlockGroup”类中添加一个this show Advanced,该类是automapper中的源对象,然后您可以在“ConvertCore”中添加一个if条件方法,并检查其是否为真,否则执行此操作。这有意义吗。内部类AccountConverter:TypeConverter{受保护的重写OD.IAccount ConvertCore(PD.IAccount源){if(source.showAdvanced)…那么你是说我用只与我的观点相关的数据污染了我的对象模型?这不是我愿意做的事。还有一种方法可以改变automapper,但也不是很优雅,就像下面给出的那样。如果这对你来说也不起作用,那么就没有更干净的方法了在automapper中,您需要有一个条件映射,如上面的“XtremeBytes”所发布的。--bool showAdvanced=false;var tt=Mapper.Map(a1,e=>e.AfterMap((a,b)=>b.Name=showAdvanced?:a.Name));---这看起来更符合我的想法-但是我在理解如何构造视图模型时遇到了一些困难。因为视图模型是映射的同一类型,我不能在ConstructUsing调用中使用Mapper.Map。AutoMaper似乎正常地处理这种递归,但它似乎是使用ConstructUsing我将失去这个功能。在这一点上,我可能根本不使用AutoMapper,而只是编写一个递归方法来进行映射。我真正想做的是这样的:Mapper.CreateMap().ForMember(dest=>dest.ChildGroups,opts=>opts.MapFrom(from=>(bool)context.Options.Items[“showAdvanced”]?from.ChildGroups:from.ChildGroups.Where(c=>c.Advanced==false))
但我认为无法从FormMember中访问选项。Items。@XVar,是的,我正在考虑它。尝试更新版本的地图创建代码
internal class AccountConverter : TypeConverter<PD.IAccount, OD.IAccount>
{
protected override OD.IAccount ConvertCore(PD.IAccount source)
{
var result = new Account()
{
CustomerNumber = source.CustomerNumber,
EAccount = source.EAccount,
EmailAddress = source.EmailAddress
};
return result;
}
}
Mapper.CreateMap<PD.IAccount, OD.IAccount>()
.ConvertUsing(new AccountConverter());
var showAdvanced = true;
var mappedViewModels = Mapper.Map<ObservableCollection<ItemFilterBlockGroupViewModel>>(
blockGroups,
options => options.Items["includeAdvanced"] = showAdvanced);
Mapper.CreateMap<ItemFilterBlockGroup, ItemFilterBlockGroupViewModel>()
.ForMember(destination => destination.ChildGroups, options => options.ResolveUsing(
(resolution) =>
{
var includeAdvanced = (bool)resolution.Context.Options.Items["includeAdvanced"];
var source = (ItemFilterBlockGroup)resolution.Context.SourceValue;
if(includeAdvanced)
return source.ChildGroups;
else
return source.ChildGroups.Where(c => c.Advanced == false);
}));