【问题标题】:Can AutoMapper implicitly flatten this mapping?AutoMapper 可以隐式地展平这个映射吗?
【发布时间】:2012-11-13 13:46:26
【问题描述】:

我正在尝试在两个对象列表之间进行映射。源类型具有A 类型的复杂属性;目标类型是A 类型的扁平子集加上源类型中的附加标量属性。

public class A
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class Source
{
    public A MyA { get; set; }
    public int SomeOtherValue { get; set; }
}

public class Destination
{
    public string Name { get; set; }
    public int SomeOtherValue { get; set; }
}

如果不清楚,我希望 Source.MyA.Name 映射到 Destination.NameSource.SomeOtherValue 映射到 Destination.SomeOtherValue

实际上,A 类型有十几个属性,其中大约 80% 映射到 Destination 中的同名属性。如果我像这样明确地拼出CreateMap 中的映射,我可以让事情正常工作:

CreateMap<Source, Destination>()
    .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.MyA.Name));

这里的缺点是我想避免为每个需要复制到DestinationA 属性添加ForMember 行。我希望我能做这样的事情:

CreateMap<Source, Destination>()
    .ForMember(dest => dest, opt => opt.MapFrom(src => src.MyA));

但是,如果我尝试上述操作,我会在注册映射时收到运行时错误:“只有类型上的顶级个人成员才支持成员的自定义配置。”

谢谢

【问题讨论】:

    标签: automapper


    【解决方案1】:

    ADestination 以及SourceDestination 之间创建映射,然后使用AfterMap() 在第二个中使用第一个映射

    Mapper.CreateMap<A, Destination>();
    Mapper.CreateMap<Source, Destination>()
          .AfterMap((s, d) => Mapper.Map<A, Destination>(s.MyA, d));
    

    然后像这样使用它:

    var res = Mapper.Map<Source, Destination>(new Source { SomeOtherValue = 7,  MyA = new A { Id = 1, Name = "SomeName" } });
    

    【讨论】:

    • 这个解决方案的一个问题是 Mapper.AssertConfigurationIsValid() 会失败。
    【解决方案2】:

    作为一种解决方法,您可以在目标类型中使用带有附加属性的自定义类型转换器以避免递归。

    [TestFixture]
    public class MapComplexType
    {
        [Test]
        public void Map()
        {
            Mapper.CreateMap<A, Destination>();
    
            Mapper.CreateMap<Source, Destination>().ConvertUsing(new TypeConvertor());
            var source = new Source
                             {
                                 MyA = new A
                                           {
                                               Name = "Name"
                                           },
                                           SomeOtherValue = 5
                             };
            var dest = new Destination();
            Mapper.Map(source, dest);
            Assert.AreEqual(dest.Name, "Name");
        }
    }
    
    public class TypeConvertor : ITypeConverter<Source, Destination>
    {
        public Destination Convert(ResolutionContext context)
        {
            var destination = (Destination) context.DestinationValue;
            if (!((Destination)context.DestinationValue).IsMapped || destination == null)
            {
                destination = destination ?? new Destination();
                destination.IsMapped = true; // To avoid recursion
                Mapper.Map((Source)context.SourceValue, destination);
                                destination.IsMapped = false; // If you want to map the same object few times
            }
            Mapper.Map(((Source)context.SourceValue).MyA, destination);
            return (Destination)context.DestinationValue;
        }
    }
    
    public class A
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
    public class Source
    {
        public A MyA { get; set; }
        public int SomeOtherValue { get; set; }
    }
    
    public class Destination
    {
        public string Name { get; set; }
        public int SomeOtherValue { get; set; }
        // Used only for mapping purposes
        internal bool IsMapped { get; set; }
    }
    

    【讨论】:

      【解决方案3】:

      试试这个,

      Mapper.CreateMap<A, Destination>();
      Mapper.CreateMap<Source, Destination>()
          .ForMember(destination => destination.Name, options => options.MapFrom(source => Mapper.Map<A, Destination>(source.MyA).Name));
      
      var objSource = new Source { SomeOtherValue = 7, MyA = new A { Id = 1, Name = "SomeName" } };
      var result = Mapper.Map<Source, Destination>(objSource);
      

      【讨论】:

      • 这个答案与问题中的解决方案有何不同?您的解决方案不需要来自 MyA 的多个 .ForMember 调用,而这是问题试图避免的?
      猜你喜欢
      • 1970-01-01
      • 2011-01-05
      • 2011-07-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多