I am having an issue using AutoMapper (which is an excellent technology) to map a business object to a DTO where I have inheritance off of an abstract base class within a collection.
Here are my objects:
abstract class Payment
class CashPayment : Payment
class CreditCardPayment : Payment
I also have an invoice object which contains a collection of payments like so:
public class Invoice
{
... properties...
public ICollection<Payment> Payments { get; set; }
}
I also have corresponding DTO versions of each of these objects.
The DtoInvoice object is defined as:
[DataContract]
public class DtoInvoice
{
...properties...
[DataMember]
public List<DtoPayment> Payments { get; set; }
}
This is what my Mapper definitions look like:
Mapper.CreateMap<Invoice, DtoInvoice>();
Mapper.CreateMap<Payment, DtoPayment>()
.Include<CashPayment, DtoCashPayment>()
.Include<CreditCardPayment, DtoCreditCardPayment>();
Mapper.CreateMap<CashPayment, DtoCashPayment>();
Mapper.CreateMap<CreditCardPayment, DtoCreditCardPayment>();
The code to perform the mapping looks like this:
var invoice = repo.GetInvoice(invoiceId);
var dtoInvoice = Mapper.Map<Invoice, DtoInvoice>(invoice);
So for example if my invoice object contains a collection of specific payments (say 1 cash and 1 credit card) when mapper tries to map them I get an error that the abstract class Payment cannot be created. If I remove the abstract keyword from the Payment object then the code works but I only get a collection of Payment object, I do not get their specific objects (Cash & Credit Card payments).
So the question is: How can I get AutoMapper to map the specific payment types and not the base class?
Update
I did some more digging and think I see a problem but am not sure how I can solve this with AutoMapper. I think this is more of an EF thing and not AutoMapper's fault. :-)
In my code I am using Entity Framework 4 Proxy POCOs with lazy loading.
So when I try to map an entity returned from EF that is a proxy POCO it gets that funny looking type like:
System.Data.Entity.DynamicProxies.CashPayment_86783D165755C316A2F58A4343EEC4842907C5539AF24F0E64AEF498B15105C2
So my theory is that when AutoMapper tries to map CashPayment to DtoCashPayment and the payment passed in is of the proxy type AutoMapper sees it as a "non match" and then maps the generic Payment type. But since Payment is an abstract class AutoMapper bombs with a "System.InvalidOperationException: Instances of abstract classes cannot be created." exception.
So the question is: Is there a way for me to use AutoMapper to map EF POCO proxy objects to Dtos.
This answer comes 'a bit' late as I've just faced the same issue with EF4 POCO proxies.
I solved it using a custom converter that calls Mapper.DynamicMap<TDestination>(object source)
to invoke the runtime type conversion, rather than the .Include<TOtherSource, TOtherDestinatio>()
.
It works fine for me.
In your case you would define the following converter:
class PaymentConverter : ITypeConverter<Payment, DtoPayment> {
public DtoPayment Convert( ResolutionContext context ) {
return Mapper.DynamicMap<DtoPayment>( context.SourceValue );
}
}
And then:
Mapper.CreateMap<Payment, DtoPayment>().ConvertUsing<PaymentConverter>();
Mapper.CreateMap<CashPayment, DtoCashPayment>();
Mapper.CreateMap<CreditCardPayment, DtoCreditCardPayment>();