AutoMapper vs ValueInjecter [geschlossen]

209

Jedes Mal, wenn ich auf StackOverflow nach AutoMapper-Inhalten suche, lese ich etwas über ValueInjecter .

Kann mir jemand die Vor- und Nachteile zwischen ihnen erklären (Leistung, Funktionen, API-Nutzung, Erweiterbarkeit, Tests)?

Rookian
quelle
2
Ein anderer, den ich oft erwähnt sehe, ist EmitMapper .
Adrianbanks
1
Was ist mit Kleber? glue.codeplex.com Sieht auch nach einem großartigen Projekt aus, aber ich habe es noch nicht ausprobiert. Ich werde es aber im nächsten Monat tun. Ich habe auch ein Projekt namens EmitMapper emitmapper.codeplex.com gesehen
Trygve
Lesen
George Birbilis

Antworten:

170

Als Schöpfer von ValueInjecter kann ich Ihnen sagen, dass ich es getan habe, weil ich etwas Einfaches und sehr Flexibles wollte

Ich schreibe wirklich nicht viel oder schreibe viel monkey codewie:

Prop1.Ignore, Prop2.Ignore etc.
CreateMap<Foo,Bar>(); CreateMap<Tomato, Potato>(); etc.

ValueInjecter ist so etwas wie Mozilla mit seinen Plugins. Sie erstellen ValueInjections und verwenden sie

Es gibt integrierte Injektionen zum Abflachen, Abflachen und einige, die vererbt werden sollen

und es funktioniert mehr in einer Art Aspekt , Sie müssen nicht alle Eigenschaften 1-zu-1 angeben, sondern Sie tun etwas wie:

Nehmen Sie alle int-Eigenschaften aus der Quelle, deren Name mit "Id" endet, transformieren Sie den Wert und setzen Sie jede auf eine Eigenschaft im Quellobjekt mit demselben Namen ohne das ID-Suffix, und der Typ wird von Entity geerbt

Ein offensichtlicher Unterschied ist, dass ValueInjecter auch in Windows-Formularen mit Abflachung und Abflachung verwendet wird. So flexibel ist es

(Zuordnung von Objekt zu Formularsteuerelementen und zurück)

Automapper, nicht in Windows-Formularen verwendbar, kein Unflatenning, aber es gibt gute Dinge wie das Zuordnen von Sammlungen. Wenn Sie es also mit ValueInjecter benötigen, tun Sie einfach Folgendes:

foos.Select(o => new Bar().InjectFrom(o));

Sie können ValueInjecter auch verwenden, um anonyme und dynamische Objekte zuzuordnen

Unterschiede:

  • Automapper erstellen Konfiguration für jede Mapping-Möglichkeit CreateMap ()

  • valueeinjecter injiziert von einem Objekt zu einem beliebigen Objekt (es gibt auch Fälle, in denen Sie von einem Objekt zu einem Werttyp injizieren)

  • Automapper hat es abgeflacht, und zwar nur für einfache Typen oder vom selben Typ, und es hat keine Abflachung

  • valueeinjecter nur dann, wenn Sie es brauchen target.InjectFrom<FlatLoopValueInjection>(source); also <UnflatLoopValueInjection> und wenn Sie möchten Foo.Bar.Name of type String, FooBarName of type Class1erben Sie FlatLoopValueInjection und geben Sie dies an

  • Automapper ordnet standardmäßig Eigenschaften mit demselben Namen zu. Im Übrigen müssen Sie eine nach der anderen angeben und Dinge wie Prop1.Ignore (), Prop2.Ignore () usw. ausführen.

  • valueeinjecter hat eine Standardinjektion .InjectFrom (), die die Eigenschaften mit demselben Namen und Typ ausführt. Für alles andere erstellen Sie Ihre benutzerdefinierten Wertinjektionen mit individuellen Zuordnungslogiken / -regeln, die eher Aspekten ähneln, z. B. von allen Requisiten vom Typ Foo bis zu allen Requisiten vom Typ Bar

