41 votes

Utilisation d'AutoMapper pour déflater un DTO

J'ai essayé d'utiliser AutoMapper pour gagner du temps en passant de mes DTO à mes objets de domaine, mais j'ai du mal à configurer la carte pour qu'elle fonctionne, et je commence à me demander si AutoMapper n'est pas le mauvais outil pour ce travail.

Considérons cet exemple d'objets de domaine (une entité et une valeur) :

public class Person
{
    public string Name { get; set; }
    public StreetAddress Address { get; set; }
}

public class StreetAddress
{
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
}

Mon DTO (d'un objet Linq à SQL) ressemble à peu près à ceci :

public class PersonDTO
{
    public string Name { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set; }
}

J'aimerais pouvoir le faire dans mon référentiel :

return Mapper.Map<PersonDTO, Person>(result);

J'ai essayé de configurer l'AutoMapper de toutes les manières possibles, mais je continue à obtenir le message générique suivant Configuration de carte de type manquante ou mappage non pris en charge sans aucun détail pour me dire où j'échoue.

J'ai essayé un certain nombre de configurations différentes, mais en voici quelques-unes :

Mapper.CreateMap<PersonDTO, Person>()
    .ForMember(dest => dest.Address, opt => opt.MapFrom(Mapper.Map<Person, Domain.StreetAddress>));

et

Mapper.CreateMap<Person, Domain.Person>()
    .ForMember(dest => dest.Address.Address1, opt => opt.MapFrom(src => src.Address))
    .ForMember(dest => dest.Address.City, opt => opt.MapFrom(src => src.City))
    .ForMember(dest => dest.Address.State, opt => opt.MapFrom(src => src.State));

J'ai lu que aplatissant d'objets avec AutoMapper est facile, mais dégonflement ce n'est pas facile... ni même possible. Quelqu'un peut-il me dire si j'essaie de faire l'impossible et, dans le cas contraire, ce que je fais de mal ?

Notez que mes objets réels sont un peu plus compliqués, il est donc possible que j'omette des informations qui sont la clé de l'erreur... si ce que je fais semble correct, je peux fournir plus d'informations ou commencer à simplifier mes objets pour les tester.

0 votes

Hmmm, votre deuxième configuration a l'air bien (à part son nom manquant) et ne devrait-elle pas être <PersonDTO, Domain.Person> ? Il serait peut-être utile de vérifier que Domain.Person et PersonDTO sont des références correctes aux classes mentionnées ci-dessus.

0 votes

1 votes

Pour l'instant, le lien de Ruben et la réponse acceptée (une seule réponse pour l'instant) de 81959186 renvoient à ce message. Je ne vois pas la valeur du commentaire du lien sur cette page. Ruben a posté un lien vers cette question à partir de l'autre page et celui-là a du sens.

70voto

sydneyos Points 1510

Cela semble également fonctionner pour moi :

Mapper.CreateMap<PersonDto, Address>();
Mapper.CreateMap<PersonDto, Person>()
        .ForMember(dest => dest.Address, opt => opt.MapFrom( src => src )));

En gros, il faut créer un mappage de la dto vers les deux objets, puis l'utiliser comme source pour l'objet enfant.

1 votes

C'est exactement ce que je recherchais. ValueInjector peut être la réponse choisie, mais avec ceci, AutoMapper semble beaucoup plus facile à utiliser.

12 votes

Ce serait une excellente réponse, mais dans mon DTO, les propriétés de l'adresse sont aplaties : "AddressCity", alors que dans l'objet Adresse elles sont juste "City", donc le mappage ne fonctionne pas à moins que je mappe explicitement chaque champ. Est-ce également ce que vous avez dû faire ?

0 votes

Cela fonctionne bien mais ne permet pas de définir des valeurs nulles. Elle ignore les valeurs nulles et conserve la valeur d'origine de la destination. Est-il possible d'accepter et d'écrire réellement les valeurs nulles ?

9voto

Ivan Samygin Points 1579

