AutoMapper: "Zignoruj resztę"?

Czy istnieje sposób, aby powiedzieć AutoMapper, aby ignorował wszystkie właściwości z wyjątkiem tych, które są mapowane jawnie?

Mam zewnętrzne klasy DTO, które mogą się zmieniać z zewnątrz i chcę uniknąć definiowania każdej właściwości, które mają być bezpośrednio ignorowane, ponieważ dodanie nowych właściwości spowoduje złamanie funkcjonalności (spowoduje wyjątki) podczas próby zmapowania ich do moich własnych obiektów.

Author: Igor Brejc, 2009-06-05

16 answers

Jest to metoda rozszerzenia, którą napisałem, która ignoruje wszystkie nieistniejące właściwości w miejscu docelowym. Nie jestem pewien, czy nadal będzie przydatny, ponieważ pytanie ma więcej niż dwa lata, ale natknąłem się na ten sam problem, dodając wiele ręcznych połączeń ignorowanych.

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;
}

Użycie:

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

UPDATE: widocznie to nie działa poprawnie, jeśli masz niestandardowe mapowania, ponieważ nadpisuje je. Myślę, że nadal może działać, jeśli najpierw zadzwoń IgnoreAllNonExisting, a potem custom mapowania później.

Schdr ma rozwiązanie (jako odpowiedź na to pytanie), które używa Mapper.GetAllTypeMaps(), aby dowiedzieć się, które właściwości nie są mapowane i automatycznie je ignorować. Wydaje mi się bardziej solidne rozwiązanie.

 67
Author: Can Gencer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-14 07:01:33

Zaktualizowałem rozszerzenie Can Gencer, aby nie nadpisywać żadnych istniejących map.

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;
}

Użycie:

Mapper.CreateMap<SourceType, DestinationType>()
                .ForMember(prop => x.Property, opt => opt.MapFrom(src => src.OtherProperty))
                .IgnoreAllNonExisting();
 207
Author: Robert Schroeder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-10 04:33:26

Z tego, co zrozumiałem, pytanie było takie, że na miejscu docelowym są pola, które nie mają zmapowanego pola w źródle, dlatego szukasz sposobów na zignorowanie tych nie zmapowanych pól docelowych.

Zamiast implementować i używać tej metody rozszerzeń można po prostu użyć

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

Teraz automapper wie, że musi tylko zweryfikować, czy wszystkie pola źródłowe są mapowane, ale nie odwrotnie.

 127
Author: Nazim Hafeez,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-02 11:13:28

Udało mi się to zrobić w następujący sposób:

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*/);
...

Uwaga: używam AutoMapper V. 2. 0.

 77
Author: Yohanb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-08 15:50:40

Od AutoMapper 5.0, właściwość .TypeMap na IMappingExpression zniknęła, co oznacza, że rozwiązanie 4.2 nie działa. Stworzyłem rozwiązanie, które wykorzystuje oryginalną funkcjonalność, ale z inną składnią:

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>();
}

Realizacja:

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));
    }
}
 38
Author: Richard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-27 11:50:18

Wersja 5.0.0-beta-1 Automapp wprowadza metodę rozszerzenia ForAllOtherMembers, więc możesz teraz to zrobić:

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());

Należy pamiętać, że jawne mapowanie każdej właściwości jest korzystne, ponieważ nigdy nie wystąpią problemy z mapowaniem po cichu, które pojawiają się, gdy zapomnisz mapować właściwość.

Być może w Twoim przypadku byłoby mądrze zignorować wszystkich innych członków i dodać TODO, aby wrócić i wyrazić to wyraźnie po ustąpieniu częstotliwości zmian w tej klasie.

 35
Author: ajbeaven,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-03 05:19:06

Minęło kilka lat od zadania pytania, ale ta metoda rozszerzenia wydaje mi się czystsza, używając aktualnej wersji 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;
}
 17
Author: Iravanchi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-05 15:08:20

Dla tych, którzy używają niestatycznego API w wersji 4.2.0 i nowszej, można użyć następującej metody rozszerzenia (znalezionej tutaj w klasie 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;
}

