Blog Dla Programistów C#/.NET

środa, 12 lutego 2025

Mapowanie obiektów to temat, który od dawna wzbudza duże emocje wśród Programistów .NET. Istnieją liczne biblioteki, które mają za zadanie automatyzować proces konwersji między modelami (np. DTO) a encjami (np. z bazy danych). Najpopularniejszym rozwiązaniem w tej kategorii jest AutoMapper, jednak nie wszyscy są jego zwolennikami.

W tym artykule chciałbym podzielić się z Tobą moimi przemyśleniami na temat tego, dlaczego sam rezygnuję z używania zewnętrznych narzędzi do mapowania w wielu projektach oraz pokażę, jak można sobie radzić bez mappera.

Dowiesz się m.in.:
    • Czy manualne mapowanie zawsze jest koszmarem?
    • Jakie są wady (i potencjalne zalety) AutoMappera czy innych bibliotek?
    • Jakich technik używam w praktyce, aby zredukować nadmiarowy kod mapujący?

Zaskakujące Powody, Dla Których Nie Używam Mappera w .NET (i co Robię Zamiast Tego)

Czym w ogóle jest mapper?


Mapper to narzędzie (biblioteka), które automatycznie przenosi dane pomiędzy różnymi strukturami obiektów, np. z modelu DTO do modelu domenowego (encja) i odwrotnie. Najczęściej wskazujemy, które właściwości powinny być mapowane, a resztą zajmuje się biblioteka.

Przykładowy kod z użyciem AutoMappera:

/* Profil mapowania */
public class MyMappingProfile : Profile
{
public MyMappingProfile()
{
CreateMap<User, UserDto>()
.ForMember(dest => dest.FullName, opt => opt.MapFrom(src => src.Name + " " + src.Surname));
}
}

/* Wykorzystanie w kodzie */
var userDto = _mapper.Map<UserDto>(user);

Na pierwszy rzut oka wygląda to bardzo wygodnie, jednak – jak zawsze w programowaniu – diabeł tkwi w szczegółach.


Dlaczego NIE używam zewnętrznego mappera?


Ukryta logika i mniejsza kontrola
    • Problem: Gdy konfigurujemy AutoMapper (lub inną bibliotekę) w jednym pliku, logika mapowania staje się "magiczna" z perspektywy reszty kodu.
    • Konsekwencja: Łatwo zapomnieć, że dodaliśmy określoną regułę (np. ForMember), a przy rozbudowanym projekcie debugowanie bywa trudne.

Wydajność i "niespodzianki" w działaniu
    • Problem: Biblioteki mapujące potrafią generować kod w locie, używać refleksji lub innych mechanizmów.
    • Konsekwencja: Może to mieć wpływ na wydajność przy dużych wolumenach danych, a w niektórych przypadkach zachowanie może być nieintuicyjne (np. automatyczne mapowanie właściwości o podobnych nazwach, co nie zawsze jest pożądane).

Brak pełnej przejrzystości w kodzie
    • Problem: Jeśli inni deweloperzy w Twoim zespole nie znają dobrze narzędzia, będą mieli trudność w zrozumieniu kodu, gdzie "coś się dzieje w mapperze".
    • Konsekwencja: Zamiast czytelnych metod, w których wprost widać, co się kopiuje i dlaczego, mamy "mglistą warstwę" abstrakcji, a debugowanie wymaga znajomości wewnętrznej struktury narzędzia.

Mylące mappingi w dużych projektach
    • Problem: Więcej klas = więcej konfiguracji = większa szansa na konflikty i rozbieżności.
    • Konsekwencja: Łatwo o sytuację, w której mapping staje się "spaghetti" – trudne do utrzymania i niosące wiele niuansów, o których nawet autorzy zapomnieli.


3. Jak radzę sobie bez mappera?


1. Tworzę dedykowane metody konwertujące
Zamiast polegać na zewnętrznej bibliotece, sam piszę metody typu ToDto() czy ToDao().

Przykład w C#:

public class User
{
public string Name { get; set; }
public string Surname { get; set; }

public UserDto ToDto()
{
return new UserDto
{
FullName = $"{Name} {Surname}"
};
}

/* Inne metody biznesowe... */
}

public class UserDto
{
public string FullName { get; set; }

public User ToUser()
{
/* Załóżmy, że nie mamy "Surname" i "Name" osobno,
więc musimy zdecydować, jak podzielić FullName.
Na przykład: */
var parts = FullName.Split(' ');
return new User
{
Name = parts.FirstOrDefault() ?? string.Empty,
Surname = parts.Skip(1).FirstOrDefault() ?? string.Empty
};
}
}

    • W ten sposób logika jest jawna i łatwa do prześledzenia.
    • Jeśli coś wymaga zmiany, widać to w kodzie – nie musisz przeszukiwać reguł w osobnej konfiguracji.

2. Korzystam z "metod rozszerzających" (Extension Methods)

    • Jeżeli nie chcę tworzyć metod konwertujących w klasach (np. bo nie chcę mieszać warstwy domeny z warstwą DTO), używam extension methods.

Przykład:

public static class UserExtensions
{
public static UserDto ToDto(this User user)
{
return new UserDto
{
FullName = $"{user.Name} {user.Surname}"
};
}

public static User ToUser(this UserDto dto)
{
var parts = dto.FullName.Split(' ');
return new User
{
Name = parts.FirstOrDefault() ?? string.Empty,
Surname = parts.Skip(1).FirstOrDefault() ?? string.Empty
};
}
}

    • Dzięki temu kod pozostaje czytelny i spójny.
    • Metody rozszerzające dają też przyjemną składnię, np. var userDto = user.ToDto();.

