2017-10-02 1 views
1

Je souhaite mapper la classe source aux classes de destination dérivées (à partir de l'abstrait) en fonction de la valeur de certaines propriétés.AutoMapper - mappage aux objets dérivés dépend de la condition

je les classes de sources suivantes:

public partial class ApplicationDriver 
{ 
    public virtual ICollection<ApplicationDriverEquipment> Equipments { get; set; } 

} 

public partial class ApplicationDriverEquipment 
{ 
    public int Id { get; set; } 
    [StringLength(256)] 
    public string Make { get; set; } 
    [StringLength(256)] 
    public string Model { get; set; } 
    [StringLength(256)] 
    public string Year { get; set; } 
    [StringLength(256)] 
    public string VINNumber { get; set; } 
    [StringLength(256)] 
    public string PlateNumber { get; set; } 
    [StringLength(256)] 
    public string CurrentMileage { get; set; } 
    [StringLength(256)] 
    public string Length { get; set; } 
    public string Type { get; set; } 

    public int DriverId { get; set; } 
    public virtual ApplicationDriver Driver { get; set; } 
} 

Je veux mapper les classes suivantes, dépendent du paramètre Type:

public class ApplicationDriverDomain 
{ 
    public List<ApplicationDriverEquipmentAbstractDomain> Equipments { get; set; } 

} 

public abstract class ApplicationDriverEquipmentAbstractDomain 
{ 
    public int Id { get; set; } 
    public string Make { get; set; } 
    public string Model { get; set; } 
    public string Year { get; set; } 
    public string PlateNumber { get; set; } 
    public string CurrentMileage { get; set; } 
    public string Type { get; protected set; } 
} 

public class ApplicationDriverEquipmentTractorDomain : ApplicationDriverEquipmentAbstractDomain 
{ 
    public ApplicationDriverEquipmentTractorDomain() 
    { 
     Type = ApplicationDriverEquipmentTypeStaticStringsDomain.Tractor; 
    } 
    public string VINNumber { get; set; } 
} 

public class ApplicationDriverEquipmentTrailerDomain : ApplicationDriverEquipmentAbstractDomain 
{ 
    public ApplicationDriverEquipmentTrailerDomain() 
    { 
     Type = ApplicationDriverEquipmentTypeStaticStringsDomain.Trailer; 
    } 

    public string Length { get; set; } 
} 

public class ApplicationDriverEquipmentStraightTruckDomain : ApplicationDriverEquipmentAbstractDomain 
{ 
    public ApplicationDriverEquipmentStraightTruckDomain() 
    { 
     Type = ApplicationDriverEquipmentTypeStaticStringsDomain.StraightTruck; 
    } 

    public string VINNumber { get; set; } 
    public string Length { get; set; } 
} 

public class ApplicationDriverEquipmentCargoVanDomain : ApplicationDriverEquipmentAbstractDomain 
{ 
    public ApplicationDriverEquipmentCargoVanDomain() 
    { 
     Type = ApplicationDriverEquipmentTypeStaticStringsDomain.CargoVan; 
    } 

    public string VINNumber { get; set; } 
    public string Length { get; set; } 
} 

J'essaie de le faire:

ApplicationDriverEquipmentAbstractDomain GetEquipment(Infrastructure.Asset.ApplicationDriverEquipment infrastructure) 
    { 
     ApplicationDriverEquipmentAbstractDomain result = null; 
     var config = new MapperConfiguration(cfg => cfg.AddProfile<AutoMapperApplicationModel>()); 
     var mapper = config.CreateMapper(); 

     switch (infrastructure.Type) 
     { 
      case ApplicationDriverEquipmentTypeStaticStringsDomain.Tractor: 
       result = mapper.Map<ApplicationDriverEquipmentTractorDomain>(infrastructure); 
       break; 

      case ApplicationDriverEquipmentTypeStaticStringsDomain.Trailer: 
       result = mapper.Map<ApplicationDriverEquipmentTrailerDomain>(infrastructure); 
       break; 

      case ApplicationDriverEquipmentTypeStaticStringsDomain.StraightTruck: 
       result = mapper.Map<ApplicationDriverEquipmentStraightTruckDomain>(infrastructure); 
       break; 

      case ApplicationDriverEquipmentTypeStaticStringsDomain.CargoVan: 
       result = mapper.Map<ApplicationDriverEquipmentCargoVanDomain>(infrastructure); 
       break; 

     } 

     return result; 
    } 

     CreateMap<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentTractorDomain>(); 
     CreateMap<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentTrailerDomain>(); 
     CreateMap<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentStraightTruckDomain>(); 
     CreateMap<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentCargoVanDomain>(); 

     CreateMap<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentAbstractDomain>() 
      .Include<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentTractorDomain>() 
      .Include<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentTrailerDomain>() 
      .Include<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentStraightTruckDomain>() 
      .Include<Infrastructure.Asset.ApplicationDriverEquipment, ApplicationDriverEquipmentCargoVanDomain>() 
      .ForMember(dest => dest.Type, opt => opt.ResolveUsing(GetEquipment)) 
      ; 

     CreateMap<Infrastructure.Asset.ApplicationDriver, ApplicationDriverDomain>() 
      .ForMember(dest => dest.Equipments, opt => opt.MapFrom(src => src.Equipments)); 

mais j'ai reçu une erreur:

"Error mapping types.\r\n\r\nMapping types:\r\nApplicationDriver -> ApplicationDriverDomain\r\nInfrastructure.Asset.ApplicationDriver -> Domain.POCO.Application.ApplicationDriverDomain\r\n\r\nType Map configuration:\r\nApplicationDriver -> ApplicationDriverDomain\r\nInfrastructure.Asset.ApplicationDriver -> Domain.POCO.Application.ApplicationDriverDomain\r\n\r\nProperty:\r\nEquipments"

+0

Qu'est-ce que AutoMapperApplicationModel? Pouvez-vous poster ce code? laissez-nous savoir la version de automapper? – Rex

+0

mais je poste le code de automapper. La version d'Automapper est 6.1.1 –

+0

https://github.com/AutoMapper/AutoMapper/wiki/Mapping-inheritance –

Répondre

0

Mise à jour:

Je crois que je comprends ce que vous essayez de faire, et des excuses je vous ai légèrement dirigé vers le bas la route incorrecte. Vous devez essentiellement distinguer l'infrastructure de l'objet source et créer ce type d'objet. Aussi, vous devez comprendre les deux manières différentes de configurer Mapper.

Dans la première partie de votre code, vous essayez de le configurer avec une instance du mappeur, puis en utilisant mon style statique d'utilisation de Mapper.Map, je recommande de toujours utiliser le style statique afin de pouvoir de faire des façons les plus dynamiques de tirer des profils de cartographie dans.

Mapper.Initialize(cfg => cfg.AddProfile<AutomapperRules>()); 
var domain = Mapper.Map<Domain.ApplicationDriverEquipmentTractorDomain>(inf); 

Ensuite, vous avez seulement besoin de faire référence à ce type de cartographie de la source sous-jacente aux types de domaine dans votre profil-à-dire

CreateMap<ApplicationDriverEquipmentInfrastructure, ApplicationDriverEquipmentTractorDomain>(); 
CreateMap<ApplicationDriverEquipmentInfrastructure, ApplicationDriverEquipmentTrailerDomain>(); 
CreateMap<ApplicationDriverEquipmentInfrastructure, ApplicationDriverEquipmentStraightTruckDomain>(); 
CreateMap<ApplicationDriverEquipmentInfrastructure, ApplicationDriverEquipmentCargoVanDomain>(); 

Alors qu'est-ce vous devez faire est d'appeler votre GetEquipment procédé de la cartographie qui décrit le ApplicationDriver à-dire

CreateMap<ApplicationDriver, ApplicationDriverDomain>() 
      .ForMember(dest => dest.Equipments, opt => opt.ResolveUsing(x => x.Equipments.Select(GetEquipment))); 

private ApplicationDriverEquipmentAbstractDomain GetEquipment(ApplicationDriverEquipmentInfrastructure infrastructure) 
    { 
     switch (infrastructure.Type) 
     { 
      case "Tractor": 
       return Mapper.Map<ApplicationDriverEquipmentTractorDomain>(infrastructure); 
      case "Trailer": 
       return Mapper.Map<ApplicationDriverEquipmentTrailerDomain>(infrastructure); 
      case "StraightTruck": 
       return Mapper.Map<ApplicationDriverEquipmentStraightTruckDomain>(infrastructure); 
      case "CargoVan": 
       return Mapper.Map<ApplicationDriverEquipmentCargoVanDomain>(infrastructure); 
     } 
     return null; 
    } 

Exemple d'utilisation:

Mapper.Initialize(cfg => cfg.AddProfile<AutomapperRules>()); 

var inf = new ApplicationDriverEquipmentInfrastructure() 
{ 
    CurrentMileage = "mil", 
    Length = "123", 
    Make = "ccc", 
    Model = "15", 
    Type = "Tractor", 
    VINNumber = "vin" 
}; 

var driver = new ApplicationDriver() 
{ 
    Equipments = new List<ApplicationDriverEquipmentInfrastructure>() {inf} 
}; 

var domain = Mapper.Map<ApplicationDriverDomain>(driver); 
+0

NullReferenceException: Référence d'objet non définie sur une instance d'un objet. avec la même erreur interne –

+0

Pourriez-vous fournir plus d'informations/peut-être une référence au repo github pour cela aussi, car cela pourrait être la façon dont tout est configuré. – codeplay

+0

https: // github.com/oshastitko/automapperInheritance –

0

Inheritance AM fonctionne en vérifiant le type de la source, et non pas à l'aide d'un discriminateur. C'est ce que vous étiez censé comprendre des docs. Une façon de résoudre votre problème consiste à transmettre une destination existante à Map. Créé par smth comme la méthode GetEquipment que vous avez là. ApplyBaseMapping est un hack, vous utilisez Include/IncludeBase pour réutiliser la configuration. Malheureusement, vous avez également corrigé un bogue déjà corrigé dans la version MyGet, la véritable erreur était donc cachée. La seule façon de déboguer ceci dans votre version est en vérifiant the execution plan.