Jeleztem korábban, hogy mióta megismertem az NHibernate-et, azóta nem nagyon foglalkozok az Entity Frameworkkel. Miért? Pár gondolatot leírok, aztán majd kifejtem őket bővebben is.
- Sokféle kulcsgenerálást ismer. Az id generálásnak rendkívül nagy hatása van a módosítások felviteli sebességére. Eddig az assigneded és a HILO-t használtam élőben. SQL Serve Identity elfelejtve, considered harmful. Az SQL Server 2012 Sequence + HILO viszont egy jó kombináció lesz.
- Batch-elt műveletek. Komplex objektum gráfok módosításakor ez is igen sokat jelent, mivel 1 roundtrip alatt lehet sok insert-update-delete műveletet végrehajtani. Ráadásul pl. Oracle esetén kihasználják az Array Bindingot, ami kb. olyan, mint SQL servernél a tábla típusú paraméter, így eszement gyorsan tud DML műveleteket végrehajtani.
- Rendkívüli kibővíthetőség. Az IInterceptor interfészen keresztül mélyen bele lehet nyúlni a működésébe. Ezt pl. field szintű securityhoz használtuk ki, e nélkül nem nagyon tudtuk volna megcsinálni.
Vagy pl. a tranzakciók megkezdése után, de még az SQL parancsok végrehajtása előtt be kellett tolni egy a kliensoldali felhasználót reprezentáló információt (audit miatt). Erre is volt kézenfekvő kibővítési pont.
Vagy oraclenek collection típusú paramétert kellett átadni, ezt is meg tudtuk szépen oldani saját adattípus definiálásával. - Direkt DML műveltek. Update vagy Delete anélkül, hogy behúznánk az entitásokat memóriába. Lehet érvelni, hogy nem erre való egy O-R mapper, de ha már egyszer az ember entitásokban és nem táblákban fogalmazza meg a dolgait, egyszerűbb a DML-eknél is ezt használni. Főleg pl. egy öröklődéses esetben, amikor több táblában is kell törölni.
- Flexibilis materializáló. Joinolt direkt SQL select kimenetét szépen bele lehet passzírozni egy objektumfába, egyszerűen.
- Saját adattípusok használta. Az Oraclenek nincs GUID típusa, ezért RAW(16)-ként tároltuk a guidokat. Entitás oldalon viszont szeretjük a GUID-ot, ezért egy saját típussal oldottuk meg a leképezést, így mindkét oldal természetes absztrakciókkal dolgozik.
- Enum mapping. Ha akarom intként menti el, ha akarom stringként. Hogy is van ez EF-nél?
- Cascade műveletek gyerekekre való használata szabályozható.
- Szabályozható, hogy csak a megváltozott property-ket updatelje, vagy mindet?
- Van stateless sessionje (NHib Session kb. EF ObjectContext) nagytömegű adatkezeléshez
- Tud natívan pl. tömböt adatbázisra mappelni. Azaz sorszáma van az elemeknek, ha kitörlök egy elemet, akkor a felette levő sorszámúakat automatikusan updateli.
- Vannak current session kontérerei. Ezek pl. WCF szerviz és DI használata esetén nélkülözhetetlenek, így pl. a session élettartama a WCF OperationContexthez láncolható. Ezt annak idején letöltöttem EF-hez, elég bonyolult volt, de ez megy ott is.
- Future Query-k: ezekkel több lekérdezést egybe lehet fűzni, hogy egy batchben hajtsa végre. EF-hez láttam ilyet a kiegészítő packben.
- Secondary Cache. Ezt még nem használtam, de érzésre hatalmas potenciál van benne. Cache réteg, így a lekérdezések egy részét memóriából adja vissza.
- Sokféle adatbázis támogatása.
- Lazy properties. Betölti az entitást, de nem tölti be pl. a benne levő byte tömböt, ami egy blobra meppelődik a táblában. Csak akkor töltődik be, ha tényleg hivatkozunk a property-re. Ehhez ugyanazt a virtuális proxy megoldást használja, mint az EF.
Hirtelen ennyi jut az eszembe. Egyetlen, de ez nagy negatívum az EF-fel szemben a Linq providere. Az egyszerűen szar, félkész, még most, 2012. márciusában is. Ami kész van, az is elég ostoba, az EF-é viszont okos, tudja, mi a jó az adatbázisnak, így optimalizálja a generált SQL kódot.
Pl. az alábbi NHibernate LINQ-ból: … where !a.IsValid ezt csinálta Oracle alatt:
where not(a.IsValid).
Ez persze table scant okoz orán is. Így kellett átírni: where a.IsValid == false. Ebből lett: where a.IsValid = 0. Ez már seek. De basszus, ezt elvárnám a LINQ providertől!
Nincs a LINQ providerében outer join implementálva! Vagy amikor írtam egy allekérdezéses, Take-es majd select-es nagyobb LINQ kifejezést egyszerűen NotImplementedExceptiont kaptam, és láttam, az egyik NHib fejlesztő megindokolta, hogy ez miért jó így.
Szóval ez a része beteg, párszor LINQ helyett Criteria vagy HQL alapú lekérdezést kellett írnom, ez bosszantó, ront a jó benyomáson.
Tudom, hogy ez a bejegyzés egyesek agyát felhúzza majd. Lesz, aki utána fog nézni, hogy amiket pozitívumként írtam, valójában megvan vagy lesz EF-ben, vagy az EF Extensions packben. Lehet, nem tudok mindent én se fejből.
Nyissunk vitát, nézzük meg, melyik-miben jó, ebből mindenki tanulhat.
Could you hire me? Contact me if you like what I’ve done in this article and think I can create value for your company with my skills.
LEAVE A COMMENT
4 COMMENTS
Szép.
A linq miatt szomorú vagyok, egyszerűbb, kisebb projekteknél kb. ez adja meg az egész orm használhatóságát szerintem.
Viszont nagyobb alkalmazásoknál már erősen elgondolkodtatóak az általad írtak.
Morzel
Igen.
és ha már ORM, akkor érdemes jobban szétnézni a “piacon”, mert van élet az EF-NH vonalon túl is.
saját tapasztalat a DataObjects.NET nevű, orosz fejlesztésű eszközzel van, az itt felsorolt dolgok legtöbbjét tudja (persze van néhány hiányosság ott is), de pl. a LINQ providere kiemelkedően jó. igaz fizetős, de hatékonyabbá tesz.
WM
Én a kódgenerált (tehát nem library alapú) ORM-kre esküszöm. Évek alatt csiszolódnak a sablonok, az eredmény szép, átlátható, igény szerint testreszabható feature készlettel, ténylegesen typesafe kódokkal.
A LINQ providerek meg a karbantarthatatlanság netovábbjai. Nincs is annál szebb, amikor C# oldalon kell workaroundolni egy szar provider által generált SQL-t.
Szindbad: ha van rá idő/hozzáértő ember/pénz, akkor nyilván a saját megoldás lesz a legjobb az adott problémára. A legtöbb helyen ezek hiányoznak.
A Linq-s probléma tényleg gáz.