Programing

AutoMapper는 여러 소스에서 변환

lottogame 2020. 12. 12. 09:57
반응형

AutoMapper는 여러 소스에서 변환


두 개의 모델 클래스가 있다고 가정 해 보겠습니다.

public class People {
   public string FirstName {get;set;}
   public string LastName {get;set;}
}

또한 수업 전화 :

public class Phone {
   public string Number {get;set;}
}

그리고 다음과 같이 PeoplePhoneD로 변환하고 싶습니다.

public class PeoplePhoneDto {
    public string FirstName {get;set;}
    public string LastName {get;set;}
    public string PhoneNumber {get;set;}
}

내 컨트롤러에서 내가 가지고 있다고 가정 해 봅시다.

var people = repository.GetPeople(1);
var phone = repository.GetPhone(4);

// normally, without automapper I would made
return new PeoplePhoneDto(people, phone) ;

이 시나리오에 대한 예를 찾을 수없는 것 같습니다. 이것이 가능한가 ?

참고 :이 질문에 대한 예제는 실제가 아닙니다.


여러 소스를 단일 대상에 직접 매핑 할 수 없습니다 . Andrew Whitaker 답변에 설명 된대로지도를 하나씩 적용해야합니다 . 따라서 모든 매핑을 정의해야합니다.

Mapper.CreateMap<People, PeoplePhoneDto>();
Mapper.CreateMap<Phone, PeoplePhoneDto>()
        .ForMember(d => d.PhoneNumber, a => a.MapFrom(s => s.Number));

그런 다음 이러한 매핑 중 하나를 사용하여 대상 개체를 만들고 생성 된 개체에 다른 매핑을 적용합니다. 이 단계는 매우 간단한 확장 방법으로 단순화 할 수 있습니다.

public static TDestination Map<TSource, TDestination>(
    this TDestination destination, TSource source)
{
    return Mapper.Map(source, destination);
}

사용법은 매우 간단합니다.

var dto = Mapper.Map<PeoplePhoneDto>(people)
                .Map(phone);

Tuple이것을 위해 사용할 수 있습니다 .

Mapper.CreateMap<Tuple<People, Phone>, PeoplePhoneDto>()
    .ForMember(d => d.FirstName, opt => opt.MapFrom(s => s.Item1.FirstName))
    .ForMember(d => d.LastName, opt => opt.MapFrom(s => s.Item1.LastName))
    .ForMember(d => d.Number, opt => opt.MapFrom(s => s.Item2.Number ));

더 많은 소스 모델이있는 경우 다른 표현 (목록, 사전 또는 기타)을 사용하여 이러한 모든 모델을 소스로 모을 수 있습니다.

위의 코드는 일부 AutoMapperConfiguration 파일에 배치하고 한 번 전체적으로 설정 한 다음 적용 가능한 경우 사용하는 것이 좋습니다.

AutoMapper는 기본적으로 단일 데이터 소스 만 지원합니다. 예를 들어 두 소스 모델에 동일한 이름의 속성이있는 경우 어떻게 알 수 있기 때문에 여러 소스를 직접 설정할 가능성이 없습니다 (컬렉션으로 묶지 않고).

이를 달성하기위한 몇 가지 해결 방법이 있습니다.

public static class EntityMapper
{
    public static T Map<T>(params object[] sources) where T : class
    {
        if (!sources.Any())
        {
            return default(T);
        }

        var initialSource = sources[0];

        var mappingResult = Map<T>(initialSource);

        // Now map the remaining source objects
        if (sources.Count() > 1)
        {
            Map(mappingResult, sources.Skip(1).ToArray());
        }

        return mappingResult;
    }

    private static void Map(object destination, params object[] sources)
    {
        if (!sources.Any())
        {
            return;
        }

        var destinationType = destination.GetType();

        foreach (var source in sources)
        {
            var sourceType = source.GetType();
            Mapper.Map(source, destination, sourceType, destinationType);
        }
    }

    private static T Map<T>(object source) where T : class
    {
        var destinationType = typeof(T);
        var sourceType = source.GetType();

        var mappingResult = Mapper.Map(source, sourceType, destinationType);

        return mappingResult as T;
    }
}

그리고:

var peoplePhoneDto = EntityMapper.Map<PeoplePhoneDto>(people, phone);

But to be quite honest, even though I am using AutoMapper for already a few years I have never had a need to use mapping from multiple sources. In cases when for example I needed multiple business models in my single view model I simply embedded these models within the view model class.

So in your case it would look like this:

public class PeoplePhoneDto {
    public People People { get; set; }
    public Phone Phone { get; set; }
}

If you have a scenario when destination type should be mapped from one of sources and you want to use linq projections, you can do following.

    Mapper.CreateMap<People, PeoplePhoneDto>(MemberList.Source);
    Mapper.CreateMap<Phone, PeoplePhoneDto>(MemberList.Source)
          .ForMember(d => d.PhoneNumber, a => a.MapFrom(s => s.Number));

    CreateMap<PeoplePhoneDto,(People,Phone)>(MemberList.Destination)
           .ForMember(x => x.Item1, opts => opts.MapFrom(x => x))
           .ForMember(x => x.Item2, opts => opts.MapFrom(x => x.PhoneNumber))
           .ReverseMap();

I needed this mostly for cross apply queries like this.

       var dbQuery =
          from p in _context.People
          from ph in _context.Phones
             .Where(x => ...).Take(1)
          select ValueTuple.Create(p, ph);
       var list = await dbQuery
          .ProjectTo<PeoplePhoneDto>(_mapper.ConfigurationProvider)
          .ToListAsync();

참고URL : https://stackoverflow.com/questions/21413273/automapper-convert-from-multiple-sources

반응형