문제
Automapper에 명시 적으로 맵핑 된 속성을 제외한 모든 속성을 무시하도록 알리는 방법이 있습니까?
외부에서 변경 될 가능성이있는 외부 DTO 클래스가 있으며, 새로운 속성을 추가하면 내 자신의 객체에 매핑하려고 할 때 기능 (예외 원인)이 깨질 것이므로 각 속성을 명시 적으로 지정하지 않기를 원합니다.
해결책
이것은 내가 쓴 확장 방법입니다. 질문이 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();
업데이트: 명백히 사용자 지정 매핑이 포함되어 있으므로 올바르게 작동하지 않습니다. 먼저 ingyeallnonexisting을 호출 한 다음 나중에 사용자 정의 매핑을하는 경우에도 여전히 작동 할 수 있다고 생각합니다.
Schdr 은이 질문에 대한 해결책 (이 질문에 대한 답변)이 있습니다. Mapper.GetAllTypeMaps()
어떤 속성이 맵핑되지 않은지 알아 내고 자동으로 무시하십시오. 나에게 더 강력한 해결책 인 것 같습니다.
다른 팁
기존지도를 덮어 쓰지 않도록 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();
내가 이해 한 바에 따르면 대상에 소스에 매핑 된 필드가없는 필드가 있다는 것이었기 때문에 맵핑되지 않은 대상 필드를 무시할 수있는 방법을 찾고 있습니다.
이러한 확장 방법을 구현하고 사용하는 대신 간단히 사용할 수 있습니다.
Mapper.CreateMap<destinationModel, sourceModel>(MemberList.Source);
이제 Automapper는 모든 소스 필드가 매핑되었지만 다른 방식으로 맵핑되지 않았 음을 확인해야한다는 것을 알고 있습니다.
당신은 또한 사용할 수 있습니다 :
Mapper.CreateMap<destinationModel, sourceModel>(MemberList.Destination);
나는 이것을 다음과 같이 할 수 있었다.
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을 사용하고 있습니다.
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
이 클래스의 변경 빈도가 정착 한 후에 돌아와서 이러한 명시 적으로 만들어냅니다.
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));
}
}
질문이 제기 된 지 몇 년이 지났지만이 확장 방법은 현재 버전의 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;
}
사용하는 사람들을 위해 비 정적 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
필드.
automapper 5.0의 경우 모든 캡처 속성을 건너 뛰기 위해
.forallothermembers (x => x.ignore ());
프로필의 끝에.
예를 들어:
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 필드 만 해결됩니다. 다른 모든 것이 건너 뜁니다. 매력처럼 작동합니다. 더 이상 까다로운 확장이 필요하지 않은 것 같습니다!
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에서 어떤 가치를 얻을 수 있는지 잘 모르겠습니다.
이것은 오래된 질문처럼 보이지만 다른 사람이 내가있는 사람에 대해 내 대답을 게시 할 것이라고 생각했습니다.
나는 Allmembers와 결합 된 구성, 객체 이니셜 라이저를 사용합니다.
Mapper.CreateMap<Source, Target>()
.ConstructUsing(
f =>
new Target
{
PropVal1 = f.PropVal1,
PropObj2 = Map<PropObj2Class>(f.PropObj2),
PropVal4 = f.PropVal4
})
.ForAllMembers(a => a.Ignore());
많은 회원을 무시하는 것에 대한 유일한 인프라는이 스레드입니다. http://groups.google.com/group/automapper-users/browse_thread/thread/9928ce9f2ffa641f . CommonBaseClassConfiguration을 제공하는 데 사용 된 트릭을 사용하여 유사한 클래스의 공통 속성을 무시할 수 있다고 생각합니다.
그리고 "나머지 무시"기능에 대한 정보는 없습니다. 나는 이전에 코드를 보았고 그러한 기능을 추가하기가 매우 어려울 것 같습니다. 또한 일부 속성을 사용하고 속성을 무시하고 마크를 표시하고 모든 표시된 속성을 무시하기 위해 일반/공통 코드를 추가 할 수 있습니다.
나는 이것이 오래된 질문이라는 것을 알고 있지만 @jmoerdyk 당신의 질문에 :
프로파일의 Chained Createmap () 표현식에서 이것을 어떻게 사용 하시겠습니까?
당신은 이것을 사용할 수 있습니다 대답 이와 같이 프로파일 CTOR 내부
this.IgnoreUnmapped();
CreateMap<TSource, Tdestination>(MemberList.Destination)
.ForMember(dest => dest.SomeProp, opt => opt.MapFrom(src => src.OtherProp));
이와 같이 필요로 만 덮어 쓰는 것보다 Allmembers에 사용할 수 있습니다.
public static IMappingExpression<TSource, TDest> IgnoreAll<TSource, TDest>(this IMappingExpression<TSource, TDest> expression)
{
expression.ForAllMembers(opt => opt.Ignore());
return expression;
}
조심하십시오. 모든 것을 무시하고 사용자 정의 매핑을 추가하지 않으면 이미 무시되고 작동하지 않습니다.
또한 Automapper에 대한 단위 테스트가 있다면 말하고 싶습니다. 그리고 모든 속성이 올바르게 매핑 된 모든 모델을 테스트합니다. 그러한 확장 방법을 사용해서는 안됩니다.
당신은 명시 적으로 무시하는 것을 써야합니다
3.3.1의 버전에서는 간단히 사용할 수 있습니다 IgnoreAllPropertiesWithAnInaccessibleSetter()
또는 IgnoreAllSourcePropertiesWithAnInaccessibleSetter()
행동 양식.