Je ne peux pas poster de commentaire, alors je poste une réponse. Je suppose qu'il y a eu des changements dans l'implémentation de l'AutoMapper, alors la réponse est la suivante https://stackoverflow.com/a/5154321/2164198 proposé par HansoS n'est plus compilable. Bien qu'il existe une autre méthode qui peut être utilisée dans de tels scénarios, à savoir - ResolveUsing :

Mapper.CreateMap<Person, Domain.Person>()
    .ForMember(dest => dest.Address, opt => opt.ResolveUsing( src => { return new Address() {Address1 = src.Address, City = src.City, State = src.State }; }))

6 votes

Cela fonctionne mais va à l'encontre du principe même de l'AutoMapper. Ce n'est plus une carte "Auto" basée sur une convention, c'est une cartographie manuelle. Pire encore, c'est une cartographie manuelle qui est cachée derrière une façade opaque.

2 votes

Desde Wiki de l'Automapper : > Actuellement, AutoMapper est orienté vers des scénarios de projection de modèles pour aplatir des modèles d'objets complexes vers des DTO et d'autres objets simples, dont la conception est mieux adaptée à la sérialisation, à la communication, à la messagerie, ou simplement à une couche anti-corruption entre le domaine et la couche application. Automapper n'est donc pas destiné à convertir DTO->Entity. Mais il possède de nombreuses fonctionnalités que vous pouvez utiliser comme bon vous semble. C'est vous qui décidez - Automapper n'est qu'un outil.

9voto

sanjuro Points 474

En plus de la réponse de Sydney et selon le commentaire de Trevor de Koekkoek, la cartographie bidirectionnelle est possible de la manière suivante

public class Person
{
    public string Name { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
    public string State { get; set; }
}

public class PersonViewModel
{
    public string Name { get; set; }
    public string AddressStreet { get; set; }
    public string AddressCity { get; set; }
    public string AddressState { get; set; }
}

Mappages de l'Automapper

Mapper.Initialize(cfg => cfg.RecognizePrefixes("Address"));
Mapper.CreateMap<Person, PersonViewModel>();
Mapper.CreateMap<PersonViewModel, Address>();
Mapper.CreateMap<PersonViewModel, Person>()
    .ForMember(dest => dest.Address, opt => opt.MapFrom( src => src )));

Si vous mettez en œuvre Nom du site vous pouvez vous débarrasser de la chaîne magique préfixe

Mapper.Initialize(cfg => cfg.RecognizePrefixes(Nameof<Person>.Property(x => x.Address)));

EDIT : En C# 6

Mapper.Initialize(cfg => cfg.RecognizePrefixes(nameof(Person.Address)));

2 votes

Vous pouvez maintenant utiliser la version C# 6 nameof opérateur : msdn.microsoft.com/fr/us/library/dn986596.aspx

8voto

Omu Points 17372

Utiliser https://github.com/omuleanu/ValueInjecter c'est le cas aplatissant y dégonflement et tout ce dont vous avez besoin. asp.net mvc sample application in the download où toutes les fonctionnalités sont démontrées (également les tests unitaires)

2 votes

J'ai essayé ValueInjecter et j'ai rencontré quelques problèmes que vous m'avez aidés à résoudre sur CodePlex. Pour l'instant, ça marche plutôt bien.

0 votes

ValueInjector fait le travail de manière plus élégante que AutoMapper.

0 votes

Il ne supporte pas les listes cependant

5voto

HansoS Points 152

Cela peut être tardif mais vous pouvez résoudre ce problème en utilisant des expressions lambda pour créer l'objet comme ceci :

Mapper.CreateMap<Person, Domain.Person>()
        .ForMember(dest => dest.Address, opt => opt.MapFrom( src => { return new Address() {Address1 = src.Address, City = src.City, State = src.State }; }))

1 votes

Cela fonctionne très bien, mais je ne sais pas comment gérer la situation où Address existe déjà sur l'objet cible.

7 votes

Il en résulte une erreur : "Une expression lambda avec un corps de déclaration ne peut pas être convertie en un arbre d'expression".

1 votes

J'obtiens la même erreur que celle mentionnée par @Kwal. Cependant, lorsque j'ai remplacé le opt.MapFrom con opt.ResolveUsing Selon la réponse d'Ivan Samygin, cela a fonctionné.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X