Ignorar o mapeamento de uma propriedade com o Automapper

285

Estou usando o Automapper e tenho o seguinte cenário: A classe OrderModel possui uma propriedade chamada 'ProductName' que não está no banco de dados. Então, quando eu tento fazer o mapeamento com:

Mapper.CreateMap<OrderModel, Orders>(); 

Isso gera uma exceção:

"As 1 propriedades a seguir no Project.ViewModels.OrderModel não estão mapeadas: 'ProductName'

Eu li no Wiki for Projections do AutoMapper o caso oposto (o atributo extra está no destino, não na fonte que é realmente o meu caso)

Como evitar o automapper para fazer o mapeamento dessa propriedade?

Msam85
fonte
7
O Automapper não funciona dessa maneira. Está preocupado apenas com propriedades no objeto de destino. O src pode conter 100 propriedades extras - o Automapper mapeia apenas as propriedades de destino. Deve haver algo mais causando a exceção de mapeamento. Você pode postar algum código do que não está funcionando?
PatrickSteele
Faz o que você pede automaticamente. Postar algum código para esclarecer
BeRecursive
Dê uma olhada nas seguintes mensagens, estas podem ajudá-lo a stackoverflow.com/questions/4456519/… stackoverflow.com/questions/4052579/…
Divi
3
O @Patrick AutoMapper faz alguns truques com a análise de nomes de métodos / propriedades. É possível que exista uma propriedade na origem que esteja sendo mapeada sem intenção, mesmo se não houver uma correspondência exata no destino. É por isso que existe um ForSourceMember (... Ignore ()) para evitar isso quando ocorre.
AaronLS

Respostas:

477

De Jimmy Bogard: CreateMap<Foo, Bar>().ForMember(x => x.Blarg, opt => opt.Ignore());

Está em um dos comentários em seu blog .

