[.net] AutoMapper : “나머지 무시”?

명시 적으로 매핑 된 속성을 제외한 모든 속성을 무시하도록 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();

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

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


답변

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

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

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

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

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

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


답변

기존지도를 덮어 쓰지 않도록 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<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;
}