简体   繁体   English

Automapper - 多对象源和一个目标

[英]Automapper - Multi object source and one destination

I am using auto mapper to map multiple objects (db class into ui objects).我正在使用自动映射器来映射多个对象(db 类到 ui 对象)。

Map 1:地图1:

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

Map 2:地图2:

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

destination d = new destination();

//Map 1 //地图1

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

//Map 2 //地图2

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

Once I make call to the 'Map 2', the values that are populated using Map 1 are lost.. (ie destination.one is becoming empty).一旦我调用“地图 2”,使用地图 1 填充的值就会丢失..(即destination.one 变为空)。 How do I fix this?我该如何解决?

Map has an overload that takes a source and destination object: Map有一个带有源和目标对象的重载:

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

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

with the accepted answer as extension-methods, simple and general version:将接受的答案作为扩展方法,简单和通用版本:

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

after configuring mapping for each input-type:为每个输入类型配置映射后:

IMapper mapper = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Person, PersonCar>();
    cfg.CreateMap<Car, PersonCar>();
}).CreateMapper();
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);

According to me you should avoid calling the overloaded Map method taking an instance of the destination object as explained in the accepted answer.根据我的说法,您应该避免调用重载的 Map 方法来获取目标对象的实例,如已接受的答案中所述。 This won't let you test/validate your mapping configuration ( Mapper.Configuration.AssertConfigurationIsValid() ) or to do so you will add a lot of 'Ignore' in your mappings.这不会让您测试/验证您的映射配置( Mapper.Configuration.AssertConfigurationIsValid() ),否则您将在映射中添加很多“忽略”。

A very simple solution is to create a composite type holding source references and define your mapping to the destination based on that composite type.一个非常简单的解决方案是创建一个包含源引用的复合类型,并根据该复合类型定义到目标的映射。

Something like:就像是:

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

现在看起来是这样的:

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

Just wanted to add, that these days you can make use of tuple syntax to define mapping from multiple types.只是想补充一点,现在您可以使用元组语法来定义多种类型的映射。

// configuring
Mapper
  .CreateMap<(SourceType1 Source1, SourceType2 Source2), DestinationType>()
    .ForMember(sss => sss.one, m => m.MapFrom(source => source.Source1.abc))
    .ForMember(sss => sss.two, m => m.MapFrom(source => source.Source2.xyz));

// using
var result = Mapper.Map<DestinationType>((source1, source2));

Pros:优点:

  • don't have to remember to map from the second type after mapping from the first从第一种映射后不必记住从第二种映射
  • all mapping is defined at once and in one place (as long as you don't need separate mappings as well as a combined one)所有映射都是一次在一个地方定义的(只要您不需要单独的映射以及组合的映射)
  • less of a clumber when mapping from more than 2 source types从 2 种以上的源类型映射时不那么麻烦
  • essentially the @asidis's idea, but does not require a separate type本质上是@asidis 的想法,但不需要单独的类型

Cons:缺点:

  • well, as with Automapper in general, you have to know where to look, to find out what types to use for mapping好吧,与一般的 Automapper 一样,您必须知道在哪里查找,以找出用于映射的类型
  • may look be a bit unwieldy when a number of types is involved当涉及多种类型时,可能看起来有点笨拙

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM