AutoMapper vs ValueInjecter [zamknięte]

209

Za każdym razem, gdy szukam rzeczy AutoMapper na StackOverflow, czytam coś o ValueInjecter .

Czy ktoś może mi powiedzieć zalety i wady między nimi (wydajność, funkcje, wykorzystanie interfejsu API, rozszerzalność, testowanie)?

Rookian
źródło
2
Kolejnym, o którym często wspominałem, jest EmitMapper .
adrianbanks
1
Co z klejem? glue.codeplex.com Wygląda również na świetny projekt, ale jeszcze go nie próbowałem. Będę jednak w ciągu następnego miesiąca. Widziałem także projekt o nazwie EmitMapper emitmapper.codeplex.com
Trygve
Zobacz artykuł mówiący o tych dwóch narzędziach - devproconnections.com/development/…
George Birbilis,

Odpowiedzi:

170

jako twórca ValueInjecter mogę powiedzieć, że to zrobiłem, ponieważ chciałem czegoś prostego i bardzo elastycznego

Naprawdę nie lubię pisać dużo ani pisać monkey codetakich jak:

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

ValueInjecter to coś w rodzaju mozilli z wtyczkami, tworzysz ValueInjections i używasz ich

są wbudowane zastrzyki do spłaszczania, spłaszczania i niektóre, które mają być dziedziczone

i działa bardziej pod względem aspektu , nie musisz określać wszystkich właściwości od 1 do 1, zamiast tego robisz coś takiego:

weź wszystkie właściwości int ze źródła, którego nazwa kończy się na „Id”, przekształć wartość i ustaw każdą z nich na właściwość w obiekcie źródłowym o tej samej nazwie bez sufiksu Id, a jej typ jest dziedziczony z Entity, takie rzeczy

więc jedną oczywistą różnicą jest to, że ValueInjecter jest stosowany nawet w formach okien ze spłaszczaniem i spłaszczaniem, jest to tak elastyczne

(mapowanie od obiektu do formantów i odwrotnie)

Automapper, nieużywany w formularzach Windows, bez rozpakowywania, ale ma dobre rzeczy, takie jak mapowanie kolekcji, więc na wypadek, gdybyś potrzebował go za pomocą ValueInjecter, po prostu robisz coś takiego:

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

możesz także użyć ValueInjecter do mapowania z anonimowych i dynamicznych obiektów

różnice:

  • automapper utwórz konfigurację dla każdej możliwości mapowania CreateMap ()

  • valueinjecter wstrzykuje z dowolnego obiektu do dowolnego obiektu (zdarzają się również przypadki, gdy wstrzykujesz z obiektu na typ wartości)

  • automapper ma wbudowane spłaszczanie, i tylko dla prostych typów lub tego samego typu, i nie ma spłaszczania

  • valueinjecter tylko wtedy, gdy jest to potrzebne to zrobić target.InjectFrom<FlatLoopValueInjection>(source); also <UnflatLoopValueInjection> , a jeśli chcesz od Foo.Bar.Name of type Stringdo FooBarName of type Class1was dziedziczyć FlatLoopValueInjection i określić ten

  • automapper domyślnie odwzorowuje właściwości o tej samej nazwie, a przez resztę musisz określać jeden po drugim i robić takie rzeczy jak Prop1.Ignore (), Prop2.Ignore () itp.

  • valueinjecter ma domyślny zastrzyk .InjectFrom (), który wykonuje właściwości o tej samej nazwie i typie; dla wszystkiego innego, co tworzysz niestandardowe wtryski wartości z indywidualną logiką / regułami mapowania, bardziej podobne aspekty, np. od wszystkich rekwizytów typu Foo do wszystkich rekwizytów typu Bar

