AutoMapper – konfiguracja
Zmniejszanie bólu mapowania


AutoMapper powstał, aby rozwiązać dość popularny problem z mapowaniem klas. W znacznej większości projektów pojawiają się warstwy i związane z nimi DTOsy (Data Transfer Object). Mapowanie polega na przepisaniu wartości pól z jednej klasy do nowego obiektu o innym typie, np. z PersonDataAccessObject do PersonDataTransferObject. Dzięki temu zostaje zachowana jedna z podstawowych zasad programowania obiektowego – hermetyzacja – bo PersonDataAccessObject może pozostać prywatną klasą, a udostępnione zostanie jedynie nowe “pudełko” na dane. AutoMapper jest potężnym narzędziem, a mimo to jego instalacja jest banalnie prosta.
Szybka instalacja
Przy korzystaniu z .NET Core potrzebujemy dwóch NuGetów: AutoMapper i AutoMapper.Extensions.Microsoft.DependencyInjection. Następnie warto utworzyć plik, gdzie będą znajdować się nasze mapowania:
public class MappingProfile : Profile { public MappingProfile() { CreateMap<Food, FoodDto>(); } }
Oraz dodać jedną linijkę w konfiguracji serwisów w Startup.cs
public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddAutoMapper(x => x.AddProfile<MappingProfile>(), typeof(Startup)); }
Teraz możemy już wstrzykiwać mapper w miejscu, gdzie go potrzebujemy i wywoływać metodę Map, podając typ docelowy oraz obiekt wejściowy do przemapowania:
public class IndexModel : PageModel { private readonly IMapper _mapper; public IndexModel(IMapper mapper) { _mapper = mapper; } public void OnGet() { var food = new Food { Name = "Sernik" }; var dto = _mapper.Map<FoodDto>(food); } }
Precyzyjne mapowanie
Domyślnie wszystkie wartości gdzie zgadzają się typy i nazwy zostaną przepisane. Możemy jednak w miejscu tworzenia map dopisać własne zachowanie, jeśli coś ma zachowywać się w inny sposób, albo przepisywać się do dodatkowych pól:
public class MappingProfile : Profile { public MappingProfile() { CreateMap<Food, FoodDto>() .ForMember(dest => dest.TotalIngredientsWeight, x => x.MapFrom(src => src.Ingredients.Sum(x => x.Value))); } }

Warto by też utworzyć test jednostkowy sprawdzający, czy nasze mapowania są poprawne. Na szczęście AutoMapper posiada jedną linijkę kodu, która jest za to odpowiedzialna. Pozwala ona wykryć potencjalne przyszłe problemy w aplikacji:
_mapper.ConfigurationProvider.AssertConfigurationIsValid();

Garść wniosków
Jak z większością rzeczy w programowaniu – początkowe zalety mogą stać się w przyszłości wadami. Profile mapowania powinny być robione raczej per biblioteka, żeby nie zrobił się śmietnik. Byłem nawet w projekcie gdzie poszczególne feature foldery posiadały własne profile. Osobiście nie stosuję AutoMappera w swoich rozwiązaniach, ale jeśli już trafiam do projektu, gdzie jest użyty – nie przeszkadza mi to. Mimo wygody w stosowaniu wolę widzieć dokładnie kiedy następuje mapowanie oraz jakie właściwości są przepisywane. Lubię czuć “ból mapowania”.
Istnieje natomiast jeden przypadek, kiedy na pewno zdecydowałbym się na AutoMappera: jeśli byłbym w projekcie, gdzie do odczytu używany jest Entity Framework lub nHibernate. Dzięki projekcjom biblioteka umożliwia ograniczenie odpytywanych kolumn przy wyciąganiu danych z bazy. Jak próbowałem analizować co tam się dokładnie dzieje, to SQL Server Profiler pokazywał mi dziwne rzeczy, więc zainteresowanym polecam po prostu wypowiedź autora. Tutaj można przeczytać o tym więcej: https://docs.automapper.org/en/stable/Queryable-Extensions.html

Piotr Wandycz
.NET okiem praktyka
O mnie
Zwyczajny programista, który wierzy że każdy rodzaj kodu można napisać w prosty sposób. W wolnym czasie rozwijam się w różnych kierunkach pozwalających utworzyć mi wymarzoną grę. Aktualnie: concept art.
© Piotr Wandycz. Design: HTML5 UP (modified).
Dodaj komentarz