AutoMapper : "나머지 무시"?


205

명시 적으로 매핑 된 속성을 제외한 모든 속성을 무시하도록 AutoMapper에 지시하는 방법이 있습니까?

외부에서 변경 될 수있는 외부 DTO 클래스가 있으며 새 속성을 추가하면 내 객체에 매핑하려고 할 때 기능 (예외 원인)이 손상되므로 명시 적으로 무시할 각 속성을 지정하지 마십시오.


1
ValueInjecter valueinjecter.codeplex.com/documentation 을 사용하면 매핑 알고리즘이 있고 특정 속성간에 매핑되는 ValueInjections 를 만들고 나머지 속성은 신경 쓰지 않습니다.
Omu

24
Automapper> 버전 5를 사용하는 사람들은 답을 자세히 보려면 ​​아래로 건너 뛰십시오.ForAllOtherMembers(opts => opts.Ignore())
Jack Ukleja

@Schneider ".ForAllOtherMembers (opts => opts.Ignore ())"는 여기서 "IgnoreAllNonExisting"확장자와 다릅니다. 여기서 가장 큰 차이점은 ".ForAllOtherMembers (opts => opts.Ignore ( )) "는 아무 것도 매핑하지 않습니다. config 속성없이 "IgnoreAllNonExisting"을 명시 적으로 사용하면 값이있는 일부 속성 (같은 이름의 속성)이 여전히 매핑됩니다.
Dragon

예. ForAllOtherMembers가 답입니다. 매핑되지 않은 멤버는 무시되므로 IgnoreUnmapped 응답은 config-valid-assert를 전달하는 것 외에는 아무 것도 수행하지 않습니다.
N73k

이 작업을 수행 할 때 매핑되는 클래스에서 관련성이 있거나 중요한 변경 사항을 명시 적으로 숨 깁니다. 모든 속성에 대해 명시 적으로 매핑하면 매핑 된 클래스가 변경 될 때마다 테스트가 중단되어 제대로 평가할 수 있습니다. ( AssertConfigurationIsValid()전화를 거는 시험을 받았으니) 이로 인해 "나머지 무시"는 반 패턴으로 간주합니다.
Arve Systad

답변:


83

이것은 내가 작성한 확장 방법으로 대상의 기존 속성이 아닌 모든 속성을 무시합니다. 질문이 2 세 이상이므로 여전히 유용한 지 확실하지 않지만 많은 수동 무시 호출을 추가 해야하는 동일한 문제가 발생했습니다.

public static IMappingExpression<TSource, TDestination> IgnoreAllNonExisting<TSource, TDestination>
(this IMappingExpression<TSource, TDestination> expression)
{
    var flags = BindingFlags.Public | BindingFlags.Instance;
    var sourceType = typeof (TSource);
    var destinationProperties = typeof (TDestination).GetProperties(flags);

    foreach (var property in destinationProperties)
    {
        if (sourceType.GetProperty(property.Name, flags) == null)
        {
            expression.ForMember(property.Name, opt => opt.Ignore());
        }
    }
    return expression;
}

용법:

Mapper.CreateMap<SourceType, DestinationType>()
                .IgnoreAllNonExisting();

업데이트 : 분명히 사용자 정의 매핑이 덮어 쓰기 때문에 올바르게 작동하지 않습니다. IgnoreAllNonExisting을 먼저 호출 한 다음 나중에 사용자 지정 매핑을 호출하면 여전히 작동 할 수 있다고 생각합니다.

schdr에는 (이 질문에 대한 답변으로) Mapper.GetAllTypeMaps()매핑되지 않은 속성을 찾고 자동으로 무시 하는 솔루션이 있습니다. 더 강력한 솔루션 인 것 같습니다.


나는 한동안 AutoMapper를 사용하지 않았지만 그것이 효과가 있다면 답을 받아 들일 것입니다 :).
Igor Brejc 2018 년

2
감사!! 나는 이것이 매우 편리하다는 것을 알았다. 속성을 개별적으로 무시하면 내 상황에서 automapper를 사용하는 목적을 무력화했습니다.
Daniel Robinson