Omu
źródło
5
Dla boga miłości, proszę powiedz mi, że ValueInjector może wziąć głęboki wykres ViewModel i odwzorować na / z głębokiego wykresu Podmiot biznesowy i odwzorować wszystko, co jest dokładnie takie samo bez pracy, i że muszę tylko określić, jak radzić sobie z tym, co inne. Mam nadzieję, że AutoMapper doda tę możliwość, ale nigdy się nie zmaterializowała i nie miałem czasu na napisanie własnego auto mapera.
Chris Marisic,
3
@Chris Marisic, możesz go użyć, zrób to, jeśli masz na myśli głębokie klonowanie, zrobiłem jeden zastrzyk, gdy pewnego rodzaju robi to rekurencyjnie, ale nie działa dla właściwości kolekcji valueinjecter.codeplex.com/Thread/View.aspx?ThreadId=236126 , lub możesz zrobić Flat ViewModel i użyć spłaszczania i rozpłaszczania, byłoby to łatwe
Omu
ViewModel i jednostki domeny byłyby podobne, ale różne, więc nie byłby czystym klonem. 90% właściwości to zwykle dokładny typ i nazwa, ViewModels często kończą się na SelectLists i powiązanych z nimi rzeczach, które chciałbym zignorować wracając do domeny. Oba są jednak bardzo prawdopodobne, że mają na sobie kolekcje obiektów.
Chris Marisic
27
<pedant>Wygląda fajnie, ale może powinien to być ValueInjectOr? </pedant>
Craig Stuntz
1
ale z jakiegoś powodu to jest :)
Omu
59

Ponieważ nigdy nie korzystałem z żadnego z innych narzędzi, mogę mówić tylko o AutoMapper. Miałem kilka celów do zbudowania AutoMapper:

  • Wsparcie spłaszczania głupich obiektów DTO
  • Obsługa oczywistych scenariuszy po wyjęciu z pudełka (kolekcje, wyliczenia itp.)
  • Być w stanie łatwo zweryfikować mapowania w teście
  • Zezwalaj na przypadki krawędzi do rozpoznawania wartości z innych miejsc (niestandardowe mapowanie typu> mapowanie poszczególnych elementów i niektóre naprawdę szalone przypadki krawędzi).

Jeśli chcesz to zrobić, AutoMapper działa dla Ciebie bardzo dobrze. Co AutoMapper nie radzi sobie dobrze to:

  • Wypełnianie istniejących obiektów
  • Unflattening

Powodem jest to, że nigdy nie musiałem robić tych rzeczy. W przeważającej części nasze podmioty nie mają ustawiaczy, nie ujawniają kolekcji itp., Dlatego nie ma ich tam. Używamy AutoMapper do spłaszczania do DTO i mapowania z modeli interfejsu użytkownika w celu wydawania poleceń i tym podobnych. Właśnie tam to działa naprawdę, bardzo dobrze dla nas.

Jimmy Bogard
źródło
1
@ Jimmy Bogard Czy widzisz, że wypełnienie istniejących obiektów trafiłoby na listę funkcji AutoMapper?
Rzym,
Nie próbowałem ValueInjecter, ale do tego, czego potrzebowaliśmy, automapper jest bardzo wydajny.
richb01
Myślę, że najważniejszą rzeczą jest weryfikowalność. Jest to ogromna pomoc przy zmianie nazw i refaktoryzacji rzeczy.
Kugel
55

Próbowałem obu i wolę ValueInjecter, ponieważ jest to takie proste:

myObject.InjectFrom(otherObject);

To wszystko, co trzeba wiedzieć o ogromnej większości moich potrzeb związanych z zastrzykami. Nie może być prostszy i bardziej elegancki niż ten.

