Automapper: Zuordnungsproblem mit Vererbung und abstrakter Basisklasse in Sammlungen mit Entity Framework 4 Proxy Pocos

.net automapper collections entity-framework poco

Frage

Ich habe ein Problem mit AutoMapper (eine hervorragende Technologie), um ein Geschäftsobjekt einem DTO zuzuordnen, bei dem ich eine abstrakte Basisklasse innerhalb einer Sammlung vererbt.

Hier sind meine Objekte:

abstract class Payment
class CashPayment : Payment
class CreditCardPayment : Payment

Ich habe auch ein Rechnungsobjekt, das eine Sammlung von Zahlungen wie folgt enthält:

    public class Invoice
    {
       ... properties...

       public ICollection<Payment> Payments { get; set; }
    }

Ich habe auch entsprechende DTO-Versionen von jedem dieser Objekte.

Das DtoInvoice-Objekt ist definiert als:

[DataContract]
public class DtoInvoice
{
   ...properties...

   [DataMember]
   public List<DtoPayment> Payments { get; set; }
}

So sehen meine Mapper-Definitionen aus:

Mapper.CreateMap<Invoice, DtoInvoice>();

Mapper.CreateMap<Payment, DtoPayment>()
  .Include<CashPayment, DtoCashPayment>()
  .Include<CreditCardPayment, DtoCreditCardPayment>();

Mapper.CreateMap<CashPayment, DtoCashPayment>();
Mapper.CreateMap<CreditCardPayment, DtoCreditCardPayment>();

Der Code für das Mapping sieht folgendermaßen aus:

var invoice = repo.GetInvoice(invoiceId);

var dtoInvoice = Mapper.Map<Invoice, DtoInvoice>(invoice);

Wenn mein Rechnungsobjekt beispielsweise eine Sammlung bestimmter Zahlungen enthält (z. B. 1 Bargeld und 1 Kreditkarte), wenn der Mapper versucht, diese abzubilden, wird die Fehlermeldung angezeigt, dass die abstrakte Klasse "Zahlung" nicht erstellt werden kann. Wenn ich das abstrakte Schlüsselwort aus dem Payment-Objekt entferne, funktioniert der Code, aber ich bekomme nur eine Sammlung von Payment-Objekten. Ich erhalte keine spezifischen Objekte (Cash & Credit Card-Zahlungen).

Die Frage ist also: Wie kann ich AutoMapper dazu bringen, die spezifischen Zahlungsarten und nicht die Basisklasse abzubilden?


Aktualisieren

Ich habe noch ein wenig gegraben und denke, ich sehe ein Problem, bin mir aber nicht sicher, wie ich das mit AutoMapper lösen kann. Ich denke, das ist eher eine EF-Sache und nicht die Schuld von AutoMapper. :-)

In meinem Code verwende ich Entity Framework 4 Proxy-POCOs mit verzögertem Laden.

Wenn ich also versuche, eine von EF zurückgegebene Entität, die ein Proxy-POCO ist, abzubilden, wird dieser komische Typ wie folgt angezeigt:

System.Data.Entity.DynamicProxies.CashPayment_86783D165755C316A2F58A4343EEC4842907C5539AF24F0E64AEF498B15105C2

Meine Theorie ist also, dass, wenn AutoMapper versucht, CashPayment zu DtoCashPayment abzubilden, die übergebene Zahlung vom Proxy-Typ ist. AutoMapper sieht es als "nicht übereinstimmend" und ordnet dann den allgemeinen Zahlungstyp zu. Da Payment jedoch eine abstrakte Klasse ist, werden AutoMapper-Bomben mit einer "System.InvalidOperationException: Instanzen abstrakter Klassen können nicht erstellt werden". Ausnahme.

Die Frage ist also: Gibt es eine Möglichkeit für mich, AutoMapper zu verwenden, um EF-POCO-Proxy-Objekte zu Dtos zuzuordnen.

Akzeptierte Antwort

Diese Antwort kommt etwas später, da ich gerade mit EF4-POCO-Proxies das gleiche Problem hatte.

Ich habe es mit einem benutzerdefinierten Konverter gelöst, der Mapper.DynamicMap<TDestination>(object source) , um die Laufzeittypkonvertierung aufzurufen, und nicht die .Include<TOtherSource, TOtherDestinatio>() .

Es funktioniert gut für mich.

In Ihrem Fall würden Sie den folgenden Konverter definieren:

class PaymentConverter : ITypeConverter<Payment, DtoPayment> {
    public DtoPayment Convert( ResolutionContext context ) {
        return Mapper.DynamicMap<DtoPayment>( context.SourceValue );
    }
}

Und dann:

Mapper.CreateMap<Payment, DtoPayment>().ConvertUsing<PaymentConverter>();
Mapper.CreateMap<CashPayment, DtoCashPayment>();
Mapper.CreateMap<CreditCardPayment, DtoCreditCardPayment>();

Beliebte Antwort

Ich habe auch Oliviers Beispiel ausprobiert und die gleichen StackOverflow-Fehler erhalten. Ich habe auch die Lösung von Subkamran ausprobiert, aber dort kein Glück, da ich keine Basisklasse aus der Entity Model Code-Generierung verwende. Automapper sprengt immer noch. Bis ich eine bessere Lösung gefunden habe, stelle ich einfach den Kontext so ein, dass beim Erstellen eines Kontextobjekts keine Proxies erstellt werden.

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

Ich hätte auch gerne eine Antwort auf das Problem, wenn ich etwas in Automapper einbaue ...

UPDATE: Die Vorabversion von Automapper behebt dieses Problem und ermöglicht es dem Mapping, einen DynamicProxy ohne zusätzliche Konfiguration abzudecken.

Das Release, in dem diese Version läuft, ist 2.2.1



Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum
Lizenziert unter: CC-BY-SA with attribution
Nicht verbunden mit Stack Overflow
Ist diese KB legal? Ja, lerne warum