덮어 쓰기 문제가없는 답변에 대해서는 다음 답변을 참조하십시오
Jason Coyne

3
이 메소드는 autoMapper 네이티브 코드에 있어야합니다! 아주 좋습니다 감사 해요!
Felipe Oriani

2
참고로, 지미 자신 (AutoMapper의 작가)은 @nazim의 답변이 버전 5 이상에
맞다고 언급했습니다.

244

내가 이해 한 바에 따르면 소스에 매핑 된 필드가없는 대상에 필드가 있으므로 매핑되지 않은 대상 필드를 무시하는 방법을 찾고 있습니다.

이러한 확장 방법을 구현하고 사용하는 대신 간단하게 사용할 수 있습니다.

Mapper.CreateMap<sourceModel, destinationModel>(MemberList.Source);  

이제 automapper는 모든 소스 필드가 맵핑되었지만 다른 방식으로 맵핑되지 않았 음을 검증해야한다는 것을 알고 있습니다.

다음을 사용할 수도 있습니다.

Mapper.CreateMap<sourceModel, destinationModel>(MemberList.Destination);  

10
이 답변에는 더 많은 의견이 있어야하며 답변으로 표시 될 수도 있습니다. 그것은 내 문제를 해결했고 비슷하게 MemberList.Destinationops 문제를 해결할 것입니다.
Tedd Hansen

1
소스와 대상의 속성을 거의 무시하지 않으려면 작동하지 않습니다. :)
RealWillyWoka

62
나중에 오는 사람에게이 5.0에 대한 정답
지미 Bogard

3
보기 좋지만 저에게는 효과가 없었습니다. 소스와 대상을 시도했지만 맵이없는 동일한 속성 개체에 대해 계속 불평합니다
Sonic Soul

1
6.0.2를 사용하면 작동하지 않습니다. 대상에서 소스로 매핑되지 않은 속성은 소스의 속성을 null과 0으로 덮어 씁니다. 또한 코드는 특히 팀에서 작업하는 경우 수행중인 작업에 대해 명확하지 않습니다. 나는 주로이 코드를 싫어 왜 내가 제안 대답 "IgnoreAllNonExisting"와 같은 선택 단어를 선호하는 이유의
sksallaj

222

기존지도를 덮어 쓰지 않도록 Can Gencer의 확장 프로그램을 업데이트했습니다.

public static IMappingExpression<TSource, TDestination> 
    IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
    var sourceType = typeof (TSource);
    var destinationType = typeof (TDestination);
    var existingMaps = Mapper.GetAllTypeMaps().First(x => x.SourceType.Equals(sourceType) && x.DestinationType.Equals(destinationType));
    foreach (var property in existingMaps.GetUnmappedPropertyNames())
    {
        expression.ForMember(property, opt => opt.Ignore());
    }
    return expression;
}

용법:

Mapper.CreateMap<SourceType, DestinationType>()
                .ForMember(prop => x.Property, opt => opt.MapFrom(src => src.OtherProperty))
                .IgnoreAllNonExisting();

4
이 솔루션을 게시 해 주셔서 감사합니다. goo.gl/rG7SL 에서 솔루션을 사용할 때이 게시물을 다시 우연히 발견 할 때까지 이상한 버그를 파악하는 데 몇 시간이 걸렸 습니다.
Nordin

3
아래에 Yohanb의 방법을 권장합니다. 이것이 작동하지 않는 경우가 있습니다.
Jon Barker

3
AutoMapper 4.2에서이 작업을 수행 할 수 있습니까? (더 Mapper.GetAllTypeMaps()이상 사용되지 않음)
mrmashal

14
AutoMapper 5+ 버전 그냥 교체 Mapper.GetAllTypeMaps()와 함께 Mapper.Configuration.GetAllTypeMaps(). 다음은 참조 github.com/AutoMapper/AutoMapper/issues/1252
Sergey G.

