【问题标题】:How to get both mapped source and destination member to create a custom mapping in AutoMapper?如何获取映射的源成员和目标成员以在 AutoMapper 中创建自定义映射?
【发布时间】:2016-02-11 09:13:24
【问题描述】:

例如,假设我需要映射这些类:

public class Dto 
{
     public List<string> Items { get; set; } = new List<string> { "orange", "apple" }
}

public class DomainObject
{
     public List<string> Items { get; set; }
}

...我想使用 AutoMapper 配置一个自定义映射,它在执行一些必须同时存在 DtoDomainObject 的操作后返回 DomainObject,或者至少我应该能够得到源Items 和目标Items

为什么我需要这个?

因为我正在将 DTO 映射到跟踪更改的对象,并且我需要提供一种自定义方法来映射集合,以免在映射操作之前丢失跟踪信息。

目前,我已经使用扩展方法在代码中实现了整个集合映射,但我想将此扩展方法称为 AutoMapper 配置的一部分,以使代码尽可能简单并保持 DRY。

可能的部分解决方案

我发现 AutoMapper 有以下IMappingExpression&lt;TSource, TDestination&gt; 方法:

IMappingExpression<TSource, TDestination> AfterMap(Action<TSource, TDestination> afterFunction); 

虽然这解决了我 90% 的问题,但仍然存在问题。 AfterMap 没有给出当前IMapper 的实例。我不再使用静态 Mapper,但我在 Castle Windsor 上为 IMapper 配置了一个自定义工厂,所以我可以在任何地方注入它。

我还需要一个当前IMapper 的实例。我可以解决IMapper a la Service Locator 反模式,但我想知道 AutoMapper 是否还有另一种方法来完成 AfterMap 已经做的事情,也许它可以提供当前IMapper 某种方式...

【问题讨论】:

    标签: c# .net automapper dto


    【解决方案1】:

    在映射配置期间使用AfterMap 不是 100% 令人满意的解决方案

    这是我的实际场景:

    mapperConfig.CreateMap<CustomerUpdateDto, Customer>()
                    .ForMember(c => c.Locations, m => m.Ignore())
                    .ForMember(c => c.Aliases, opts => opts.Ignore())
                    .ForMember(c => c.Contacts, opts => opts.Ignore())
                    .ForMember(c => c.Activities, opts => opts.Ignore())
                    .AfterMap
                    (
                        (dto, customer) =>
                        {
                            // AHHH! Dependency injection, please ;)
                            IMapper mapper = Container.Current.Resolve<IMapper>();
    
                            dto.Aliases.MapTo<ISet<CustomerAlias>, ISet<CustomerAlias>, CustomerAlias>(customer.Aliases, mapper);
                            dto.Activities.MapTo<ISet<Activity>, ISet<Activity>, Activity>(customer.Activities, mapper);
                            dto.Locations.MapTo<ISet<Location>, ISet<Location>, Location>(customer.Locations, mapper);
                        }
                    )
                    .ForAllMembers(options => options.Condition(src => !src.IsSourceValueNull));
    

    MapTo 是一种自定义扩展方法,它概括了一种解决方案,以避免创建整个集合的新实例而不是能够将每个集合项从源对象映射到目标对象的默认 AutoMapper 行为:

    public static class CollectionMappingExtensions
    {
        public static void MapTo<TSource, TTarget, TItem>(this TSource source, TTarget target, IMapper mapper)
            where TSource : ICollection<TItem>
            where TTarget : ICollection<TItem>
        {
            foreach (TItem item in source)
            {
                TItem targetItem = target.SingleOrDefault(someItem => someItem.Equals(someItem));
    
                if (targetItem == null)
                    target.Add(item);
                else
                    mapper.Map(item, targetItem);
            }
        }
    }
    

    顺便说一句,如果我能避免使用静态服务定位器而不是依赖注入来获取IMapper,那就太好了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多