W świecie programowania w .NET, walka z tzw. „boilerplate code” (kodem powtarzalnym) to chleb powszedni. Każdy programista backendowy zna ten ból: masz encję domenową, ale potrzebujesz ją zwrócić z API. Tworzysz więc klasę DTO. Następnie piszesz mapper (lub konfigurujesz AutoMapper). Potem, przy zapytaniu do bazy danych, musisz pamiętać o projekcji (.Select()), aby nie pobierać całej bazy do pamięci.
Tutaj na scenę wkracza Facet – biblioteka, która wykorzystuje jedną z najpotężniejszych funkcji współczesnego C#: Source Generators.
Czym jest Facet?
Facet to biblioteka NuGet, która automatycznie generuje obiekty DTO (Data Transfer Objects), kod mapujący oraz projekcje EF Core w czasie kompilacji.
W przeciwieństwie do tradycyjnych bibliotek mapujących (jak AutoMapper), które często działają w oparciu o Refleksję (Reflection) w czasie działania aplikacji (runtime), Facet tworzy gotowy kod C# w momencie, gdy budujesz projekt.
Główne zalety:
- Zero narzutu w Runtime: Ponieważ kod jest generowany podczas kompilacji, działa tak szybko, jak ręcznie napisany kod. Nie ma kosztownej refleksji.
- Bezpieczeństwo typów (Type Safety): Jeśli zmienisz nazwę właściwości w encji, kompilator natychmiast poinformuje Cię o błędzie w DTO, zanim w ogóle uruchomisz aplikację.
- Projekcje SQL: Biblioteka potrafi wygenerować wydajne zapytania LINQ (
Select), pobierając z bazy danych tylko te kolumny, które są faktycznie potrzebne w Twoim DTO.
Jak to działa w praktyce?
Załóżmy, że masz prostą encję w systemie e-commerce:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string InternalSkuCode { get; set; } // Tego nie chcemy zwracać klientowi
public Category Category { get; set; }
}
Zamiast ręcznie tworzyć ProductDto i pisać kod kopiujący dane, używasz atrybutu [Facet].
Krok 1: Definicja
Definiujesz klasę DTO jako partial i oznaczasz ją atrybutem wskazującym na encję źródłową:
using Facet;
[Facet(typeof(Product))]
public partial class ProductDto
{
// Możesz wskazać, które pola chcesz, lub wykluczyć niechciane.
// Domyślnie Facet spróbuje dopasować właściwości po nazwach.
}
Krok 2: Magia kompilacji
W tle, Facet wygeneruje drugą część klasy ProductDto zawierającą właściwości Id, Name, Price (pominie te, których nie ma w DTO lub są wykluczone) oraz metody mapujące.
Krok 3: Użycie (np. z Entity Framework Core)
To tutaj Facet błyszczy najjaśniej. Zamiast pobierać całą encję, używasz wygenerowanej metody rozszerzającej:
var products = await dbContext.Products
.Where(p => p.Price > 100)
.ToProductDtoListAsync(); // Wygenerowana metoda!
Ten kod zostanie przetłumaczony na optymalny SQL, pobierający tylko wybrane kolumny.
Zaawansowane funkcje: Flattening
Jedną z nowszych i bardzo przydatnych funkcji jest spłaszczanie (Flattening). Często zdarza się, że encja ma zagnieżdżone obiekty (np. Product.Category.Name), a my chcemy zwrócić płaską strukturę JSON.
Tradycyjnie musiałbyś pisać: CategoryName = p.Category.Name
Z Facet, jeśli nazwiesz właściwość w DTO zgodnie z konwencją (np. CategoryName), biblioteka często domyśli się, o co chodzi, lub możesz to skonfigurować atrybutem, a generator utworzy odpowiedni kod nawigujący po relacjach.
Facet vs AutoMapper vs Mapster
| Cecha | Facet | AutoMapper | Ręczne pisanie kodu |
| Moment generowania | Kompilacja (Source Gen) | Runtime (zazwyczaj) | Czas pisania kodu |
| Wydajność | Bardzo wysoka | Średnia (narzut inicjalizacji) | Bardzo wysoka |
| Wykrywanie błędów | Podczas kompilacji (Red squiggle) | Często dopiero po uruchomieniu | Podczas kompilacji |
| Ilość kodu do napisania | Mała (Atrybuty) | Mała (Profile) | Duża |
| Debugowanie | Łatwe (masz wgląd w wygenerowany kod) | Trudne (magia w tle) | Łatwe |
Podsumowanie
Biblioteka Facet to świetny przykład tego, w jakim kierunku zmierza ekosystem .NET. Odchodzimy od „magicznych”, wolnych rozwiązań opartych na refleksji na rzecz rozwiązań generowanych statycznie (AOT-friendly).
Jeśli budujesz nowe API w .NET 6/7/8+ i chcesz zachować czystość architektury bez poświęcania wydajności i bez pisania setek identycznych klas DTO – Facet jest biblioteką, którą zdecydowanie warto sprawdzić.