Automapper:使用 Entity Framework 4 Proxy Pocos 在集合上的繼承和抽象基類映射問題
我在使用 AutoMapper(這是一項出色的技術)將業務對象映射到 DTO 時遇到問題,在該 DTO 中我繼承了集合中的抽象基類。
這是我的對象:
abstract class Payment class CashPayment : Payment class CreditCardPayment : Payment我還有一個發票對象,其中包含一組付款,如下所示:
public class Invoice { ... properties... public ICollection<Payment> Payments { get; set; } }我也有每個這些對象的相應 DTO 版本。
DtoInvoice 對象定義為:
[DataContract] public class DtoInvoice { ...properties... [DataMember] public List<DtoPayment> Payments { get; set; } }這就是我的 Mapper 定義的樣子:
Mapper.CreateMap<Invoice, DtoInvoice>(); Mapper.CreateMap<Payment, DtoPayment>() .Include<CashPayment, DtoCashPayment>() .Include<CreditCardPayment, DtoCreditCardPayment>(); Mapper.CreateMap<CashPayment, DtoCashPayment>(); Mapper.CreateMap<CreditCardPayment, DtoCreditCardPayment>();執行映射的程式碼如下所示:
var invoice = repo.GetInvoice(invoiceId); var dtoInvoice = Mapper.Map<Invoice, DtoInvoice>(invoice);因此,例如,如果我的發票對象包含一組特定付款(例如 1 筆現金和 1 張信用卡),當映射器嘗試映射它們時,我會收到無法創建抽像類 Payment 的錯誤。如果我從 Payment 對像中刪除了 abstract 關鍵字,那麼程式碼就可以工作,但我只得到了 Payment 對象的集合,我沒有得到它們的特定對象(現金和信用卡支付)。
所以問題是:如何讓 AutoMapper 映射特定的支付類型而不是基類?
更新
我做了更多的探勘,並認為我發現了一個問題,但不確定如何使用 AutoMapper 解決這個問題。我認為這更像是 EF 的事情,而不是 AutoMapper 的錯。:-)
在我的程式碼中,我使用延遲載入的實體框架 4 代理 POCO。
因此,當我嘗試映射從 EF 返回的作為代理 POCO 的實體時,它會得到看起來很有趣的類型,例如:
System.Data.Entity.DynamicProxies.CashPayment_86783D165755C316A2F58A4343EEC4842907C5539AF24F0E64AEF498B15105C2所以我的理論是,當 AutoMapper 嘗試將 CashPayment 映射到 DtoCashPayment 並且傳入的付款是代理類型時,AutoMapper 將其視為“不匹配”,然後映射通用付款類型。但由於 Payment 是一個抽像類 AutoMapper,因此會出現“System.InvalidOperationException:無法創建抽像類的實例”。例外。
所以問題是:有沒有辦法讓我使用 AutoMapper 將 EF POCO 代理對象映射到 Dtos。
這個答案來得有點晚,因為我剛剛遇到了與 EF4 POCO 代理相同的問題。
我使用自定義轉換器解決了它,該轉換器呼叫
Mapper.DynamicMap<TDestination>(object source)呼叫執行時類型轉換,而不是.Include<TOtherSource, TOtherDestinatio>().這對我來說可以。
在您的情況下,您將定義以下轉換器:
class PaymentConverter : ITypeConverter<Payment, DtoPayment> { public DtoPayment Convert( ResolutionContext context ) { return Mapper.DynamicMap<DtoPayment>( context.SourceValue ); } }然後:
Mapper.CreateMap<Payment, DtoPayment>().ConvertUsing<PaymentConverter>(); Mapper.CreateMap<CashPayment, DtoCashPayment>(); Mapper.CreateMap<CreditCardPayment, DtoCreditCardPayment>();