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.