오토매퍼: "나머지는 무시하세요"?
AutoMapper에게 명시적으로 매핑된 속성을 제외한 모든 속성을 무시하도록 지시할 수 있는 방법이 있습니까?
외부에서 변경될 가능성이 있는 외부 DTO 클래스가 있으며 새 속성을 추가하면 내 개체에 매핑하려고 할 때 기능이 손상(예외 발생)되기 때문에 각 속성이 명시적으로 무시되도록 지정하는 것을 피하고 싶습니다.
제가 이해한 질문은 소스에 매핑된 필드가 없는 대상에 필드가 있다는 것입니다. 따라서 매핑되지 않은 대상 필드를 무시하는 방법을 찾는 것입니다.
이러한 확장 방법을 구현하고 사용하는 대신 단순히 사용할 수 있습니다.
Mapper.CreateMap<sourceModel, destinationModel>(MemberList.Source);
이제 자동 매핑기는 모든 소스 필드가 매핑되었는지만 확인하면 되며 그 반대는 아님을 알게 되었습니다.
다음을 사용할 수도 있습니다.
Mapper.CreateMap<sourceModel, destinationModel>(MemberList.Destination);
기존 지도를 덮어쓰지 않도록 Cancer의 확장자를 업데이트했습니다.
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();
업데이트: 버전 9.0에서는 Mapper 정적 API가 제거되었습니다.
이에게는 더 .ForAllOtherMembers 는 Automapper 11에서 제거되었습니다.
5에는 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이 클래스의 변경 빈도가 안정된 후에 돌아와서 이를 명시합니다.
이것은 대상에 존재하지 않는 모든 속성을 무시하는 확장 메서드입니다.질문이 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()매핑되지 않은 속성을 확인하고 자동으로 무시합니다.저에게는 더 강력한 해결책인 것 같습니다.
저는 다음과 같은 방법으로 이 작업을 수행할 수 있었습니다.
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 이후로는.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;
}
Automapper 5.0의 경우 매핑되지 않은 모든 속성을 건너뛰기 위해 입력하기만 하면 됩니다.
.기타 모든 구성원(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 필드만 확인됩니다. 다른 모든 필드는 건너뜁니다.매력적으로 작동합니다. 더 이상 까다로운 확장이 필요하지 않은 것 같습니다!
버전 4.2.0 이상에서 비정적 API를 사용하는 사용자를 위해 다음 확장 방법을 사용합니다(여기에서 확인 가능).AutoMapperExtensionsclass)를 사용할 수 있습니다.
// 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들판.
오토매퍼 4.2에 대한 로버트 슈뢰더의 답변을 업데이트했습니다.정적 매퍼가 아닌 구성에서는 사용할 수 없습니다.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;
}
이것은 오래된 질문처럼 보이지만 저처럼 보이는 다른 사람을 위해 제 대답을 게시할 것이라고 생각했습니다.
나는 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());
기본적으로 AutoMapper는 대상 유형을 사용하여 구성원의 유효성을 검사하지만 구성원 목록을 사용하여 유효성 검사를 건너뛸 수 있습니다.옵션 없음.
var configuration = new MapperConfiguration(cfg =>
cfg.CreateMap<Source2, Destination2>(MemberList.None);
);
여기에서 참조를 찾을 수 있습니다.
닷넷 5용 WebApi에서 Nuget 패키지 사용AutoMapper.Extensions.Microsoft.DependencyInjection매퍼 프로필에서 이렇게 하고 있습니다.저는 오토매퍼에 정말 녹슬었지만, 이제는 지도가 없는 회원들에게도 잘 작동하는 것 같습니다.
시작 시:
var mapperConfig = new MapperConfiguration(mc => mc.AddProfile(new AutoMapperProfile()));
services.AddSingleton(mapperConfig.CreateMapper());
그리고 내 AutoMapperProfile에서:
CreateMap<ProjectActivity, Activity>()
.ForMember(dest => dest.ActivityName, opt => opt.MapFrom(src => src.Name))
.ValidateMemberList(MemberList.None);
많은 구성원을 무시하는 것에 대한 유일한 정보는 이 스레드인 http://groups.google.com/group/automapper-users/browse_thread/thread/9928ce9f2ffa641f 입니다. 저는 당신이 비슷한 클래스에 대한 공통 속성을 무시하는 데 사용된 트릭을 사용할 수 있다고 생각합니다.
그리고 "나머지는 무시" 기능에 대한 정보가 없습니다.이전에 코드를 살펴본 적이 있는데 이러한 기능을 추가하는 것은 매우 어려울 것 같습니다.또한 일부 특성을 사용하여 무시된 속성으로 표시하고 일반/공통 코드를 추가하여 표시된 모든 속성을 무시할 수 있습니다.
이것이 오래된 질문이라는 것을 알지만, 당신의 질문에 @jmoerdyk:
프로파일의 연결된 CreateMap() 표현식에서 이를 어떻게 사용하시겠습니까?
프로파일레이터 안에서 이 답변을 사용할 수 있습니다.
this.IgnoreUnmapped();
CreateMap<TSource, Tdestination>(MemberList.Destination)
.ForMember(dest => dest.SomeProp, opt => opt.MapFrom(src => src.OtherProp));
이렇게 덮어쓰기만 필요한 것이 아니라 ForAllMembers를 사용할 수 있습니다.
public static IMappingExpression<TSource, TDest> IgnoreAll<TSource, TDest>(this IMappingExpression<TSource, TDest> expression)
{
expression.ForAllMembers(opt => opt.Ignore());
return expression;
}
모두 무시되므로 주의하십시오. 사용자 지정 매핑을 추가하지 않으면 이미 무시되고 작동하지 않습니다.
또한, 저는 당신이 AutoMapper에 대한 유닛 테스트가 있는지 말하고 싶습니다.그리고 모든 속성이 올바르게 매핑된 모든 모델을 테스트하는 경우 이러한 확장 방법을 사용하면 안 됩니다.
당신은 무시를 명시적으로 써야 합니다.
버전 12 매우 나쁜 코드이지만, 급한 일을 해결했습니다.
CreateMap<RepairPutRequest, Repair>(MemberList.None)
.ForAbdusselamMember(x => x.ClosedLostTimeId, y => y.MapFrom(z => z.ClosedLostTimeId))
.ForAbdusselamMember(x => x.Explanation, y => y.MapFrom(z => z.Explanation)).IgnoreUnmapped()
;
public static class MappingExtensions
{
public static Dictionary<string, List<string>> list = new Dictionary<string, List<string>>();
public static IMappingExpression<TSource, TDestination> IgnoreUnmapped<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
{
var sourceType = typeof(TSource);
var destinationType = typeof(TDestination);
var key =$"{sourceType.FullName}__||__{destinationType.FullName}" ;
var t = list[key];
foreach (var item in destinationType.GetProperties())
{
if (!t.Contains(item.Name)) {
expression.ForMember(item.Name, x => x.Ignore());
}
}
return expression;
}
public static IMappingExpression<TSource, TDestination> ForAbdusselamMember<TSource, TDestination, TMember>(this IMappingExpression<TSource, TDestination> expression,
Expression<Func<TDestination, TMember>> destinationMember, Action<IMemberConfigurationExpression<TSource, TDestination, TMember>> memberOptions )
{
var sourceType = typeof(TSource);
var destinationType = typeof(TDestination);
var key = $"{sourceType.FullName}__||__{destinationType.FullName}";
if (!list.ContainsKey(key))
{
list[key]=new List<string>();
}
expression.ForMember(destinationMember, memberOptions);
var memberInfo = ReflectionHelper.FindProperty(destinationMember);
list[key].Add(memberInfo.Name);
return expression;
}
}
저는 약간의 개선을 했습니다.코드는 다음과 같습니다.
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);
var memberConfigurations = expression.GetType()
.GetProperty("MemberConfigurations",
BindingFlags.NonPublic | BindingFlags.Instance)
?.GetValue(expression) as List<IPropertyMapConfiguration>;
var mappedProperties = memberConfigurations?
.Select(p => p.DestinationMember.Name)
.ToList();
foreach (var property in destinationProperties)
{
if (mappedProperties != null && mappedProperties.Contains(property.Name))
continue;
expression.ForMember(property.Name, opt => opt.Ignore());
}
return expression;
}
에서는 3.3.1 버는간사단용수있다습니를 .IgnoreAllPropertiesWithAnInaccessibleSetter()또는IgnoreAllSourcePropertiesWithAnInaccessibleSetter()방법들.
대상 유형에 없는 속성을 무시하기 위한 현재(버전 9) 솔루션은 플립된 매핑을 만든 후 반대로 만드는 것입니다.
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<TheActualDestinationType, TheActualSourceType>().ReverseMap();
});
언급URL : https://stackoverflow.com/questions/954480/automapper-ignore-the-rest
'codememo' 카테고리의 다른 글
| clearfix'의 어떤 방법을 사용할 수 있습니까? (0) | 2023.06.02 |
|---|---|
| ARC로? ARC로?장점과 단점은 무엇입니까? (0) | 2023.06.02 |
| 앱에 대한 푸시 알림 설정 재설정 (0) | 2023.06.02 |
| 그룹화된 테이블 뷰 셀의 배경/경계 색상을 사용자 지정하는 방법은 무엇입니까? (0) | 2023.06.02 |
| 레일에 매개변수가 있는지 테스트하는 방법 (0) | 2023.06.02 |