smartcaveman
fonte
13
Além disso, CreateMap<Foo, Bar>().ForSourceMember(x => x.Blarg, opt => opt.Ignore());pode ser útil
stackoverfloweth
5
@stackoverfloweth Você não quer dizer CreateMap<SourceType, DestType> (MemberList.Source).ForSourceMember(x => x.MySourceProperty, opt => opt.DoNotValidate()):?
Monty
12
Ignorar foi substituído por DoNotValidate no ForSourceMember: github.com/AutoMapper/AutoMapper/blob/master/docs/…
Jamie
@ Jamie @monty - Comecei a atualizar este comentário: seu comentário, mas parece que a mudança de sintaxe afeta apenas o caso de projeção (onde a propriedade de origem precisa ser ignorada). A solicitação do OP é ignorar uma propriedade de destino, portanto, Ignore()permanece a sintaxe correta. Isso ocorre porque a alteração de sintaxe Ignorefoi feita na ISourceMemberConfigurationExpressioninterface, mas não na IMemberConfigurationExpression`3interface separada .
smartcaveman
2
@Franva ForMember () é realmente "ForDestinationMember ()"
rvnlord 02/08/19
243

Eu sou talvez um pouco perfeccionista; Eu realmente não gosto da sintaxe ForMember (..., x => x.Ignore ()). É uma coisinha, mas é importante para mim. Eu escrevi este método de extensão para torná-lo um pouco melhor:

public static IMappingExpression<TSource, TDestination> Ignore<TSource, TDestination>(
    this IMappingExpression<TSource, TDestination> map,
    Expression<Func<TDestination, object>> selector)
{
    map.ForMember(selector, config => config.Ignore());
    return map;
}

Pode ser usado assim:

Mapper.CreateMap<JsonRecord, DatabaseRecord>()
        .Ignore(record => record.Field)
        .Ignore(record => record.AnotherField)
        .Ignore(record => record.Etc);

Você também pode reescrevê-lo para trabalhar params, mas eu não gosto da aparência de um método com muitas lambdas.

Steve Rukuts
fonte
6
Eu sei que isto vai além da questão inicial, mas eu realmente gosto desta resposta, o seu limpo, muito fácil de ler e entender instantaneamente mais fácil reutilizar
Lski
Em relação params: Você poderia retornar uma matriz de seletores de dentro de um único lambda, em seguida, mapear sobre cada seletor com foreachou Select()Talvez não menos confuso para o futuro, no entanto.
jpaugh
obrigado @Steve Rukuts, para quem procura um método de extensão para ignorar os membros de origem, você pode usar este IMappingExpression público estático <TSource, TDestination> IgnoreSourceValidation <TSource, TDestination> (este mapa IMappingExpression <TSource, TDestination>, Expression <Func <TSource , objeto >> seletor) {map.ForSourceMember (seletor, config => config.DoNotValidate ()); mapa de retorno; }
Jason Dias
79

Você consegue fazer isso:

conf.CreateMap<SourceType, DestinationType>()
   .ForSourceMember(x => x.SourceProperty, y => y.Ignore());
Richard
fonte
O automapper tem uma extensão ForSourceMember?
Redeemed1
Eu faço isso atualmente, mas seria ideal para não ter que criar todos esses ignorar ...: /
Tom Stickel 14/13/13
você sabe se há uma maneira de ignorar ao fazer o mapeamento e não ao criar o mapa?
Sam I am diz Reinstate Monica
3
Para o cenário indicado na pergunta, essa deve ser a resposta aceita. A resposta atual aceita ignora o mapeamento de propriedades no objeto de destino. Esta pergunta é sobre ignorar mapeamentos no objeto de origem.
Rob S.
28

Apenas para quem tenta fazer isso automaticamente, você pode usar esse método de extensão para ignorar propriedades não existentes no tipo de destino:

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

para ser usado da seguinte forma:

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

graças a Can Gencer pela dica :)

fonte: http://cangencer.wordpress.com/2011/06/08/auto-ignore-non-existing-properties-with-automapper/

Stéphane
fonte
3
FYI: mesclado de stackoverflow.com/questions/4052579/…
Shog9
1
Isso não funciona ao injetar o IMapper. O Mapper.GetAllTypeMaps não existe na versão mais recente do AutoMapper. Além disso, quando configuro meus mapas em um AutoMapper.Profile e, posteriormente, injeto o IMapper, recebi a exceção "Mapper não inicializado. Chame Initialize com a configuração apropriada. Se você estiver tentando usar instâncias do mapeador por meio de um contêiner ou não, verifique se você não possui chamadas para os métodos estáticos Mapper.Map e, se você estiver usando os métodos de extensão ProjectTo ou UseAsDataSource, certifique-se de passar na instância apropriada de IConfigurationProvider. "
Ristogod
Acabei de chegar 'Mapper' does not contain a definition for 'GetAllTypeMaps' [DSSTools]..
Bassie
2
@Bassie Use Mapper.Configuration.GetAllTypeMaps() fonte
Mike Bovenlander
28

Agora existe (AutoMapper 2.0) um IgnoreMapatributo que eu vou usar em vez da sintaxe fluente que é um IMHO um pouco pesado.

Guillaume
fonte
35
O atributo ignore vaza o mapeador automático através do seu aplicativo.
27411
11
O AutoMapper é uma coisa que não me importo de vazar por todo o lugar. ;)
Pawel Krakowiak
4
Você sempre pode considerar derivar IgnoreMapAttribute.
Alapago
1
Essa é uma boa maneira de ignorar uma propriedade base que é herdada em muitos objetos. Evita que seja necessário ignorá-lo em todas as configurações de mapeamento.
Perseguição Florell
23

Ao mapear um modelo de exibição de volta para um modelo de domínio, pode ser muito mais simples validar a lista de membros de origem em vez da lista de membros de destino

Mapper.CreateMap<OrderModel, Orders>(MemberList.Source); 

Agora, minha validação de mapeamento não falha, exigindo outra Ignore(), sempre que adiciono uma propriedade à minha classe de domínio.

Loren Paulsen
fonte
7
Isso é o que eu procurava, tão útil quando apenas modifica um subconjunto de propriedades de objetos de domínio a partir de um DTO muito mais simples.
Adam Tolley
5
Esta é as crianças de resposta, fazer esse funcionário tão novatos não será confundido
Piotr M
0

Pode usar IgnoreAttribute na propriedade que precisa ser ignorada

Naresh
fonte
2
É [IgnoreMap]deIgnoreMapAttribute
fiorebat 5/12/19
-5

Olá a todos Por favor, use isso, está funcionando bem ... para o mapeador automático usar vários .ForMember em C #

        if (promotionCode.Any())
        {
            Mapper.Reset();
            Mapper.CreateMap<PromotionCode, PromotionCodeEntity>().ForMember(d => d.serverTime, o => o.MapFrom(s => s.promotionCodeId == null ? "date" : String.Format("{0:dd/MM/yyyy h:mm:ss tt}", DateTime.UtcNow.AddHours(7.0))))
                .ForMember(d => d.day, p => p.MapFrom(s => s.code != "" ? LeftTime(Convert.ToInt32(s.quantity), Convert.ToString(s.expiryDate), Convert.ToString(DateTime.UtcNow.AddHours(7.0))) : "Day"))
                .ForMember(d => d.subCategoryname, o => o.MapFrom(s => s.subCategoryId == 0 ? "" : Convert.ToString(subCategory.Where(z => z.subCategoryId.Equals(s.subCategoryId)).FirstOrDefault().subCategoryName)))
                .ForMember(d => d.optionalCategoryName, o => o.MapFrom(s => s.optCategoryId == 0 ? "" : Convert.ToString(optionalCategory.Where(z => z.optCategoryId.Equals(s.optCategoryId)).FirstOrDefault().optCategoryName)))
                .ForMember(d => d.logoImg, o => o.MapFrom(s => s.vendorId == 0 ? "" : Convert.ToString(vendorImg.Where(z => z.vendorId.Equals(s.vendorId)).FirstOrDefault().logoImg)))
                .ForMember(d => d.expiryDate, o => o.MapFrom(s => s.expiryDate == null ? "" : String.Format("{0:dd/MM/yyyy h:mm:ss tt}", s.expiryDate))); 
            var userPromotionModel = Mapper.Map<List<PromotionCode>, List<PromotionCodeEntity>>(promotionCode);
            return userPromotionModel;
        }
        return null;
ravikant sonare
fonte