5
이것을 읽는 새로운 사람들을 위해. 이 답변은 AutoMapper 2에 대한 것이며이 의견을 작성할 때 우리는 버전 6에 있습니다. 이것은 해킹이며 훨씬 더 깨끗한 방법은 MemberList 열거 형을 사용하는 것입니다. Github 이슈 1839와 더 나은 솔루션을 참조하십시오. github.com/AutoMapper/AutoMapper/issues/1839 예 : stackoverflow.com/a/31182390/3850405
Ogglas

83

나는 다음과 같은 방법으로 이것을 할 수 있었다.

Mapper.CreateMap<SourceType, DestinationType>().ForAllMembers(opt => opt.Ignore());
Mapper.CreateMap<SourceType, DestinationType>().ForMember(/*Do explicit mapping 1 here*/);
Mapper.CreateMap<SourceType, DestinationType>().ForMember(/*Do explicit mapping 2 here*/);
...

참고 : AutoMapper v.2.0을 사용하고 있습니다.


4
정말 고맙습니다! 그것은 매력처럼 작동합니다. 난 그냥 무효 :(를 돌려 체인에 먼저 호출하지만 ForAllMembers을 시도 선행 IgnoreAll 나중에 수정 될 수 있음이 명백하지 않았다..
SeriousM

5
나도 이런 식으로 마음에 들지 않습니다. 50 명의 회원이 있고 25 명의 회원을 무시하고 싶을 경우 25 명의 회원을 무시해야한다면 자동 매퍼의 요점은 무엇입니까? 이름이 일치하고 일치하지 않는 속성이있는 경우 매핑되지 않은 속성과 일치하지 않고 모든 입력을 전달하여 automapper에 알리는 것이 왜 명확하지 않습니까?
sksallaj

71

AutoMapper의 버전 5.0.0-beta-1에는 ForAllOtherMembers확장 방법이 도입되어 이제는 다음을 수행 할 수 있습니다.

CreateMap<Source, Destination>()
    .ForMember(d => d.Text, o => o.MapFrom(s => s.Name))
    .ForMember(d => d.Value, o => o.MapFrom(s => s.Id))
    .ForAllOtherMembers(opts => opts.Ignore());

속성 매핑을 잊었을 때 발생하는 자동 실패 매핑 문제는 발생하지 않으므로 각 속성을 명시 적으로 매핑하는 이점이 있습니다.

아마도 귀하의 경우에는 다른 모든 멤버를 무시 TODO하고이 클래스에 대한 변경 빈도가 정해진 후 되돌아 와서이를 명시 하는 것이 현명 할 수 있습니다 .


3
버전 5까지는 놀라운 일이었습니다. Automapper의 거버넌스에 어떤 문제가 있습니까?
Jack Ukleja

이것에 감사합니다. 아래로 스크롤하는 데 잠시 시간이 걸렸지 만 완벽하게 작동합니다.
cobolstinks

2
ForAllOtherMembers 줄을 먼저 넣을 수도 있고 같은 방식으로 작동하므로 일종의 기본 클래스 구성이 있으면 좋습니다.
N73k

이것이 선호되는 접근법입니다. OP가 허용 된 답변을 변경할 수 있는지 궁금하십니까?
체이스 플 로렐

1
소스 객체의 속성을 무시하는 것과 동등한 것이 있습니까? 같은 것 ForAllOtherSourceMembers?
SuperJMN

44

AutoMapper 5.0부터는 .TypeMap속성 IMappingExpression이 사라 졌으므로 4.2 솔루션이 더 이상 작동하지 않습니다. 원래 기능을 사용하지만 다른 구문으로 솔루션을 만들었습니다.

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMap<Src, Dest>();
    cfg.IgnoreUnmapped();        // Ignores unmapped properties on all maps
    cfg.IgnoreUnmapped<Src, Dest>();  // Ignores unmapped properties on specific map
});

// or add  inside a profile
public class MyProfile : Profile
{
   this.IgnoreUnmapped();
   CreateMap<MyType1, MyType2>();
}

이행:

