Automapper: problème de mappage avec l’inheritance et la classe de base abstraite sur les collections avec Entity Framework 4 Proxy Pocos

J’ai un problème avec AutoMapper (qui est une excellente technologie) pour mapper un object métier à un DTO où j’ai hérité d’une classe de base abstraite au sein d’une collection.

Voici mes objects:

abstract class Payment class CashPayment : Payment class CreditCardPayment : Payment 

J’ai aussi un object de facture qui contient une collection de paiements comme ceci:

  public class Invoice { ... properties... public ICollection Payments { get; set; } } 

J’ai également des versions DTO correspondantes de chacun de ces objects.

L’object DtoInvoice est défini comme suit:

 [DataContract] public class DtoInvoice { ...properties... [DataMember] public List Payments { get; set; } } 

Voici à quoi ressemblent mes définitions Mapper:

 Mapper.CreateMap(); Mapper.CreateMap() .Include() .Include(); Mapper.CreateMap(); Mapper.CreateMap(); 

Le code pour effectuer le mappage ressemble à ceci:

 var invoice = repo.GetInvoice(invoiceId); var dtoInvoice = Mapper.Map(invoice); 

Ainsi, par exemple, si mon object de facture contient une collection de paiements spécifiques (par exemple, 1 espèces et 1 carte de crédit) lorsque le mappeur essaie de les cartographier, j’obtiens une erreur indiquant que la classe abstraite Paiement ne peut pas être créée. Si je supprime le mot-clé abstrait de l’object de paiement, le code fonctionne, mais je n’obtiens qu’une collection d’objects de paiement, je n’obtiens pas leurs objects spécifiques (paiements en espèces et par carte de crédit).

La question est donc de savoir comment AutoMapper peut mapper les types de paiement spécifiques et non la classe de base.


Mettre à jour

J’ai fait plus de recherches et je pense voir un problème, mais je ne sais pas comment je peux résoudre ce problème avec AutoMapper. Je pense que c’est plus une chose EF que la faute d’AutoMapper. 🙂

Dans mon code, j’utilise Entity Framework 4 Proxy POCO avec un chargement différé.

Donc, quand j’essaie de mapper une entité renvoyée par EF qui est un proxy POCO, elle obtient ce type de recherche drôle comme:

 System.Data.Entity.DynamicProxies.CashPayment_86783D165755C316A2F58A4343EEC4842907C5539AF24F0E64AEF498B15105C2 

Donc, ma théorie est que lorsque AutoMapper essaie de mapper CashPayment sur DtoCashPayment et que le paiement passé est du type proxy, AutoMapper le voit comme un “non-match”, puis mappe le type de paiement générique. Mais depuis que Payment est une classe abstraite, AutoMapper bombes avec une “System.InvalidOperationException: Instances de classes abstraites ne peuvent pas être créées”. exception.

Donc, la question est la suivante: est-il possible pour moi d’utiliser AutoMapper pour mapper des objects proxy EF POCO à Dtos.

Cette réponse arrive un peu tard car je viens de faire face au même problème avec les proxys EF4 POCO.

Je l’ai résolu en utilisant un convertisseur personnalisé qui appelle Mapper.DynamicMap(object source) pour appeler la conversion de type à l’exécution, plutôt que le .Include() .

Ça fonctionne bien pour moi.

Dans votre cas, vous définiriez le convertisseur suivant:

 class PaymentConverter : ITypeConverter { public DtoPayment Convert( ResolutionContext context ) { return Mapper.DynamicMap( context.SourceValue ); } } 

Et alors:

 Mapper.CreateMap().ConvertUsing(); Mapper.CreateMap(); Mapper.CreateMap(); 

J’ai aussi essayé l’exemple d’Olivier et j’ai eu les mêmes erreurs StackOverflow. J’ai également essayé la solution de subkamran mais pas la chance car je n’utilise pas une classe de base de la génération de code de modèle d’entité. Automapper explose encore. Jusqu’à ce que je trouve une meilleure solution, je viens de définir le contexte pour ne pas créer de proxy lorsque je crée un object de contexte.

 model.Configuration.ProxyCreationEnabled = false; model.Configuration.LazyLoadingEnabled = true; 

Je voudrais aussi voir une réponse au problème en utilisant peut-être quelque chose construit dans Automapper …

MISE À JOUR: La pré-version de Automapper corrige ce problème et permet au mappage de couvrir un DynamicProxy sans configuration supplémentaire.

La version dans laquelle cela fonctionne est 2.2.1

En me basant sur la réponse d’Olivier, je ne pouvais pas le faire fonctionner dans mon contexte … il continuait dans une boucle infinie et envoyait une exception StackOverflowException.

Dans cet exemple, AbstractClass est ma classe de base et AbstractViewModel est mon modèle de vue de base (non marqué comme abstract ).

Cependant, je l’ai fait fonctionner en utilisant ce convertisseur d’aspect hackish:

  public class ProxyConverter : ITypeConverter where TSource : class where TDestination : class { public TDestination Convert(ResolutionContext context) { // Get dynamic proxy base type var baseType = context.SourceValue.GetType().BaseType; // Return regular map if base type == Abstract base type if (baseType == typeof(TSource)) baseType = context.SourceValue.GetType(); // Look up map for base type var destType = (from maps in Mapper.GetAllTypeMaps() where maps.SourceType == baseType select maps).FirstOrDefault().DestinationType; return Mapper.DynamicMap(context.SourceValue, baseType, destType) as TDestination; } } // Usage Mapper.CreateMap() .ConvertUsing(new ProxyConverter()); 

Ainsi, un DerivedClassA normalement, mais un DynamicProxy_xxx sera également mappé correctement lorsque ce code inspectera son type de base ( DerivedClassA ).

S’il vous plaît, s’il vous plaît, montrez-moi s’il vous plaît que je n’ai pas à faire cette merde de recherche folle. Je ne connais pas assez AutoMapper pour corriger correctement la réponse d’Olivier.

J’ai rencontré le même problème avec les proxy Entity Framework, mais je ne voulais pas passer à une version préliminaire d’AutoMapper. J’ai trouvé un travail simple mais légèrement laid sur la version 2.2.0. J’essayais de passer d’un object DTO à un object proxy EF existant et recevais des erreurs à propos de l’absence d’un mappage pour le nom de classe proxy laid. Ma solution consistait à utiliser une surcharge pour spécifier les types concrets réels que j’avais mappés manuellement:

 Mapper.Map(dtoSource, entityDest, typeof(DtoClass), typeof(ConcreteEntityClass)); 

Je viens de faire face au même problème avec le mappage de proxys EF dynamics avec ViewModels dans une application MVC.

J’ai trouvé une solution simple en utilisant Mapper.DynamicMap () pour ce problème. Voici mon code:

Conversion du proxy dynamic en classe ViewModel:

 // dynamic proxy instance WebService webService = _repWebService.GetAll().SingleOrDefault(x => x.Id == id); //mapping FirstStepWebServiceModel model = Mapper.DynamicMap(webService); 

Conversion de la classe ViewModel en proxy dynamic EF:

 [HttpPost] public ActionResult FirstStep(FirstStepWebServiceModel input) { // getting the dynamic proxy from database WebService webService = _repWebService.GetAll().Single(x => x.Id == input.WebServiceId); // mapping the input ViewModel class to the Dynamic Proxy entity Mapper.DynamicMap(input, webService); } 

J’espère que cet exemple vous aidera