Archive for the ‘NHibernate’ Category

NHibernate futures

Saturday, March 31st, 2012

Korábban írtam, hogy a Future query-k milyen jók, mivel ha tudjuk, hogy sok lekérdezést egymás után akarunk végrehajtani, akkor össze lehet őket rakni egy batchbe, ezzel igen jelentős gyorsulást lehet elérni. Álljon itt egy konkrét példa:

private IQueryable LoadTradeStatisticsQueryable(ISession session, TaConfig config, TradeDirection dir)
{
return from ts in session.Query()
where ts.TaConfig == config && ts.Dir == dir
select ts;
}

public Dictionary> LoadTradeStatisticsBulk(TradeDirection dir, IEnumerable taSubPortfolios)
{
var futures = new Dictionary>();
using (var session = AtsNHibSessionFactory.Factory.OpenSession())
{
foreach (var taSubPortfolio in taSubPortfolios)
{
futures.Add(taSubPortfolio, LoadTradeStatisticsQueryable(session, taSubPortfolio.TaConfig, dir).ToFuture());
}
foreach (TaSubPortfolio p in futures.Keys.ToList())
{
futures[p] = futures[p].ToList();
}
}

return futures;
}

A trükk egyszerű. A lekérdezéseket nem hajtjuk végre, hanem a Queryable-öket a ToFuture segítségével betárazzuk későbbre. Aztán mikor mind megvan, a ToList()-tel kikényszerítjük az IQueryable-ök végrehajtását. A poén az, hogy ilyenkor az NHib tudja, hogy ezek future query-k, így a 2. ciklus első iterációjakor egyszerre kiadja az összes lekérdezést, így a ciklus 2..n. iterációjában már csak kivesszük az eredményeket.
Az adatbázisba ez sok-sok selectként megy be egy batchben, majd a több resultsetből az NHib szépen materializálja az entitásokat.
Sokszoros sebességnövekedést lehet elérni csak ezzel az egyszerű trükkel. Ez nem csak homogén lekérdezésekre megy, tetszőlegeseket össze lehet rakni így egybe.
EF-hez itt van hasonló kiegészítés.

Miért NHibernate?

Friday, March 30th, 2012

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.