public static class MapperExtensions
{
    private static void IgnoreUnmappedProperties(TypeMap map, IMappingExpression expr)
    {
        foreach (string propName in map.GetUnmappedPropertyNames())
        {
            if (map.SourceType.GetProperty(propName) != null)
            {
                expr.ForSourceMember(propName, opt => opt.Ignore());
            }
            if (map.DestinationType.GetProperty(propName) != null)
            {
                expr.ForMember(propName, opt => opt.Ignore());
            }
        }
    }

    public static void IgnoreUnmapped(this IProfileExpression profile)
    {
        profile.ForAllMaps(IgnoreUnmappedProperties);
    }

    public static void IgnoreUnmapped(this IProfileExpression profile, Func<TypeMap, bool> filter)
    {
        profile.ForAllMaps((map, expr) =>
        {
            if (filter(map))
            {
                IgnoreUnmappedProperties(map, expr);
            }
        });
    }

    public static void IgnoreUnmapped(this IProfileExpression profile, Type src, Type dest)
    {
        profile.IgnoreUnmapped((TypeMap map) => map.SourceType == src && map.DestinationType == dest);
    }

    public static void IgnoreUnmapped<TSrc, TDest>(this IProfileExpression profile)
    {
        profile.IgnoreUnmapped(typeof(TSrc), typeof(TDest));
    }
}

3
이것을 체인 CreateMap<TSource,TDest>()식으로 어떻게 사용 Profile하시겠습니까?
jmoerdyk

2
고마워 GetUnmappedPropertyNames 메서드는 소스와 대상 모두에서 매핑되지 않은 모든 속성 이름을 반환합니다.이 맵은 역방향 맵에서 중단 된 것으로 보이므로 매핑되지 않은 속성이 소스 또는 대상에 있는지 확인하기 위해 IgnoreUnmapped를 약간 변경해야했습니다. 따라서. 다음은 문제와 업데이트를 보여주는 바이올린입니다. dotnetfiddle.net/vkRGJv
Mun

1
결과를 포함하도록 답변을 업데이트했습니다. 소스 매핑을 사용하지 않으므로이 문제를 해결하지 못했습니다! 감사.
Richard

1
리플렉션을 사용할 수없는 PCL에서는 작동하지 않으며 GetProperty (propName)가 없습니다.
George Taskos

이것이 어떻게 질문에 대한 해결책인지, 또는 이것이 어떻게 수행되는지 알 수 없습니다. 그들이 있기 때문에 - 매핑되지 않은 속성은 이미 무시하려고하는 매핑되지 않은 . 포스터는 " 명시 적으로 매핑 되지 않는 한 소품을 무시하는 방법"이라고 말했다 . 즉, Src.MyProp 및 Dest.MyProp가있는 경우 MyProp에 대해 MapFrom & ForMember를 명시 적으로 호출하지 않는 한 해당 매핑을 무시해야합니다. 따라서 기본 매핑을 무시해야합니다. 이 솔루션이하는 유일한 일은 config-valid-assert 일을 전달하는 것입니다. 매핑이 작동하기 위해 어쨌든 필요하지 않습니다.
N73k

17

질문을한지 몇 년이 지났지 만 현재 확장 버전의 AutoMapper (3.2.1)를 사용하여이 확장 방법이 더 깔끔해 보입니다.

public static IMappingExpression<TSource, TDestination> IgnoreUnmappedProperties<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
    var typeMap = Mapper.FindTypeMapFor<TSource, TDestination>();
    if (typeMap != null)
    {
        foreach (var unmappedPropertyName in typeMap.GetUnmappedPropertyNames())
        {
            expression.ForMember(unmappedPropertyName, opt => opt.Ignore());
        }
    }

    return expression;
}

16

사용하는 사람들을 위해 비 정적 API를 위 (발견 된 다음 확장 메서드 버전 4.2.0과 여기 에서 AutoMapperExtensions사용할 수있는 클래스) :

// from http://stackoverflow.com/questions/954480/automapper-ignore-the-rest/6474397#6474397
public static IMappingExpression IgnoreAllNonExisting(this IMappingExpression expression)
{
    foreach(var property in expression.TypeMap.GetUnmappedPropertyNames())
    {
        expression.ForMember(property, opt => opt.Ignore());
    }
    return expression;
}