Omu
quelle
5
Für den Liebesgott sagen Sie mir bitte, dass ValueInjector ein Deep Graph ViewModel und eine Zuordnung zu / von einem Deep Graph Business Entity erstellen und alles abbilden kann, was ohne Arbeit genau gleich ist und dass ich nur angeben muss, wie mit dem, was anders ist, umzugehen ist. Ich hatte gehofft, AutoMapper würde diese Funktion hinzufügen, aber sie ist nie zustande gekommen und ich hatte keine Zeit, meinen eigenen Auto-Mapper zu schreiben.
Chris Marisic
3
@Chris Marisic Sie können es verwenden, falls Sie tiefes Klonen meinen, ich habe einmal eine Injektion durchgeführt, die dies irgendwie rekursiv ausführt , aber nicht für die Sammlungseigenschaften valueeinjecter.codeplex.com/Thread/View.aspx?ThreadId=236126 funktioniert , oder Sie können ein Flat ViewModel machen und die Abflachung und Abflachung verwenden, das wäre einfach
Omu
Das ViewModel und die Domain Entities wären ähnlich, aber unterschiedlich, also kein reiner Klon. 90% der Eigenschaften sind in der Regel exakter Typ und Name. ViewModels enthalten häufig SelectLists und damit verbundene Dinge, die ich ignorieren möchte, wenn ich zur Domain zurückkehre. Auf beiden befindet sich jedoch sehr wahrscheinlich eine Sammlung von Objekten.
Chris Marisic
27
<pedant>Sieht cool aus, aber vielleicht sollte es ValueInjectOr sein? </pedant>
Craig Stuntz
1
aber aus irgendeinem Grund ist es äh :)
Omu
59

Da ich noch nie eines der anderen Tools verwendet habe, kann ich nur über AutoMapper sprechen. Ich hatte ein paar Ziele vor Augen, um AutoMapper zu erstellen:

  • Unterstützt das Abflachen für dumme DTO-Objekte
  • Unterstützen Sie sofort einsatzbereite offensichtliche Szenarien (Sammlungen, Aufzählungen usw.)
  • Sie können Zuordnungen in einem Test einfach überprüfen
  • Lassen Sie Randfälle zu, um Werte von anderen Stellen aufzulösen (benutzerdefinierte Typ-> Typzuordnung, Zuordnung einzelner Elemente und einige wirklich verrückte Randfälle).

Wenn Sie diese Dinge tun möchten, funktioniert AutoMapper sehr gut für Sie. Dinge, die AutoMapper nicht gut macht, sind:

  • Vorhandene Objekte füllen
  • Abflachen

Der Grund dafür ist, dass ich diese Dinge nie tun musste. Zum größten Teil haben unsere Entitäten keine Setter, machen keine Sammlungen verfügbar usw. Deshalb ist es nicht da. Wir verwenden AutoMapper, um DTOs zu reduzieren und von UI-Modellen Befehlsnachrichten und dergleichen zuzuordnen. Dort funktioniert es wirklich sehr, sehr gut für uns.

Jimmy Bogard
quelle
1
@ Jimmy Bogard Sehen Sie, dass das Füllen vorhandener Objekte jemals in die Feature-Liste für AutoMapper gelangen würde?
Roman
Ich habe ValueInjecter noch nicht ausprobiert, aber für das, was wir gebraucht haben, ist Automapper sehr leistungsfähig.
richb01
Ich denke, das Wichtigste hier ist die Überprüfbarkeit. Beim Umbenennen und Umgestalten von Dingen ist dies eine große Hilfe.
Kugel
55

Ich habe beides ausprobiert und bevorzuge ValueInjecter, weil es so einfach ist:

myObject.InjectFrom(otherObject);

Das ist alles, was ich für die überwiegende Mehrheit meiner Injektionsbedürfnisse wissen muss. Einfacher und eleganter geht es nicht.

Adrian Grigore
quelle
1
this objectErweiterungsmethode dort?
Chris Marisic
2
Wie kann ich meinen Code von ValueInjecter entkoppeln? Für mich scheint es immer eine Abhängigkeit von ValueInjecter zu haben, dh in meinem Webprojekt, da ich DIREKT ValueInjecter (Erweiterungsmethode) für das angegebene Objekt verwende.
Rookian
1
@Rookian ehrlich gesagt ist dies kein Problem, über das Sie zu viel nachdenken sollten. Sie können sich auf die Schnittstelle wie @Omu verlassen. Wenn Sie also die Mapper ändern, sparen Sie möglicherweise Arbeit (wahrscheinlich nicht viel). Diese Art von Abhängigkeit ist einfach zu schwer zu abstrahieren, es sei denn, Sie möchten sich mit AOP befassen, was leider oft nur rückgängig gemacht werden kann, da .NET nicht dazu beiträgt, AOP-Unterstützung korrekt bereitzustellen. Jetzt können Sie einen Teil der Zuordnung AOP entfernen, insbesondere wenn Sie MVC verwenden und Aktionsfilter schreiben, die die ViewModel / DomainModel-Zuordnung verarbeiten.
Chris Marisic
13
Warum ist ein Wrapper die beste Lösung? Das einzige, was Sie tun müssen, wenn Sie den Mapper wechseln möchten, ist, die InjectFrom()Erweiterungsmethode selbst zu implementieren .
Jgauffin
1
Ich habe auch beides ausprobiert und bevorzuge AutoMapper. Ich habe es für einen kleinen Teil meines Systems verwendet, in dem ich Entitäten mit von Linq2Sql generierten Klassen zuordne. Die einfache Zuordnung als StockTotalQuantity -> stock_size_quantity oder UserId -> user_id funktionierte standardmäßig mit AutoMapper. Mit ValeInjecter funktionierte es auch nach dem Hinzufügen von Convetion nicht. Halten Sie sich vorerst an AutoMapper.
Artur Kędzior
27