Ważne jest to, że po usunięciu statycznego API kod taki jak Mapper.FindTypeMapFor nie będzie już działał, stąd użycie pola expression.TypeMap.

 16
Author: nick_w,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-29 07:33:22

Dla Automapper 5.0 aby pominąć wszystkie niezapisane właściwości wystarczy umieścić

.ForAllOtherMembers(x=>X. Ignore ());

Na końcu twojego profilu.

Na przykład:

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());
    }
}

W tym przypadku tylko pole Id dla obiektu wyjściowego zostanie rozwiązane wszystkie pozostałe zostaną pominięte. Działa jak urok, wydaje się, że nie potrzebujemy już żadnych trudnych rozszerzeń!

 13
Author: framerelay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-25 11:41:32

Zaktualizowałem odpowiedź Roberta Schroedera na AutoMapper 4.2. W przypadku niestatycznych konfiguracji maperów nie możemy użyć Mapper.GetAllTypeMaps(), ale expression ma odniesienie do wymaganego 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;
}
 10
Author: mrmashal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-13 05:54:53

Jak wolisz określić, że niektórzy członkowie są ignorowani? Czy istnieje konwencja, klasa bazowa lub atrybut, który chcesz zastosować? Kiedy już zaczniesz wyraźnie określać wszystkie mapowania, nie jestem pewien, jaką wartość uzyskasz z Automappera.

 8
Author: Jimmy Bogard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-05 12:31:23

To wydaje się stare pytanie, ale pomyślałem, że opublikuję moją odpowiedź dla każdego, kto wygląda jak ja.

Używam ConstructUsing, object initializer sprzężony z forallmembers ignore np

    Mapper.CreateMap<Source, Target>()
        .ConstructUsing(
            f =>
                new Target
                    {
                        PropVal1 = f.PropVal1,
                        PropObj2 = Map<PropObj2Class>(f.PropObj2),
                        PropVal4 = f.PropVal4
                    })
        .ForAllMembers(a => a.Ignore());
 7
Author: gm1886,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-07 22:33:00

Jedyną informacją o ignorowaniu wielu członków jest ten wątek - http://groups.google.com/group/automapper-users/browse_thread/thread/9928ce9f2ffa641f . Myślę, że możesz użyć sztuczki używanej w ProvidingCommonBaseClassConfiguration, aby zignorować wspólne właściwości dla podobnych klas.
I nie ma informacji o funkcji "Ignoruj resztę". Patrzyłem już wcześniej na kod i wydaje mi się, że bardzo trudno będzie dodać taką funkcjonalność. Również można spróbuj użyć jakiegoś atrybutu i zaznaczyć ignorowane właściwości i dodać jakiś ogólny / wspólny kod, aby zignorować wszystkie zaznaczone właściwości.

 1
Author: zihotki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-05 10:27:50

Wiem, że to stare pytanie, ale @jmoerdyk w twoim pytaniu:

Jak można tego użyć w przykutym wyrażeniu CreateMap () W profilu?

Możesz użyć tej odpowiedź w ten sposób wewnątrz profilu ctor

this.IgnoreUnmapped();
CreateMap<TSource, Tdestination>(MemberList.Destination)
.ForMember(dest => dest.SomeProp, opt => opt.MapFrom(src => src.OtherProp));
 0
Author: j.loucao.silva,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:03

Możesz użyć ForAllMembers, niż zastąpić tylko potrzebne like this

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

Bądź ostrożny, zignoruje wszystkie, a jeśli nie dodasz niestandardowego mapowania, są one już ignorowane i nie będą działać

Również, chcę powiedzieć, jeśli masz test jednostkowy dla Automapp. I testujesz, że wszystkie modele ze wszystkimi właściwościami odwzorowanymi poprawnie nie powinieneś używać takiej metody rozszerzenia

Powinieneś napisać jawnie ignoruj

 0
Author: zxxc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-06 08:09:28

W wersji 3.3.1 można po prostu użyć metod IgnoreAllPropertiesWithAnInaccessibleSetter() LUB IgnoreAllSourcePropertiesWithAnInaccessibleSetter().

 -1
Author: Ivan Kochurkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-21 13:13:47