여기서 중요한 것은 일단 정적 API가 제거 Mapper.FindTypeMapFor되면 더 이상 작동하지 않으므로 expression.TypeMap필드를 사용하는 것 입니다.


7
5.0부터는 expression.TypeMap더 이상 사용할 수 없습니다. 다음 은 5.0에 대한 내 솔루션입니다.
Richard

public static IMappingExpression<TSource, TDestination> IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)유형 문제를 해결하는 데 사용해야 했습니다.
Nick M

16

Automapper 5.0의 경우 매핑되지 않은 모든 속성을 건너 뛰려면

.ForAllOtherMembers (x => x. 무시 ());

프로필 끝에서

예를 들면 다음과 같습니다.

internal class AccountInfoEntityToAccountDtoProfile : Profile
{
    public AccountInfoEntityToAccountDtoProfile()
    {
        CreateMap<AccountInfoEntity, AccountDto>()
           .ForMember(d => d.Id, e => e.MapFrom(s => s.BankAcctInfo.BankAcctFrom.AcctId))
           .ForAllOtherMembers(x=>x.Ignore());
    }
}

이 경우 출력 개체의 Id 필드 만 해결되고 다른 모든 필드는 건너 뜁니다. 매력처럼 작동하여 더 이상 까다로운 확장 프로그램이 필요하지 않은 것 같습니다!


10

AutoMapper 4.2에 대한 Robert Schroeder의 답변을 업데이트했습니다. 비 정적 매퍼 구성, 우리는 사용할 수 Mapper.GetAllTypeMaps()있지만,이 expression요구에 대한 참조를 가지고 TypeMap:

public static IMappingExpression<TSource, TDestination> 
    IgnoreAllNonExisting<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
    foreach (var property in expression.TypeMap.GetUnmappedPropertyNames())
    {
        expression.ForMember(property, opt => opt.Ignore());
    }
    return expression;
}

AutoMapper 5.0에서는 작동하지 않습니다. IMappingExpression의 .TypeMap 속성을 사용할 수 없습니다. 5. + 버전 의 경우 Richard의 답변
Michael Freidgeim

AM 4.2와 호환
Leszek P

8

특정 멤버를 무시하도록 어떻게 지정 하시겠습니까? 적용하려는 컨벤션, 기본 클래스 또는 속성이 있습니까? 모든 매핑을 명시 적으로 지정하는 사업을 시작하면 AutoMapper에서 어떤 가치를 얻을 수 있는지 잘 모르겠습니다.


지미, 당신은 명확성에 대한 요점을 가지고 있습니다. 가장 우아한 방법으로 이것을 달성하는 방법에 관해서는 : 기본 클래스와 속성은이 상황에서 작동하지 않습니다. 대상 클래스는 실제로 내 통제하에 있지 않기 때문에 XSD 데이터 계약에서 자동 생성되므로 하나는 각 생성주기 후에이 코드를 수동으로 편집합니다. 해결책은 구체적인 경우에 달려 있다고 생각합니다. 컨테이너에 등록 할 컴포넌트를 선택하기 위해 Windsor Castle과 유사한 유창한 인터페이스가 솔루션 일 수 있습니까?
Igor Brejc 2016 년

아 이제 더 이해가 되네요. 흥미로운 기능입니다. 2.1 시간대에서 그 기능을 살펴 보겠습니다.
Jimmy Bogard

2
존재하지 않는 모든 필드를 "무시"할 수있는 구성 가능한 값을 갖는 것은 어떻습니까?
Ricardo Sanchez

6
이것은 질문에 대한 답변이 아닙니다.
user2864740

안녕 지미, 당신은 저자입니까? 기존 동작이 아닌 모든 속성을 기본 동작으로 무시하고 싶습니다 (플래그로 제어 가능). 또한 AutoMapper에서 이상한 오류가 발생하여 알아낼 수 없습니다. 그것은 나에게 구체적인 내용을주지 않습니다.
나오미

