Maikel van den Bosch: 09-11-2023
Object-2-Object
Object-2-Object vormt een veelvoorkomende uitdaging in het .NET-landschap, in het bijzonder bij het hanteren van Data Transfer Objects (DTO’s). Het kiezen van de meest geschikte aanpak en instrumenten is van groot belang, aangezien er diverse methoden beschikbaar zijn om deze taak te volbrengen. In dit artikel vergelijk ik enkele toonaangevende libraries, die ieder gebruikmaken van verschillende technologieën op de achtergrond. De vergelijking is gebaseerd op een benchmark die focust op de snelheid van de mapping, een cruciale factor bij het werken met grote datavolumes.
AutoMapper
Al geruime tijd behoort AutoMapper tot de marktleiders op het gebied van objectmapping in .NET. De library is zeer gebruiksvriendelijk; je kunt eenvoudigweg een profiel creëren waarin de mappingregels worden vastgelegd. Een enkele regel code volstaat vervolgens om de objecten daadwerkelijk te mappen.
Hoewel AutoMapper in het verleden reflection-methodologieën hanteerde, maakt het tegenwoordig gebruik van expression trees ter verbetering van de mappingssnelheid. AutoMapper biedt bovendien talrijke extra functionaliteiten.
Mapster
Mapster is een alternatief dat wellicht minder bekend is, maar significant gebruiksgemak biedt. Het is niet noodzakelijk een profiel aan te maken; de objecten kunnen direct worden gemapt. Hoewel automatische configuratie aanwezig is, biedt Mapster tevens mogelijkheden voor handmatige configuratie.
In deze benchmark gebruik ik Mapster’s reflection-technologie. Deze techniek vereist geen configuratie, wat een duidelijk onderscheid biedt met andere methoden.
Mapperly
Mapperly maakt uitsluitend gebruik van codegeneratie. Men dient te specificeren welke objecten gemapt dienen te worden, waarna Mapperly de vereiste code genereert. Dit betekent dat een ‘partial class’ met methode-definities aangemaakt dient te worden, die vervolgens door de codegeneratie wordt ingevuld.
Eigen implementatie
Een alternatieve aanpak bestaat uit het zelf implementeren van de mapping. Dit kan bijvoorbeeld worden bereikt door het inzetten van implicit operators. Met deze benadering behoudt je volledige controle over het gehele mappingproces. Voor de benchmark die ik uitvoer, maak ik gebruik van een variant op deze methode. Echter, ik vermijd het gebruik van implicit operators om potentiële beïnvloeding van de bovengenoemde libraries te voorkomen. In plaats daarvan implementeer ik een afzonderlijke methode die verantwoordelijk is voor de uitvoering van de mapping. Deze code zal gebruik maken van de beste preformance optimalisaties die ik kan bedenken, om zo snel mogelijk te kunnen mappen.
Handig om te vermelden is dat het gebruiken van een methode minder snel is dan het gebruiken van implicit operators, lees meer hierover in mijn andere blog
Benchmark
De benchmark voor deze analyse is uitgevoerd met behulp van BenchmarkDotNet. De volgende libraries zijn in de test betrokken:
– Handmatige mapping (methodemapping)
– AutoMapper
– Mapster
– Mapperly
Configuraties zijn, indien noodzakelijk, opgenomen in een setup-methode om de benchmark zo eerlijk mogelijk te maken.
De resultaten van de benchmark zijn als volgt:
100 objecten mappen
1.000 objecten mappen
100.000 objecten mappen
1.000.000 objecten mappen
Legenda
Mean is de gemiddelde tijd die nodig is om een enkele iteratie van de benchmark uit te voeren.
Error is de afwijking van de gemiddelde tijd.
StdDev geeft aan hoe de verdeling is van alle metingen. Een grotere StdDev wil zeggen dat meer metingen verder van het gemiddelde af zitten.
Ratio is de verhouding tussen de gemiddelde tijd van de huidige benchmark en de gemiddelde tijd van de baseline benchmark.
RatioSD is de standaardafwijking van de ratio.
Allocated is de hoeveelheid geheugen die is toegewezen voor een enkele iteratie van de benchmark.
Voor alle waarden geldt: hoe lager, hoe beter.
Conclusie
Persoonlijk geef ik de voorkeur aan handmatige mapping met behulp van implicit operators. Deze aanpak verzekert volledige controle over het mappingproces. Indien ik toch een library zou aanbevelen, dan gaat mijn voorkeur uit naar Mapperly, vanwege de snelheid die door codegeneratie mogelijk is. Zoals te zien in de tabellen is automapper vele malen trager dan o.a. Mapperly, zowel bij kleine als ook bij grote aantallen objecten.
Wel is er enige configuratie vereist, maar deze zijn minimaal.
Aangezien alle mappers evenveel geheugen alloceren, is geheugengebruik geen qualifier voor één van de mappers.