3. Dedykowane serwisy do mapowania

    • W większych aplikacjach stosuję serwisy, np. IUserMapper, który zwraca UserDto na podstawie User lub odwrotnie.
    • To świetna opcja, gdy mamy mnóstwo klas i nie chcemy zaśmiecać modeli zbyt wieloma metodami.

public interface IUserMapper
{
UserDto MapToDto(User user);
User MapToModel(UserDto userDto);
}

public class UserMapper : IUserMapper
{
public UserDto MapToDto(User user)
{
/* Jawnie opisujemy mapowanie */
return new UserDto
{
FullName = $"{user.Name} {user.Surname}"
};
}

public User MapToModel(UserDto userDto)
{
var parts = userDto.FullName.Split(' ');
return new User
{
Name = parts.FirstOrDefault() ?? string.Empty,
Surname = parts.Skip(1).FirstOrDefault() ?? string.Empty
};
}
}

Serwis jest prostą klasą, którą łatwo przetestować, zdebugować i modyfikować.


Potencjalne zalety i kiedy mapper może być pomocny


Aby być fair, muszę przyznać, że mappery mają też swoje zalety:
    1. Szybki start: Przy małym projekcie, w którym mamy wiele pól 1:1, konfiguracja jest dość prosta i może zaoszczędzić czas.
    2. Proste mapowanie: Gdy w 100% nazwy i typy pól się pokrywają, AutoMapper i inne narzędzia sprawdzają się całkiem nieźle.
    3. Mniejsza ilość "klepania kodu": Przy 20-30 polach w modelu, manualne mapowanie bywa żmudne.


Kiedy warto w ogóle rozważyć nieużywanie mappera?


    1. Gdy mamy złożoną logikę biznesową: Różne pola mogą być mapowane w zależności od warunków biznesowych, a do tego dochodzą walidacje i konwersje. Łatwiej wtedy mieć pełną kontrolę i używać własnych metod.
    2. Gdy priorytetem jest wydajność i przejrzystość: Używanie refleksji i skomplikowanej konfiguracji wewnętrznej może wprowadzać overhead i trudniejsze debugowanie.
    3. Gdy zespół preferuje jawność kodu: Nie wszyscy lubią "magię" w stylu CreateMap<TSource, TDestination> – czasem po prostu wolimy wszystko widzieć "na wierzchu".


Wnioski


    • Mapper (np. AutoMapper) bywa naprawdę przydatny w pewnych scenariuszach, szczególnie gdy mamy proste mapowania 1:1.
    • Manualne mapowanie daje pełną kontrolę i przejrzystość – to ja decyduję, jak i co chcę zmapować, oraz widzę to "na pierwszy rzut oka".
    • Nie rezygnuję z mappera w 100% – raczej oceniam konkretny projekt i sprawdzam, czy dodatkowa warstwa abstrakcji i konfiguracji jest tu potrzebna.

Dzięki temu mogę tworzyć kod w pełni dopasowany do danego problemu biznesowego, bez obawy, że za rok zapomnę, gdzie i dlaczego ustawiłem regułę ForMember(...).


Bonus


Jeżeli chcesz nie tylko zagłębić się w temat mapowania obiektów w .NET, ale również poznać kompletny zestaw praktyk potrzebnych w pracy Programisty C#/.NET, zachęcam do zapoznania się z moim kompletnym szkoleniem online Zostań Programistą .NET. Znajdziesz tam nie tylko wiedzę o narzędziach czy bibliotekach, ale też wskazówki, jak projektować czysty i łatwy w utrzymaniu kod w różnych warstwach aplikacji.


Podsumowanie


Mam nadzieję, że tym artykułem pomogę Ci spojrzeć na kwestię mapowania obiektów od innej strony. Sam wybór, czy korzystać z narzędzi typu AutoMapper, czy nie, zależy od wielu czynników: skali projektu, preferencji zespołu czy stopnia złożoności logiki biznesowej.

Jeśli interesuje Cię więcej praktycznych porad i chcesz rozwijać swoje kompetencje w .NET, zerknij na mój kurs Zostań Programistą .NET. To świetny sposób na zdobycie umiejętności, które doceni każdy pracodawca w branży. Powodzenia!

To wszystkie na dzisiaj. Jeżeli taki artykuł Ci się spodobał, to koniecznie dołącz do mojej społeczności – darmowe zapisy, gdzie będziesz również miał dostęp do dodatkowych materiałów i przede wszystkim bonusów. Do zobaczenia w kolejnym artykule.

Szkolenie Zostań Programistą .NET
Szczegóły == Zostań Programistą .NET ==
Zapisy tylko do piątku do 22:00!
Autor artykułu:
Kazimierz Szpin
Kazimierz Szpin
CTO & Founder - FindSolution.pl
Programista C#/.NET. Specjalizuje się w Blazor, ASP.NET Core, ASP.NET MVC, ASP.NET Web API, WPF oraz Windows Forms.
Autor bloga ModestProgrammer.pl
Dodaj komentarz

Wyszukiwarka

Szkolenie Zostań Programistą .NET
Szczegóły == Zostań Programistą .NET ==
Zapisy tylko do piątku do 22:00!
© Copyright 2025 modestprogrammer.pl. Wszelkie prawa zastrzeżone. Regulamin. Polityka prywatności. Design by Kazimierz Szpin