LINQ 2 SQL, DataLoadOptions a CompiledQuery
Len pre obnovenie pamäte DataLoadOptions je trieda, kde sa definuje eager-loading pre LINQ 2 SQL. Použitie je asi nasledovné:
var context = new MyDataContext(connectionString);
var dlo = new DataLoadOptions();
dlo.LoadWith<User>(u => u.Roles);
context.LoadOptions = dlo;
DataLoadOptions má však niekoľko obmedzení.
- LoadOptions sa musí nastaviť ešte pred prvým query.
- LoadOptions, ani samotný DataLoadOptions objekt sa už nemôžu meniť po spustení prvého query.
Vzhľadom na tieto obmedzenia som nastavovanie LoadOptions dal priamo do konštruktoru triedy MyDataContext. Tu som nastavil eager-loading, ktorý je tipický pre celú aplikáciu. Napríklad pre niektoré entity sa načíta rovno aj ich vlastník a podobne.
Dnes sme riešili performance a niektoré query sa museli predkompilovať.V LINQ 2 SQL na toto slúži trieda CompiledQuery. Použitie je celkom jednoduché:
Func<MyDataContext, int, User> getUser;
getUser = CompiedQuery.Compile((MyDataContext context, int userId) => context.Users.FirstOrDefault(u => u.Id == userId));
var context = new MyDataContext(connectionString);
User user1 = getUser(context, 1);
volanie funkcie getUser trva asi 10tinu času neskompilovaného query.
Lenže tu sme narazili na problém, že pri volaní getUser nad rôznymi inštanciami MyDataContext to hádzalo výnimku “Compiled queries across DataContexts with different LoadOptions not supported.” Z tohoto sú jasné obmedzenia vlastnosti LoadOptions, pretože každá expression sa interne skompiluje.
Naštastie riešenie bolo jednoduché. V statickom konštruktore sa vytvorí jedna inštancia DataLoadOptions a v konštruktore MyDataContext sa do LoadOptions nastaví práve táto jedna inštancia. Keďže sa DataLoadOptions už potom nemení, tak by to malo byť aj thread-safe.
Čo bolo ale zujímavé, že pri tejto implementácii sa čas kompilácie query (myslím bez použitia CompiledQuery) skrátil asi na polovicu.