Ignorer le mappage d'une propriété avec Automapper

285

J'utilise Automapper et j'ai le scénario suivant: La classe OrderModel a une propriété appelée 'ProductName' qui n'est pas dans la base de données. Donc quand j'essaye de faire le mapping avec:

Mapper.CreateMap<OrderModel, Orders>(); 

Il génère une exception:

"Les 1 propriétés suivantes sur Project.ViewModels.OrderModel ne sont pas mappées: 'ProductName'

J'ai lu sur le Wiki for Projections d'AutoMapper le cas contraire (l'attribut supplémentaire est sur la destination, pas dans la source qui est en fait mon cas)

Comment puis-je éviter l'automappeur pour effectuer le mappage de cette propriété?

Msam85
la source
7
Automapper ne fonctionne pas de cette façon. Il ne se préoccupe que des propriétés de l'objet de destination. Le src peut contenir 100 propriétés supplémentaires - Automapper mappe uniquement les propriétés dest. Il doit y avoir autre chose à l'origine de l'exception de mappage. Pouvez-vous publier un code de ce qui ne fonctionne pas?
PatrickSteele
Il fait ce que vous demandez automatiquement. Poster du code pour clarifier
BeRecursive
Jetez un oeil aux articles suivants, ceux-ci pourraient vous aider stackoverflow.com/questions/4456519/… stackoverflow.com/questions/4052579/…
Divi
3
@Patrick AutoMapper fait quelques astuces pour analyser les noms de méthode / propriété. Il est possible qu'il existe une propriété sur la source qui est mappée involontairement même s'il n'y a pas de correspondance exacte sur la destination. C'est pourquoi il existe un ForSourceMember (... Ignore ()) pour empêcher cela quand cela se produit.
AaronLS

Réponses:

477

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

C'est dans l' un des commentaires de son blog .

smartcaveman
la source
13
Cela CreateMap<Foo, Bar>().ForSourceMember(x => x.Blarg, opt => opt.Ignore());pourrait aussi être utile
stackoverfloweth
5
@stackoverfloweth Ne pas vous dire: CreateMap<SourceType, DestType> (MemberList.Source).ForSourceMember(x => x.MySourceProperty, opt => opt.DoNotValidate())?
monty
12
Ignorer a été remplacé par DoNotValidate dans ForSourceMember: github.com/AutoMapper/AutoMapper/blob/master/docs/…
Jamie
@Jamie @monty - J'ai commencé à mettre à jour ce re: votre commentaire, mais il semble que le changement de syntaxe n'affecte que le cas de projection (où la propriété source doit être ignorée). La demande de l'OP est d'ignorer une propriété de destination, donc, Ignore()reste la syntaxe correcte. En effet, le changement de syntaxe pour a Ignoreété effectué sur l' ISourceMemberConfigurationExpressioninterface mais pas sur l' IMemberConfigurationExpression`3interface disjointe .
smartcaveman
2
@Franva ForMember () est en fait "ForDestinationMember ()"
rvnlord
243

Je suis peut-être un peu perfectionniste; Je n'aime pas vraiment la syntaxe ForMember (..., x => x.Ignore ()). C'est une petite chose, mais ça m'importe. J'ai écrit cette méthode d'extension pour la rendre un peu plus agréable:

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

Il peut être utilisé comme ceci:

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

Vous pouvez également le réécrire pour qu'il fonctionne params, mais je n'aime pas l'apparence d'une méthode avec beaucoup de lambdas.

Steve Rukuts
la source
6
Je sais que cela va au-delà de la question initiale, mais j'aime vraiment cette réponse, elle est propre, très facile à lire et à comprendre instantanément, plus facile à réutiliser
Lski
Concernant params: Vous pouvez renvoyer un tableau de sélecteurs à l'intérieur d'un seul lambda, puis mapper sur chaque sélecteur avec foreachou Select()peut - être pas moins désordonné, cependant.
jpaugh
merci @Steve Rukuts, pour tous ceux qui recherchent une méthode d'extension pour ignorer les membres source, vous pouvez utiliser cette IMappingExpression statique publique <TSource, TDestination> IgnoreSourceValidation <TSource, TDestination> (cette IMappingExpression <TSource, TDestination> carte, Expression <Func <TSource , objet >> sélecteur) {map.ForSourceMember (sélecteur, config => config.DoNotValidate ()); carte de retour; }
Jason Dias
79

Tu peux le faire:

conf.CreateMap<SourceType, DestinationType>()
   .ForSourceMember(x => x.SourceProperty, y => y.Ignore());
Richard
la source
Automapper a-t-il une extension ForSourceMember?
Racheté1
Je fais cela actuellement, mais il serait idéal de ne PAS avoir à créer tous ces Ignorer ...: /
Tom Stickel
savez-vous s'il existe un moyen d'ignorer lors de la cartographie et non lors de la création de la carte?
Sam je suis dit Reinstate Monica
FYI: fusionné de stackoverflow.com/questions/4052579/…
Shog9
3
Pour le scénario donné dans la question, cela devrait être la réponse acceptée. La réponse actuellement acceptée ignore le mappage des propriétés dans l'objet de destination. Cette question pose la question de l'ignorance des mappages dans l'objet source.
Rob S.
28

Pour toute personne essayant de le faire automatiquement, vous pouvez utiliser cette méthode d'extension pour ignorer les propriétés non existantes sur le type de destination:

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

à utiliser comme suit:

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

merci à Can Gencer pour l'astuce :)

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

Stéphane
la source
3
FYI: fusionné de stackoverflow.com/questions/4052579/…
Shog9
1
Cela ne fonctionne pas lors de l'injection d'IMapper. Mapper.GetAllTypeMaps n'existe pas dans la dernière version d'AutoMapper. En outre, lorsque j'ai configuré mes cartes dans un AutoMapper.Profile puis injecté IMapper par la suite, j'ai obtenu cette exception "Mappeur non initialisé. Appelez Initialize avec la configuration appropriée. Si vous essayez d'utiliser des instances de mappeur via un conteneur ou autre, assurez-vous de n'avez aucun appel aux méthodes statiques de Mapper.Map et si vous utilisez des méthodes d'extension ProjectTo ou UseAsDataSource, assurez-vous de passer l'instance IConfigurationProvider appropriée. "
Ristogod
Je viens de recevoir 'Mapper' does not contain a definition for 'GetAllTypeMaps' [DSSTools]..
Bassie
2
@Bassie Use Mapper.Configuration.GetAllTypeMaps() source
Mike Bovenlander
28

Il y a maintenant (AutoMapper 2.0) un IgnoreMapattribut, que je vais utiliser plutôt que la syntaxe courante qui est un peu lourde à mon humble avis .

Guillaume
la source
35
L'attribut ignore fuit le mappeur automatique via votre application.
Phill
11
AutoMapper est une chose qui ne me dérange pas de fuir partout. ;)
Pawel Krakowiak
4
Vous pouvez toujours envisager de dériver IgnoreMapAttribute.
Alapago
1
Il s'agit d'un bon moyen d'ignorer une propriété de base héritée de nombreux objets. Évite d'avoir à l'ignorer dans chaque configuration de mappage.
Chase Florell
23

Lors du mappage d'un modèle de vue vers un modèle de domaine, il peut être beaucoup plus simple de simplement valider la liste des membres source plutôt que la liste des membres de destination

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

Maintenant, ma validation de mappage n'échoue pas, nécessitant une autre Ignore(), chaque fois que j'ajoute une propriété à ma classe de domaine.

Loren Paulsen
la source
7
C'est ce que je cherchais, si utile lorsque l'on modifie uniquement un sous-ensemble de propriétés d'objet de domaine à partir d'un DTO beaucoup plus simple.
Adam Tolley
5
Ceci est la réponse des enfants, rendez ce fonctionnaire afin que les débutants ne soient pas confus
Piotr M
0

Pourrait utiliser IgnoreAttribute sur la propriété qui doit être ignorée

Naresh
la source
2
Son [IgnoreMap]deIgnoreMapAttribute
fiorebat
-5

Bonjour à tous S'il vous plaît Utilisez cela, cela fonctionne bien ... pour le mappeur automatique, utilisez plusieurs .ForMember en 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
la source