Az ORM mozaikszó az angol Object-Relational Mapping szavak rövidése, amit magyarul objektum-relációs leképzésnek hÃvunk. Az ORM egy olyan komponens, ami az objektumorientált nyelvünk objektumait relációs adatbázis utasÃtásokra képes fordÃtani. Felmerülhet a kérdés, hogy miért van szükség erre?
ORM megoldások nélkül is lehetséges SQL adatbázisokkal kapcsolatot létesÃteni és adatokat manipulálni a programunkkal, de ez nem elÅ‘nyös biztonsági szempontból, mivel Ãgy megvan rá az esély, hogy SQL Injection-re adunk lehetÅ‘séget.
Az SQL Injection egy olyan támadási forma, amiben egy nem ellenÅ‘rzött és megfelelÅ‘en nem szűrt felhasználói bemenet értéke egy SQL utasÃtás része lesz. Nézzünk egy egyszerű példát.
string sql = $"SELECT * FROM USERS WHERE name={userName};";
A fenti példában a userName legyen egy a felhasználótól, mondjuk egy beviteli mezÅ‘bÅ‘l érkezÅ‘ mezÅ‘. Illetve az egyszerűség kedvéért tételezzük fel, hogy a sql változó módosÃtás nélkül továbbÃtásra kerül a DB felé. Ebben az esetben, ha a felhasználó "vicces" kedvében van és az alábbi szöveget adja meg: karcsi; DROP TABLE USERS; --, akkor a parancs amit továbbÃtani fogunk a DB felé az valójában nem egy, hanem kettÅ‘ valid SQL utasÃtás. Az egyik listáz, de a másik törli a USERS táblát.
Mint látható, ha nem ellenÅ‘rizzük a bevitelt, akkor akkor igen csúnya meglepetésekre számÃthatunk. Természetesen a nem ORM megoldások is kÃnálnak ez ellen védelmet, de ezek használata már a fejlesztÅ‘ felelÅ‘ssége.
Az ORM megoldások ez ellen tipikusan úgy védenek, hogy nem kell SQL-t Ãrni. Helyette a nyelv eszközeivel, metódusaival rakjuk össze az utasÃtásokat. Ezen felül az ORM megoldások nagy elÅ‘nye, hogy nem kell nekünk az objektumainkat manuálisan SQL utasÃtás sorrá és SQL-bÅ‘l vissza konvertálgatnunk, hogy használni tudjuk a szerver adatait.
Az ORM megoldások használatának további elÅ‘nye a flexibilitás növekedése. Az SQL esetén emlÃtettem, hogy ahány DB, annyi nyelvjárás. Ha a programunkat ráépÃtjük egy adott szervermegoldásra, akkor ha késÅ‘bb váltani akarunk, akkor kénytelenek leszünk átÃrni, módosÃtani az utasÃtásaink jó részét. Ez a felesleges nyűg elkerülhetÅ‘, ha eleve egy ORM megoldást alkalmazunk.
Eddig csak az elÅ‘nyökrÅ‘l volt szó, de ezeknek az elÅ‘nyöknek ára van. Az egyik ár a teljesÃtmény. Az utasÃtások generálása/fordÃtása, az objektumok konvertálgatása idÅ‘t vesz igénybe, ezáltal az ORM-ek használata némileg lassÃtja a programot. Ez a sebességcsökkenés általában elfogadható mértékű az elÅ‘nyökhöz képest, de akadhat olyan szituáció, használat, amikor ORM használata nélkül nagyságrendileg nagyobb teljesÃtményt tudunk elérni. A másik hátrány pedig az, hogy mivel a választott nyelvünk elemeivel Ãrjuk az SQL lekérdezéseinket, nem triviális, hogy mi mire fog SQL-be fordulni. Ezáltal a hibakeresés komplexitása növekedhet.
Entity Framework
Az Entity Framework a .NET ORM megoldása. Ebből létezik Core és nem Core változat. A nem Core jelzésű változat a 6-os széria óta nem fejlesztett. Ez tipikusan MS SQL Szerver és .NET Framework esetén használt. Ezzel szemben a Core változatok fejlesztésénél elsődleges szempont volt a több platform és adatbázis-kezelő rendszer támogatása.
Az Entity Framework Core az alábbi adatbázis rendszereket támogatja:
- MS SQL Server
- SQLite
- PostgreSQL
- MySQL/MariaDB
- Azure Cosmos
- In Memory
Az In Memory megoldás nem relációs adatbázis, kifejezetten tesztelésre hozta létre a Microsoft. Ezen felül további SQL megoldások használata is lehetséges, de ezek támogatását nem a Microsoft fejleszti.
Az Entity Framework használatához három csomag telepÃtésére lesz szükségünk. Az elsÅ‘ a Microsoft.EntityFrameworkCore.Design, ami az Entity Framework tervezÅ‘ csomagja. Ez a tervezésben segÃt minket. Ezt a Visual Studio és a parancsoros EF eszköz fogja használni. A másik két csomag, amire szükségünk lesz az a Microsoft.EntityFrameworkCore és a Microsoft.EntityFrameworkCore.xxx, ahol az xxx a használt SQL szerver támogató csomagja.
Ezen felül használat elÅ‘tt telepÃteni kell a parancssoros Entity Framework eszközt is. Erre majd a migrációk és a kód generálás miatt lesz szükségünk. Ezt a következÅ‘ parancs segÃtségével tudjuk telepÃteni:
dotnet tool install --global dotnet-ef
Támogatott tÃpusok
A C# és általánosságban a .NET tÃpusrendszere nem feltétlen fedi egymást, Ãgy elÅ‘fordulhat, hogy a C# kódunkban használt tÃpusnak nincs megfelelÅ‘je a választott adatbázis-kezelÅ‘ rendszerben. Ebben az esetben az Entity Framework a DB támogató csomagban meghatározott kód alapján belsÅ‘leg konvertálni fogja a tÃpusainkat valami olyanra, ami az adatbázis-kezelÅ‘ által támogatott, de ez nem biztos, hogy a legoptimálisabb lesz.
Például a .NET 6-ban megjelent DateOnly és a decimal tÃpust az SQLite támogató csomag szövegként fogja tárolni a DB-ben, mivel SQLite esetén ezeknek nincs megfelelÅ‘jük. Ez leginkább a DB méretét fogja jelentÅ‘sen megdobni, de hozhat magával teljesÃtménybeli gondokat is.