【问题标题】:Automapper - Multi object source and one destinationAutomapper - 多对象源和一个目标
【发布时间】:2013-11-01 20:58:06
【问题描述】:

我正在使用自动映射器来映射多个对象(db 类到 ui 对象)。

地图 1:

Mapper.CreateMap<sourceone, destination>().ForMember(sss => sss.one, m => m.MapFrom(source => source.abc));

地图2:

Mapper.CreateMap<sourcetwo, destination>().ForMember(sss => sss.two, m => m.MapFrom(source => source.xyz));

destination d = new destination();

//地图1

d = AutoMapper.Mapper.Map<sourceone, destination>(sourceone);

//地图2

d = AutoMapper.Mapper.Map<sourcetwo, destination>(sourcetwo);

一旦我调用“地图 2”,使用地图 1 填充的值就会丢失..(即destination.one 变为空)。我该如何解决这个问题?

【问题讨论】:

    标签: c# asp.net-mvc automapper


    【解决方案1】:

    现在看起来是这样的:

    DestinationDto = _mapper.Map(source2, _mapper.Map<source1type, destinationType>(source1));
    

    【讨论】:

    • 这真的很有帮助!谢谢你。我正沿着一条看起来像是一场维修噩梦等待发生的道路前进。我有: (myObject1, myObject2) => { var _combinedObject = _mapper.Map(myObject2); _combinedObject.someProperty = myObject1.SomeProperty; _combinedObject.anotherProperty= myObject1.AnotherProperty;返回 _combinedObject ; }) .ToList();现在它更短更容易阅读 IMO: (myObject1, myObject2) => { return _mapper.Map(myObject2, _mapper.Map(myObject1)); }) .ToList();
    【解决方案2】:

    根据我的说法,您应该避免调用重载的 Map 方法来获取目标对象的实例,如已接受的答案中所述。这不会让您测试/验证您的映射配置 (Mapper.Configuration.AssertConfigurationIsValid()),否则您将在映射中添加很多“忽略”。

    一个非常简单的解决方案是创建一个包含源引用的复合类型,并根据该复合类型定义到目标的映射。

    类似:

        public class SourceOneTwo
        {
            public SourceOne SourceOne { get; set; }
            public SourceTwo SourceTwo { get; set; }
        }
        static void Main(string[] args)
        {
            var config = new MapperConfiguration(cfg => 
                cfg.CreateMap<SourceOneTwo, Destination>()
                .ForMember(dest => dest.one, m => m.MapFrom(source => source.SourceOne.abc))
                .ForMember(dest => dest.two, m => m.MapFrom(source => source.SourceTwo.xyz)));
            config.AssertConfigurationIsValid();
        }
    

    【讨论】:

    • 这看起来很干净
    【解决方案3】:
    mapper.MergeInto<PersonCar>(person, car)
    

    接受的答案是扩展方法,简单和通用的版本:

    public static TResult MergeInto<TResult>(this IMapper mapper, object item1, object item2)
    {
        return mapper.Map(item2, mapper.Map<TResult>(item1));
    }
    
    public static TResult MergeInto<TResult>(this IMapper mapper, params object[] objects)
    {
        var res = mapper.Map<TResult>(objects.First());
        return objects.Skip(1).Aggregate(res, (r, obj) => mapper.Map(obj, r));
    }
    

    为每个输入类型配置映射后:

    IMapper mapper = new MapperConfiguration(cfg =>
    {
        cfg.CreateMap<Person, PersonCar>();
        cfg.CreateMap<Car, PersonCar>();
    }).CreateMapper();
    

    【讨论】:

    • 重用性是关键!
    • 我今天需要这样的东西,它的简洁性是如此的优雅,谢谢!
    • 谢谢!这应该是选定的答案!
    • 很好的解决方案。它在 .net 核心中也能完美运行。
    • 不错的解决方案兄弟!
    【解决方案4】:
    public class Person
    {
        public string Name { get; set; }
        public string PhNo { get; set; }
    }
    public class Company
    {
        public int EmpNo { get; set; }
        public string Title { get; set; }
    }
    
    public class PersonCompany
    {
        public string Name { get; set; }
        public string PhNo { get; set; }
    
        public int EmpNo { get; set; }
        public string Title { get; set; }
    }
    
    //you can test as below
            var pMap = Mapper.CreateMap<Person,PersonCompany>();
            pMap.ForAllMembers(d => d.Ignore()); 
            pMap.ForMember(d => d.Name, opt => opt.MapFrom(s => s.Name))
                .ForMember(d => d.PhNo, opt => opt.MapFrom(s => s.PhNo));
    
            var cMap = Mapper.CreateMap<Company, PersonCompany>();
            cMap.ForAllMembers(d => d.Ignore());
            cMap.ForMember(d => d.EmpNo, opt => opt.MapFrom(s => s.EmpNo))
                .ForMember(d => d.Title, opt => opt.MapFrom(s => s.Title));
    
    
            var person = new Person { Name = "PersonName", PhNo = "212-000-0000" };
            var personCompany = Mapper.Map<Person,PersonCompany>(person);
            var company = new Company { Title = "Associate Director", EmpNo = 10001 };
            personCompany = Mapper.Map(company, personCompany);
    
            Console.WriteLine("personCompany.Name={0}", personCompany.Name);
            Console.WriteLine("personCompany.PhNo={0}", personCompany.PhNo);
            Console.WriteLine("personCompany.EmpNo={0}", personCompany.EmpNo);
            Console.WriteLine("personCompany.Title={0}", personCompany.Title);
    

    【讨论】:

      【解决方案5】:

      Map 有一个接受源对象和目标对象的重载:

      d = AutoMapper.Mapper.Map<sourceone, destination>(sourceone);
      
      /* Pass the created destination to the second map call: */
      AutoMapper.Mapper.Map<sourcetwo, destination>(sourcetwo, d);
      

      【讨论】:

      • 这很丑陋和令人困惑,API 应该清楚地包含一个 Map(params) 方法
      • @Flip:我可能误解了你的意思,但它确实包含一个Map&lt;T&gt;(params) 方法,它只是返回一个新的T
      • 这不再在较新的 AutoMappers 上编译,但同样的原则适用:使用 mapper 的实例而不是静态方法。
      猜你喜欢
      • 2021-02-22
      • 2017-06-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-28
      • 2012-07-18
      相关资源
      最近更新 更多