使用automapper反规范化对象层次结构

时间:2015-05-05 09:39:36

标签: c# automapper automapper-3

我知道有些问题类似于这个问题,但据我所知(并且测试),所提供的解决方案似乎都不合适,所以这里就是这样。

我想知道是否可以展平/非规范化对象层次结构,以便使用AutoMapper将具有嵌套属性列表的实例映射到某个目标类型的列表。

我有一个看起来像

的源类

来源:

public class DistributionInformation
{
   public string Streetname;
   public RouteInformation[] Routes;
}

public class RouteInformation
{
   public int RouteNumber;
   public string RouteDescription;
}

目的地:

public class DenormDistributionInfo
{
   public string Streetname;
   public int RouteNumber;
   public string RouteDescription;
}

所以我想将两个源映射到非规范化目标DenormDistributionInfo的列表。

I.e:

IEnumerable<DenormDistributionInfo> result = Mapper.Map(distributionInformationInstance);

使用AutoMapper是可行/可行的,还是应该“手动”放弃并反规范化?

2 个答案:

答案 0 :(得分:4)

主要的是你要避免不得不向上看&#34;映射中的数据并非隐含在源中。 &#34;魔法&#34;映射会导致严重的维护问题。

然而,从概念上讲,这种映射非常简单。唯一复杂的因素是您需要两个源对象($query->execute(array(":doc_id" => $doc_id)); DistributionInformation)才能构建目标对象。如果您遵循这一思路,我们可以创建一个非神奇的映射,明确保留我们的意图 - 这是我如何做到的: -

RouteInformation

并调用它: -

// We need both source objects in order to perform our map
Mapper.CreateMap<Tuple<DistributionInformation, RouteInformation>, DenormDistributionInfo>()
      .ForMember(d => d.Streetname, o => o.MapFrom(s => s.Item1.Streetname))
      .ForMember(d => d.RouteDescription, o => o.MapFrom(s => s.Item2.RouteDescription))
      .ForMember(d => d.RouteNumber, o => o.MapFrom(s  => s.Item2.RouteNumber));

// We can use ConstructUsing to pass both our source objects to our map
Mapper.CreateMap<DistributionInformation, IEnumerable<DenormDistributionInfo>>()
      .ConstructUsing(
          x => x.Routes
                .Select(y => Mapper.Map<DenormDistributionInfo>(Tuple.Create(x, y)))
                .ToList());

如果您愿意,可以通过创建DTO来保存两个源对象,从而避免一些Tuple恐怖。如果您的真实代码甚至比您在问题中提供的示例更为复杂,我特别强烈推荐这一点。

是否使用AutoMapper执行此映射或多或少比手动执行操作要由您决定。在这种情况下,我不会觉得我很烦,但是在一个更常见的情况下经常重复,我可能会考虑它。

答案 1 :(得分:0)

我挖了一下,虽然我选择通过“手动”映射来解决问题 还有另外一种方式(除了Iain发布的答案。但它确实感觉相当hacky。

想法是使用类型转换器并将其映射两次

    public class DistributionInfoConverter : ITypeConverter<DistributionInformation, IEnumerable<DenormDistributionInfo>>
    {
        public IEnumerable<DenormDistributionInfo> Convert(ResolutionContext context)
        {
            var result = new List<DenormDistributionInfo>();
            var source = (DistributionInformation)context.SourceValue;

            foreach (var routeDetail in source.Routes)
            {
                var model = new DenormDistributionInfo();
                Mapper.Map(routeDetail, model);
                Mapper.Map(source, model);
                result.Add(model);
            }

            return result;
        }
    }

    Mapper.CreateMap<RouteInformation, DenormDistributionInfo>();
    Mapper.CreateMap<DistributionInformation, DenormDistributionInfo>()
    Mapper.CreateMap<DistributionInformation, IEnumerable<DenormDistributionInfo>>().ConvertUsing<DistributionInfoConverter>();

唯一的问题是,对于DistributionInformation的集合,你必须循环/选择每个项目和地图,而不是让automapper找出如何将集合映射到像往常一样的集合。