自动映射器-多对象源和一个目标


70

我正在使用自动映射器来映射多个对象(将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变为空)。我该如何解决?

Answers:


89

Map 有一个采用源对象和目标对象的重载:

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

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

15
这是难看和混淆,该API应明确包括一个地图<T>(PARAMS)方法
菲利普

1
@Flip:我可能会误解您的意思,但是它确实包含一个Map<T>(params)方法,只是返回一个new T
Andrew Whitaker

@Filip听起来像是一个简单的扩展,如果您更喜欢API的外观,则可以添加该扩展
Sonic Soul

这不再在较新的AutoMappers上编译,而是应用相同的原理:使用mapper的实例而不是静态方法。
Jeramy Rutley

45
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();

可重用性是关键!
Chase Florell's

今天我需要这样的东西,简单到如此优雅,谢谢!
PmanAce

谢谢!这应该是选定的答案!
FoundNil

很好的解决方案。它也可以在.net内核中完美运行。
约翰·普拉多

9
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);

4

根据我的看法,您应该避免像接受的答案中所述使用目标对象的实例调用重载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();
    }

这看起来像一个干净的方法
liang

2

如今看起来像这样:

DestinationDto = _mapper.Map(source2, _mapper.Map<source1type, destinationType>(source1));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.