7

이것은 오래된 질문처럼 보이지만 다른 사람에게 내 대답을 게시 할 것이라고 생각했습니다.

ConstructUsing을 사용합니다. ForAllMembers와 연결된 객체 이니셜 라이저는 무시합니다.

    Mapper.CreateMap<Source, Target>()
        .ConstructUsing(
            f =>
                new Target
                    {
                        PropVal1 = f.PropVal1,
                        PropObj2 = Map<PropObj2Class>(f.PropObj2),
                        PropVal4 = f.PropVal4
                    })
        .ForAllMembers(a => a.Ignore());

1

많은 멤버를 무시하는 것에 대한 유일한 정보는 http://groups.google.com/group/automapper-users/browse_thread/thread/9928ce9f2ffa641f 스레드 입니다. ProvidingCommonBaseClassConfiguration에 사용 된 트릭을 사용하여 유사한 클래스의 공통 속성을 무시할 수 있다고 생각합니다.
"나머지 무시"기능에 대한 정보는 없습니다. 나는 이전에 코드를 살펴 보았고 그러한 기능을 추가하는 것이 매우 어려울 것 같습니다. 또한 일부 속성을 사용하고 속성을 무시한 것으로 표시하고 표시된 모든 속성을 무시하는 일반 / 공통 코드를 추가 할 수 있습니다.


1
아마도 한 가지 방법은 ForAllMembers 메서드를 사용하고 무시해서는 안되는 속성의 속성 이름이 포함 된 문자열을받은 내 자신의 IMemberConfigurationExpression을 구현 한 다음 나머지를 통해 Ignore ()를 호출하는 것입니다. 그냥 아이디어, 그것이 효과가 있는지 확실하지 않습니다.
Igor Brejc 2016 년

예,이 방법도 가능하지만이 방법은 속성을 사용하는 것보다 까다 롭지 만 더 유연합니다. 은 총알이 없다는 것은 유감입니다 :(.
zihotki

1

나는 이것이 오래된 질문이라는 것을 알고 있지만 귀하의 질문에 @jmoerdyk :

프로파일의 연결된 CreateMap () 표현식에서 이것을 어떻게 사용 하시겠습니까?

답변을 Profile ctor 내에서 사용할 수 있습니다

this.IgnoreUnmapped();
CreateMap<TSource, Tdestination>(MemberList.Destination)
.ForMember(dest => dest.SomeProp, opt => opt.MapFrom(src => src.OtherProp));

0

이처럼 필요한 것만 덮어 쓰는 것보다 ForAllMembers를 사용할 수 있습니다

public static IMappingExpression<TSource, TDest> IgnoreAll<TSource, TDest>(this IMappingExpression<TSource, TDest> expression)
        {
            expression.ForAllMembers(opt => opt.Ignore());
            return expression;
        }

조심하십시오. 모두 무시하고 사용자 정의 매핑을 추가하지 않으면 이미 무시되고 작동하지 않습니다.

또한 AutoMapper에 대한 단위 테스트가 있다면 말하고 싶습니다. 그리고 모든 속성이 올바르게 매핑 된 모든 모델은 그러한 확장 방법을 사용하지 않아야합니다.

당신은 명시 적으로 ignore를 작성해야합니다


-1

대상 유형에 존재하지 않는 속성을 무시하는 현재 (버전 9) 솔루션은 뒤집힌 매핑을 만들고 뒤집는 것입니다.

var config = new MapperConfiguration(cfg => {
  cfg.CreateMap<TheActualDestinationType, TheActualSourceType>().ReverseMap();
});

-2

3.3.1 버전에서는 단순히 IgnoreAllPropertiesWithAnInaccessibleSetter()또는 IgnoreAllSourcePropertiesWithAnInaccessibleSetter()메소드를 사용할 수 있습니다 .


6
이것은 원래 포스터의 질문에 따라 작동하지 않습니다. 이러한 메소드는 소스에서 누락되었지만 대상 유형에있는 특성이 아닌 보호 또는 개인 특성 만 무시합니다.
Dan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.