Adrian Grigore
źródło
1
this objectmetoda rozszerzenia tam?
Chris Marisic
2
Jak mogę oddzielić mój kod od ValueInjecter? Wydaje mi się, że zawsze mam zależność od ValueInjecter, tj. W moim projekcie internetowym, ponieważ używam ValueInjecter (metoda rozszerzenia) na danym obiekcie BEZPOŚREDNIO.
Rookian
1
@Rookian szczerze mówiąc, nie jest to problem, na który powinieneś zbyt dużo się zastanawiać. Możesz polegać na interfejsie, jak wspomniano @Omu, więc jeśli kiedykolwiek zmienisz program mapujący, możesz zaoszczędzić trochę pracy (prawdopodobnie niewiele). Tego rodzaju zależność jest zbyt trudna do wyodrębnienia, chyba że chcesz dostać się do pełnego AOP, co jest niestety wielokrotnie niemożliwe, ponieważ .NET nie pomaga w zapewnieniu prawidłowej obsługi AOP. Teraz możesz usunąć AOP z niektórych mapowań, szczególnie jeśli używasz MVC i piszesz Filtry akcji, które obsługują mapowanie ViewModel / DomainModel.
Chris Marisic,
13
dlaczego owijarka jest najlepszym rozwiązaniem? Jedyne, co musisz zrobić, aby przełączyć program mapujący, to samodzielnie wdrożyć InjectFrom()metodę rozszerzenia.
jgauffin
1
Próbowałem też obu i wolę AutoMapper. Użyłem go w niewielkiej części mojego systemu, w której mapuję Encje za pomocą klas wygenerowanych przez Linq2Sql. Proste mapowanie jako StockTotalQuantity -> stock_size_quantity lub UserId -> user_id domyślnie działało z AutoMapper. Nie działał z ValeInjecter, nawet po dodaniu konwekcji. Na razie trzymam się AutoMappera.
Artur Kędzior
27

To pytanie też badam, a dla mojego przypadku użycia wydaje się to bardzo przydatne. Nie wymaga wcześniejszej konfiguracji (wydaje mi się, że może obniżyć wydajność, chociaż inteligentnie zaimplementowany może buforować odwzorowania dla przyszłych wywołań, a nie odzwierciedlać za każdym razem), więc nie musisz predefiniować żadnych odwzorowań przed ich użyciem.

Najważniejsze jednak, że umożliwia odwrotne mapowanie. Teraz może coś mi brakuje, ponieważ Jimmy wspomina, że ​​nie widzi przypadku użycia, w którym jest to konieczne, więc może mam błędny wzór, ale moim przypadkiem użycia jest to, że tworzę obiekt ViewModel z mojej ORM. Następnie wyświetlam to na mojej stronie internetowej. Kiedy użytkownik skończy otrzymam ViewModel z powrotem jako httppost, w jaki sposób zostanie to przekonwertowane z powrotem do oryginalnych klas ORM? Chciałbym poznać wzór z automapper. Z ValueInjector jest to banalne, a nawet się spłaszczy. np. Utworzenie nowego bytu

Model utworzony przez bytframework (najpierw model):

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

ViewModel (który mogę ozdobić za pomocą walidatorów):

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

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

Moim zdaniem nie jest to prostsze?

(To nasuwa pytanie, co jest nie tak ze wzorcem, na który się natknąłem (i wydaje się, że robi to wielu innych), że nie jest postrzegane jako wartość dla AutoMapper?)

Jeśli jednak ten wzór, jak opisano, jest tym, którego chcesz użyć, to mój głos jest wartościowy w przeliczeniu na milę kraju.

DanH
źródło
1
prawdopodobnie powinieneś zadać to również w osobnym pytaniu oznaczonym asp.net-mvc i najlepszymi praktykami, ViewModel ..., atm Nie widzę żadnego problemu, o ile działa dobrze dla ciebie, ale jestem pewien, że ktoś może mieć inne opinie
Omu
Dobrze, że nauczyłem się więcej mvc. Mogę teraz odpowiedzieć na moje pytanie. Aby zaktualizować oryginalny model po odzyskaniu zapełnionego modelu widoku, należy użyć funkcji UpdateModel (), którą zapewnia mvc.
DanH,
1
UpdateModel () służy do wypełnienia modelu reprezentującego widok i jest tym samym, co wykonywanie akcji (model MyModelClasss)
Omu
To prawda, ale jeśli chcesz mieć oddzielny model widoku, na przykład model repozytorium, można go użyć do wypełnienia założenia, że ​​mapowanie jest trywialne (i często tak jest). Oczywiście, jeśli bardziej skomplikowany ValueInjector sam się sprawdzi.
DanH
1
Myślę, że można argumentować, że nie powinieneś po prostu przywracać swoich właściwości do modelu domeny - powinieneś użyć metod, które dodają mu znaczenia.
Mike Cole,