-1

I'm using an automapper to flatten the object coming from WS. Simplified model would be as follows:

public abstract class AOrder {
    public Product Product {get;set;}
    public decimal Amount {get;set;}
    //number of other properties
}

public abstract class Product {
    //product properties
}
public class RatedProduct : Product {
   public int Rate { get;set;}
}

public class MarketOrder : AOrder {
    //some specific market order properties
}

Using automapper I'm trying to flatten this into:

public class OrderEntity {
   public decimal Amount {get;set;}
   public int ProductRate {get;set;}
}

with next mapping:

CreateMap<RatedProduct, OrderEntity>();
CreateMap<MarketOrder, OrderEntity>();

The above mapping will not map the ProductRate. Atm I've just used the AfterMap:

CreateMap<MarketOrder, OrderEntity>()
    .AfterMap((s,d) => {
         var prod = s.Product as RatedProduct;
         if (prod != null) 
         {
             //map fields
         }
     });

which works pretty well, but thought if I could reuse the automapper flattening possibilities (i.e. matching by name) I wouldn't need to apply the after map in quite many places.

Note: I can't change the WS and this is just a tiny part from object hierarchy.

Advice appreciated.

Alex M
  • 2,410
  • 1
  • 24
  • 37
  • 1
    This is not "polymorphism" as polymorphic properties would imply that that base type has a method or property defined and the children implement it.... and when you call the method/property on the base class reference the specific type was actually used. In your case the base class doesn't have the property...and you need to do a downcast. So it is with downcasting as there is no polymorphism. – John Sobolewski May 08 '13 at 12:32
  • @jsobo, I need to map all the properties from `abstract Product` into `RatedProduct` as well. One might insist on proper usage of subtype polymorphism, so therefore I followed your note and changed the header. – Alex M May 08 '13 at 13:36

1 Answers1

1

Mapping Rate to ProductRate is fairly straight forward with "ForMember"

The one where you have to do a cast to the specific type to see if it is that type is a little trickier but I think the same approach you took is what you might have to do however I don't think you need to do "aftermap". I thought all your destination mappings had to be found OR you need to mark them as ignore of the mapping will fail.

Another thing you could do is just change the OrderEntity.ProductRate to be OrderEntity.Rate. Then it would find it and map it for you except where it was hidden because Product doesn't have a rate (but RatedProducts do).

public class OrderEntity {
   public decimal Amount {get;set;}
   public int Rate {get;set;}  //changed name from ProductRate to just Rate.
}

 Mapper.CreateMap<Product, OrderEntity>()
    .Include<RatedProduct, OrderEntry>();

 Mapper.CreateMap<RatedProduct, OrderEntry>();

SEE: Polymorphic element types in collections

Alex M
  • 2,410
  • 1
  • 24
  • 37
John Sobolewski
  • 4,512
  • 1
  • 20
  • 26
  • Sorry I missed that there was a new version of automapper. I'm not 100% sure that this works now? – John Sobolewski May 08 '13 at 12:29
  • This solution is identical to one I used with AfterMap method. – Alex M May 08 '13 at 13:24
  • @Aleksey agreed however see: https://github.com/AutoMapper/AutoMapper/wiki/Lists-and-arrays I think you want to setup a child parent mapping see the section labeled "Polymorphic element types in collections" this would allow you to map things to the "product" but specify how to map it diferrently if it really was a "RatedProduct". – John Sobolewski May 08 '13 at 14:56
  • It is probably easier in this case to use AfterMap then, as at least I can abstract the functionality which maps N properties from RatedProduct to OrderEntry if Product is of RatedProduct type. Thanx for your help. – Alex M May 09 '13 at 09:22