.net - when - wpf automapper




Automapper:Entity Framework 4 Proxy Pocosを使用してコレクションの継承と抽象基本クラスのマッピング問題 (4)

私は、AutoMapper(優れた技術)を使用して、ビジネスオブジェクトを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オブジェクトから削除すると、コードは機能しますが、支払いオブジェクトのコレクションしか取得できません。特定のオブジェクト(現金とクレジットカードの支払い)を取得しません。

つまり、問題は次のとおりです。AutoMapperにどのようにして基本クラスではなく特定の支払いタイプをマッピングさせることができますか?

更新

私はもう少し掘り下げて、問題があると思っていますが、AutoMapperでこれをどのように解決できるかはわかりません。 私はこれがEFのものであり、AutoMapperのせいではないと思う。 :-)

私のコードでは、遅延読み込みでEntity Framework 4 Proxy POCOを使用しています。

したがって、プロキシPOCOであるEFから返されたエンティティをマップしようとすると、次のような面白い探しの型が得られます。

System.Data.Entity.DynamicProxies.CashPayment_86783D165755C316A2F58A4343EEC4842907C5539AF24F0E64AEF498B15105C2

だから私の理論は、AutoMapperがCashPaymentをDtoCashPaymentにマップしようとしたときに渡された支払いがプロキシタイプのものであるということです.OutMapperはそれを「不一致」と見なして、一般的な支払いタイプをマッピングします。 しかし、Paymentは抽象クラスのAutoMapperの爆弾であるため、 "System.InvalidOperationException:抽象クラスのインスタンスを作成できません。" 例外。

ですから問題は:AutoMapperを使ってEF POCOプロキシオブジェクトをDtosにマップする方法があるかどうかです。


Entity Frameworkプロキシで同じ問題が発生しましたが、AutoMapperのプレリリース版に切り替える必要はありませんでした。 私はバージョン2.2.0の場合、少し醜い回避策を見つけました。 私はDTOから既存のEFプロキシオブジェクトに移行しようとしていましたが、醜いプロキシクラス名のマッピングがないというエラーが発生しました。 私の解決策は、私が手動でマッピングした指定された実際の具体的な型のオーバーロードを使用することでした:

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

Olivierの反応を踏まえて、私は自分の状況で彼を働かせることができませんでした...それは無限ループを続け、Exceptionをスローしました。

この例では、 AbstractClassは私の基底クラスであり、 AbstractViewModelは私の基本ビューモデルです( abstract気持ちではありません)。

しかし、私はそれをこのhackish見た目のコンバータを使用して動作させる:

    public class ProxyConverter<TSource, TDestination> : ITypeConverter<TSource, TDestination>
        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<AbstractClass, AbstractViewModel>()
        .ConvertUsing(new ProxyConverter<AbstractClass, AbstractViewModel>());

したがって、 DerivedClassAは通常どおりにマッピングされますが、 DynamicProxy_xxxもこのコードが基底型( DerivedClassA )を検査するときに正しくマップされます。

してください、私はこのクレイジールックアップの駄目をする必要はないことを私に教えてください。 Olivierの答えを正しく修正するのに十分なAutoMapperについて知りません。


私は、動的EFプロキシをMVCアプリケーションのViewModelsにマッピングするのと同じ問題に直面しました。

私はこの問題に対してMapper.DynamicMap()を使って簡単な解決策を見つけました。 ここに私のコードです:

動的プロキシからViewModelクラスへの変換:

// dynamic proxy instance
WebService webService = _repWebService.GetAll().SingleOrDefault(x => x.Id == id);

//mapping
FirstStepWebServiceModel model = Mapper.DynamicMap<FirstStepWebServiceModel>(webService);

ViewModelクラスからEF Dynamic Proxyへの変換:

[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);
}

この例があなたに役立つことを願って


私もOlivierの例を試して、同じエラーが発生しました。 私はサブカムランのソリューションも試しましたが、エンティティモデルのコード生成からベースクラスを使用していないので、そこに運がありません。 Automapperはまだ爆破する。 より良い解決策が見つかるまで、私はContextオブジェクトを作成するときにContextを使ってプロキシを作成しないようにしました。

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

私はまた、Automapperに何かを組み込んで、おそらくこの問題への答えを見たいと思っています...

更新:Automapperのプレリリースではこの問題が修正され、余分な構成を必要とせずにDynamicProxyをカバーするマッピングが可能になりました。

これが動作するリリースは2.2.1です







automapper