Miroslav Holec

Software & Cloud Architect

miroslavholec.cz / blog / automapper-do-robustniho-kodu-nepatri

AutoMapper do robustního kódu nepatří

Miroslav Holec

Miroslav Holec

Publikován 22. července 2015 , aktualizace: 29. března 2016

Tento článek je starší 18 měsíců a je proto možné, že popisuje postupy nebo technologie, které v uplynulé době mohly doznat výraznějších změn. Názory a myšlenky v tomto článku již nemusí vyjadřovat současné stanovisko autora nebo autorů. Článek byl napsán 22. července 2015.

AutoMapper je celkem chytrý nuget package, který umožňuje velmi snadno provádět mapování mezi objekty. Nejtypičtější použití je při mapování datových entit na různé data transfer objekty, například ViewModely. V praxi pak AutoMapper překlápí hodnoty properties z jednoho objektu do druhého a to na základě C# reflexe, případně dalších konfiguračních pravidel, která se definují pomocí Fluent API (extension metod).

Ukázka použití

Pro předvedení myšlenky AutoMapper použiju ukázku mapování produktové entity na ViewModel.

public class Product
{
    public string Title { get; set; }
    public decimal Price { get; set; }
}

public class ProductViewModel
{
    public string Title { get; set; }
    public decimal Price { get; set; }
}

Pro převedení produktu na ViewModel stačí nakonfigurovat mapování

AutoMapper.Mapper.CreateMap<Product, ProductViewModel>();

a od toho momentu je možné všude v kódu používat:

var viewmodel = AutoMapper.Mapper.Map<ProductViewModel>(product);

Vypadá to elegantně. S rostoucím počtem properties na entitě Product se nemusí vývojář o nic starat a nechá vše na automapperu. U jednoduchých projektů, kde jsou si DTO a datové entity podobné téměř 1:1 to funguje příkladně. Jenomže s rostoucí komplexitou projektu začnou vznikat první problémy.

Příliš mnoho automatizace škodí

Najednou má vývojář komplexní model a každá entita řadu cizích klíčů a navázaných objektů nebo kolekcí. Přestává být žádoucí, aby se vše mapovalo. Nebo naopak vzniká potřeba mapovat něco trochu jinak. Elegance jde stranou a z ničehonic vznikají rozsáhlé konfigurace v duchu:

autoMapper.Mapper.CreateMap<Product, ProductViewModel>()
            .ForMember(dest => dest.ImageUrl,
                       opts => opts.MapFrom(src => src.Image.Url))
			.ForMember(dest => dest.CategoryId,
					   opts => opts.Ignore());

Nakonec se to stejně obalí

Dřív nebo později je potřeba některé ViewModely vyrábět chytřeji a zapojit do jejich mapování pokročilejší logiku. Občas na to stačí ještě AutoMapper a dostatek času s hledáním řešení "jak to mám napsat" ale jindy se zkrátka použití AutoMapper obalí a doplní vlastním kódem:

public class ProductMap
{
	public ProductViewModel ToViewModel(Product dbmodel)
    {
        var viewmodel = AutoMapper.Mapper.Map<ProductViewModel>(product);

		if (dbmodel.Images != null && dbmodel.Images.Any())
		{
			viewmodel.ImageUrl = CreateAbsoluteUrl(dbmodel.EshopId, dbmodel.Images.Single());
		}

		return viewmodel;
	}
}

Komplexita roste a s ní nakonec i nejistota:

  • mapuje se to?
  • dělá to AutoMapper nebo já?
  • jak ten ViewModel vlastně vypadá když ho vrátí AutoMapper?
  • proč je to NULL? to udělal AutoMapper nebo to tam tak posílám?

Lehce na bojišti, těžko na testišti

Kombinace AutoMapperu s vlastní logikou nakonec dožene vývojáře k tomu, aby mapování důkladně otestoval. Za normálních okolností pro (minimálně ta jednoduchá) mapování nepíšu testy ale když se spojí "blackbox" s vlastním kódem, není zbytí. Pak najednou začnou testy odečítat ušetřený čas, protože to, co se nepsalo ručně v aplikačním kódu, to se teď testuje.

Automapper do robustního řešení nepatří

Pokud nedělám skutečně na jednoduchém webovém projektu, je z mého pohledu použití AutoMapperu sázka do loterie a osobně upřednostňuji napsat si vše sám. Pokud přidávám do jedné třídy novou vlastnost, mám možnost se rozhodnout, kde se všude tato vlastnost zpropaguje a zasáhnout do všech mapování. V případě AutoMapperu naopak přemýšlím (namapuje se to? bude to fungovat?). Společně s řadou chytrých pluginů jako ReSharper navíc nezabere napsání pár desítek řádků mnoho času.

Dodatek po 2 měsících

I po dvou měsících intenzivní práce s AutoMappersem se ukazuje, že přinesl více škody než užitku. Problémy se vyskytují například při změněně názvů sloupců na view modelu nebo na entitě. Automapper provede konvezi a pokud nenajde shodu, sloupce se zkrátka nenamapují. Protože se projekt zkompiluje, je často velmi snadné na mapování zapomenout. Podobné problémy pozoruji při mapování nullable hodnot a při konverzi typů s pohyblivou desetinnou čárkou. Automapper se snaží za každou cenu "něco udělat" a často jen vytváří domnění, že všechno funguje správně.

Školení ASP.NET Core a Entity Framework Core

Budoucnost platformy .NET bude patřit technologiím ASP.NET Core a EF Core. Přijďte se naučit tyto moderní technologie používat na mém praktickém školení.

7.8.2017 - 9.8.2017 ASP.NET Core MVC
11.9.2017 - 12.9.2017 Entity Framework Core