Dies ist eine Frage, die ich auch untersucht habe, und für meinen Anwendungsfall scheint es zweifellos ein Wertinjektor zu sein. Die Verwendung erfordert keine vorherige Einrichtung (kann die Leistung beeinträchtigen, obwohl sie bei intelligenter Implementierung die Zuordnungen für zukünftige Aufrufe zwischenspeichern könnte, anstatt sie jedes Mal wiederzugeben), sodass Sie vor der Verwendung keine Zuordnungen vordefinieren müssen.

Am wichtigsten ist jedoch, dass es eine umgekehrte Zuordnung ermöglicht. Jetzt fehlt mir hier möglicherweise etwas, da Jimmy erwähnt, dass er keinen Anwendungsfall sieht, wo dies erforderlich ist. Vielleicht habe ich das falsche Muster, aber mein Anwendungsfall ist, dass ich ein ViewModel-Objekt aus meinem ORM erstelle. Ich zeige dies dann auf meiner Webseite an. Wenn der Benutzer fertig ist, erhalte ich das ViewModel wieder als httppost. Wie wird es wieder in die ursprünglichen ORM-Klassen konvertiert? Ich würde gerne das Muster mit Automapper kennen. Mit ValueInjector ist es trivial und wird sogar abgeflacht. zB Erstellen einer neuen Entität

Das vom Entityframework erstellte Modell (Modell zuerst):

public partial class Family
{ 
    public int Id { get; set; }
    public string FamilyName { get; set; }

    public virtual Address Address { get; set; }
}

public partial class Address
{
    public int Id { get; set; }
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string TownCity { get; set; }
    public string County { get; set; }
    public string Postcode { get; set; }

    public virtual Family Family { get; set; }
}

Das ViewModel (das ich mit Validatoren dekorieren kann):

public class FamilyViewModel
{
    public int Id { get; set; }
    public string FamilyName { get; set; }

    public int AddressId { get; set; }
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string AddressTownCity { get; set; }
    public string AddressCounty { get; set; }
    public string AddressPostcode { get; set; }
}

Der ViewController:

    //
    // GET: /Family/Create

    public ActionResult Create()
    {
        return View();
    } 

    //
    // POST: /Family/Create

    [HttpPost]
    public ActionResult Create(FamilyViewModel familyViewModel)
    {
        try
        {
            Family family = new Family();
            family.InjectFrom<UnflatLoopValueInjection>(familyViewModel);
            db.Families.Add(family);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

Einfacher geht es meiner Meinung nach nicht?

(Das wirft also die Frage auf, was ist falsch an dem Muster, auf das ich stoße (und es scheint, dass viele andere dies tun), dass es für AutoMapper nicht als wertvoll angesehen wird?)

Wenn Sie dieses Muster jedoch als beschrieben verwenden möchten, ist meine Stimme ein Wert für eine Landmeile.

DanH
quelle
1
Wahrscheinlich sollten Sie dies auch in einer separaten Frage stellen, die mit asp.net-mvc und Best Practices, ViewModel ..., gekennzeichnet ist. atm Ich sehe kein Problem, solange es für Sie gut funktioniert, aber ich bin mir sicher, dass jemand könnte andere Meinungen haben
Omu
Nun, ich habe mehr mvc gelernt. Ich kann jetzt meine Frage beantworten. Die Möglichkeit, das ursprüngliche Modell zu aktualisieren, wenn Sie ein ausgefülltes Ansichtsmodell zurückerhalten, besteht in der Verwendung der UpdateModel () -Funktion, die mvc bereitstellt.
DanH
1
UpdateModel () wird verwendet, um das Modell zu füllen, das die Ansicht darstellt, und entspricht der Ausführung von Action (MyModelClasss-Modell)
Omu
Richtig, aber wenn Sie ein separates Ansichtsmodell für beispielsweise ein Respository-Modell haben möchten, können Sie damit festlegen, dass die Zuordnung trivial ist (und dies häufig der Fall ist). Natürlich, wenn der komplexere ValueInjector zur Geltung kommt.
DanH
1
Ich denke, man könnte argumentieren, dass Sie Ihre Eigenschaften nicht einfach auf Ihr Domain-Modell zurücksetzen sollten - Sie sollten Methoden verwenden, die ihm Bedeutung verleihen.
Mike Cole