Ez egy tutorialhoz tartozó leírás! A turtorial erről a címről érhető el:
A cikksorozat záró részeként az SqlCacheDependency-t vesszük górcső alá. Ez az objektum szerintem a legérdekesebb a három közül, hiszen imperatívan és deklaratívan is használhatjuk, illetve az egyszerűsége miatt több helyen is megbújva várja, hogy előcsalogassuk.
Erről található a legtöbb leírás, így ezek átolvasása után egy eléggé részletes képet kaptam a témáról, melyet kiegészítve a saját tapasztalataimmal megszületett ez a cikk.
Erről található a legtöbb leírás, így ezek átolvasása után egy eléggé részletes képet kaptam a témáról, melyet kiegészítve a saját tapasztalataimmal megszületett ez a cikk.
SqlCacheDependency, minek kell még egy?
Jogosan merül fel bennünk a kérdés, hogy tényleg szükségünk van erre? A választ nem lehet csak úgy egyből rávágni, hogy igen vagy nem.
Sok helyen csak az SqlDependency-t említik érthető módon, hiszen az ASP.NET mellett winforms, console alkalmazásokból is elérhető.
Az SqlCacheDependency-t igazából inkább csak kényelmesebb használni, de nem kapunk semmi olyat, amit eddig ne tudtunk volna megoldani SqlDependency-vel.
Hatékonyság szempontjából viszont állítólag az SqlCacheDependency valamivel alatta marad az SqlDependency-nek.
Tehát amint láthatjuk összetett kérdésről van szó. Ez olyan, mint a memória vs. műveletigény. A cikk olvasása során ezeket tartsuk szem előtt.
Jogosan merül fel bennünk a kérdés, hogy tényleg szükségünk van erre? A választ nem lehet csak úgy egyből rávágni, hogy igen vagy nem.
Sok helyen csak az SqlDependency-t említik érthető módon, hiszen az ASP.NET mellett winforms, console alkalmazásokból is elérhető.
Az SqlCacheDependency-t igazából inkább csak kényelmesebb használni, de nem kapunk semmi olyat, amit eddig ne tudtunk volna megoldani SqlDependency-vel.
Hatékonyság szempontjából viszont állítólag az SqlCacheDependency valamivel alatta marad az SqlDependency-nek.
Tehát amint láthatjuk összetett kérdésről van szó. Ez olyan, mint a memória vs. műveletigény. A cikk olvasása során ezeket tartsuk szem előtt.
Honnan származik ?
Mint ahogy már említettem, eléggé széleskörű támogatás van ASP.NET-ben SqlCacheDependency ügyileg. Ez annak is köszönhető, hogy a Notification és ASP.NET Cache között jött létre a kapcsolat. Így a CacheDependency osztály egy alosztályaként az SqlCacheDepenency magába zárja (encapsulate) az SqlDependency-t, úgy, hogy közben megtartja a CacheDependency-s viselkedését. Ennek a származtatásnak köszönhető az, hogy a másik két objektummal ellentétben nem a System.Data.SqlClient névtéren belül található, hanem a System.Web.Caching névtér alá került.
Az SqlCacheDependency-t két helyről is tudjuk használni. Van értelemszerűen a kódból történő elérés, illetve van egy rövidebb út, amikor magából az oldalról érjük el (deklaratívan).
Mint ahogy már említettem, eléggé széleskörű támogatás van ASP.NET-ben SqlCacheDependency ügyileg. Ez annak is köszönhető, hogy a Notification és ASP.NET Cache között jött létre a kapcsolat. Így a CacheDependency osztály egy alosztályaként az SqlCacheDepenency magába zárja (encapsulate) az SqlDependency-t, úgy, hogy közben megtartja a CacheDependency-s viselkedését. Ennek a származtatásnak köszönhető az, hogy a másik két objektummal ellentétben nem a System.Data.SqlClient névtéren belül található, hanem a System.Web.Caching névtér alá került.
Az SqlCacheDependency-t két helyről is tudjuk használni. Van értelemszerűen a kódból történő elérés, illetve van egy rövidebb út, amikor magából az oldalról érjük el (deklaratívan).
Kódból történő használata
Imperatív használatra egy példa
Ahhoz, hogy kódból tudjuk használni az SqlCacheDependency-t két dologra van szükségünk. Első az, hogy az SqlDependency.Start() tagfüggvényével feliratkozunk a lekérdezés figyelésre, ugyanúgy, mint ahogy az előző cikkben is tettük.
A második dolog, amire szükségünk van, hogy létre kell hoznunk egy példányt az SqlCacheDependency-ből. Majd a megfelelő beállítások elvégzése után a Response.AddCacheDependency() tagfüggvénnyel hozzáadjuk a cache függőséget alkalmazásunkhoz. Nézzük meg egy példaalkalmazás keretén belül, hogy is történik mindez.
Imperatív használatra egy példa
Ahhoz, hogy kódból tudjuk használni az SqlCacheDependency-t két dologra van szükségünk. Első az, hogy az SqlDependency.Start() tagfüggvényével feliratkozunk a lekérdezés figyelésre, ugyanúgy, mint ahogy az előző cikkben is tettük.
A második dolog, amire szükségünk van, hogy létre kell hoznunk egy példányt az SqlCacheDependency-ből. Majd a megfelelő beállítások elvégzése után a Response.AddCacheDependency() tagfüggvénnyel hozzáadjuk a cache függőséget alkalmazásunkhoz. Nézzük meg egy példaalkalmazás keretén belül, hogy is történik mindez.
string connstring = "Data Source=.\\SQLEXPRESS;DataBase=AdventureWorks;Integrated Security=True; Asynchronous Processing=true";
using (SqlConnection conn = new SqlConnection(connstring))
{
string query = "SELECT ProductId AS Azon, Name AS Név, ProductNumber, Color FROM Production.Product Where Color Like ‘%Black%’";
using (SqlConnection conn = new SqlConnection(connstring))
{
string query = "SELECT ProductId AS Azon, Name AS Név, ProductNumber, Color FROM Production.Product Where Color Like ‘%Black%’";
using (SqlCommand comm = new SqlCommand(query, conn))
{
try
{
conn.Open();
SqlCacheDependency dependency = new SqlCacheDependency(comm);
{
try
{
conn.Open();
SqlCacheDependency dependency = new SqlCacheDependency(comm);
int expire = 3;
DateTime exp = DateTime.Now.AddMinutes(expire);
DateTime exp = DateTime.Now.AddMinutes(expire);
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetExpires(exp);
Response.Cache.SetValidUntilExpires(true);
Response.AddCacheDependency(dependency);
GridView1.DataSource = comm.ExecuteReader();
GridView1.DataBind();
}
catch (SqlException exp)
{
Response.Write(exp.Message);
}
finally
{
conn.Close();
} //finally
} //using command
} //using connection
Response.Cache.SetExpires(exp);
Response.Cache.SetValidUntilExpires(true);
Response.AddCacheDependency(dependency);
GridView1.DataSource = comm.ExecuteReader();
GridView1.DataBind();
}
catch (SqlException exp)
{
Response.Write(exp.Message);
}
finally
{
conn.Close();
} //finally
} //using command
} //using connection
A SetCacheAbility()-ig a kód szerintem teljesen egyértelmű, hogy mit csinál az alkalmazás. Az előbb említett tagfüggvény egy HttpCacheAbility enumerátort vár, amely arra való, hogy beállítsuk vele a HTTP fejléc Cache-Control értékét. Ezzel azt szabjuk meg, hogy hol gyorsítótárazható az adat (szerver által küldött válasz). Például a Private (alapértelmezett) esetén csak a kliensnél (proxy nem tárolja); Public esetében pedig proxy-nál is és kliensnél is, illetve, ha csak a szerveren szeretnénk tárolni, akkor a Server-t válasszuk az enumerátornál.
A SetExpires() értelemszerűen az elévülési időt szabja meg, a SetValidUntilExpires() pedig azt, hogy az ASP.NET mellőzi-e a klienstől érkező érvénytelenítési kérelmet. A tapasztalat az, hogy vele is meg nélküle is tökéletesen működik az alkalmazás!
A SetExpires() értelemszerűen az elévülési időt szabja meg, a SetValidUntilExpires() pedig azt, hogy az ASP.NET mellőzi-e a klienstől érkező érvénytelenítési kérelmet. A tapasztalat az, hogy vele is meg nélküle is tökéletesen működik az alkalmazás!
Cache API-s gyorsítótárazás I.
Még kétfajta lehetőséget villantanék meg, hogy hogyan lehet a Cache-hez hozzáadni ilyen függőséget. Cache API-t használja mindkettő (ezeket nem tartalmazza a példaalkalmazás!).
Az első egy egyszerű függőséget szab meg, egy általunk megadott objektumhoz. Ez az objektum általában vagy egy DataSet vagy egy DataTable.
Még kétfajta lehetőséget villantanék meg, hogy hogyan lehet a Cache-hez hozzáadni ilyen függőséget. Cache API-t használja mindkettő (ezeket nem tartalmazza a példaalkalmazás!).
Az első egy egyszerű függőséget szab meg, egy általunk megadott objektumhoz. Ez az objektum általában vagy egy DataSet vagy egy DataTable.
DataTable cache_table = new DataTable();
SqlDataReader datareader = comm.ExecuteReader();
cache_table.Load(datareader);
Cache.Insert("Products", cache_table, dependency);
SqlDataReader datareader = comm.ExecuteReader();
cache_table.Load(datareader);
Cache.Insert("Products", cache_table, dependency);
Cache API-s gyorsítótárazás II.
A másik lehetőség ennél egy kicsit többet nyújt számunkra. Konkrétan a változásról való értesítéshez rendelhetünk egy delegate-t, így megtudhatjuk a cache érvénytelenítés okát. Ehhez szükségünk lesz egy CacheItemRemoveCallBack objektumra, mely segítségével a delegate-ünket össze tudjuk kapcsolni a gyorsítótárazott object-tel.
A másik lehetőség ennél egy kicsit többet nyújt számunkra. Konkrétan a változásról való értesítéshez rendelhetünk egy delegate-t, így megtudhatjuk a cache érvénytelenítés okát. Ehhez szükségünk lesz egy CacheItemRemoveCallBack objektumra, mely segítségével a delegate-ünket össze tudjuk kapcsolni a gyorsítótárazott object-tel.
Cache.Insert("Products", cache_table, dependency, DateTime.Now.AddMinutes(3), TimeSpan.Zero, CacheItemPriority.Default, new CacheItemRemovedCallback(CacheChanged));
private static void CacheChanged(string key, object cacheitem, CacheItemRemoveReason reason)
{
AddToLog("Az alábbi kulcsú cacheitem törölve lett a cacheből! Kulcs: " + key + ", ok: " + reason.ToString());
}
private static void CacheChanged(string key, object cacheitem, CacheItemRemoveReason reason)
{
AddToLog("Az alábbi kulcsú cacheitem törölve lett a cacheből! Kulcs: " + key + ", ok: " + reason.ToString());
}
Az Insert ezen túlterhelésének a következő a szintakszisa:
Cache.Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpriration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback)
Cache.Insert(string key, object value, CacheDependency dependencies, DateTime absoluteExpiration, TimeSpan slidingExpriration, CacheItemPriority priority, CacheItemRemovedCallback onRemoveCallback)
A key a kulcs, amely alapján a későbbiek tudunk rá hivatkozni.
A value a gyorsítótárazandó objektum.
A dependencies a cache függőség, ami lehet akár fájl is.
Az absoluteExpiration az elévülési idő. Ha abszolút lejárati időt adunk meg, akkor a slidingExpiration vagy Cache.NoSlindingExpiration vagy TimeSpan.Zero legyen!
A slindingExpiration az utolsó hozzáféréstől számított elévülési idő. Ha ennél csúszó Expiration-t adunk meg, akkor az absoluteExpiration paraméternek feltétlenül Cache.NoAbsoluteExpriration-nak kell lennie!
Az onRemoveCallback segítségével iratkozunk fel arra az eseményre, ami akkor hajtódik végre, ha a cache tartalma érvénytelenítve illetve törölve lett.
A value a gyorsítótárazandó objektum.
A dependencies a cache függőség, ami lehet akár fájl is.
Az absoluteExpiration az elévülési idő. Ha abszolút lejárati időt adunk meg, akkor a slidingExpiration vagy Cache.NoSlindingExpiration vagy TimeSpan.Zero legyen!
A slindingExpiration az utolsó hozzáféréstől számított elévülési idő. Ha ennél csúszó Expiration-t adunk meg, akkor az absoluteExpiration paraméternek feltétlenül Cache.NoAbsoluteExpriration-nak kell lennie!
Az onRemoveCallback segítségével iratkozunk fel arra az eseményre, ami akkor hajtódik végre, ha a cache tartalma érvénytelenítve illetve törölve lett.
Az érvénytelenítés oka (tehát a CacheItemRemoveReason enumerátor) a következők valamelyike lehet: Expired | Removed | Underused | DependencyChanged re-create item and add back to cache as required.
Természetesen az Insert párjával az Add-del is tökéletesen működik mindkét példakód!
Természetesen az Insert párjával az Add-del is tökéletesen működik mindkét példakód!
Page Fragment Cache, avagy az OutputCache direktíva
Lekérdezés alapú cachelés
Deklaratív módon kétféleképpen is lehet használni a QN-t. Az egyik esetben egy lekérdezésre szabhatunk meg változásfigyelést, míg a másik esetben egész adattáblákra! Kezdjük először a lekérdezéses verzióval. Ilyenkor igazából, csak a kódunkon rövidítünk. A következő pár sor helyett összesen egy sort kell majd beírnunk az aspx fájlba:
Lekérdezés alapú cachelés
Deklaratív módon kétféleképpen is lehet használni a QN-t. Az egyik esetben egy lekérdezésre szabhatunk meg változásfigyelést, míg a másik esetben egész adattáblákra! Kezdjük először a lekérdezéses verzióval. Ilyenkor igazából, csak a kódunkon rövidítünk. A következő pár sor helyett összesen egy sort kell majd beírnunk az aspx fájlba:
SqlCacheDependency dependency = new SqlCacheDependency(comm);
int expire = 3;
DateTime exp = DateTime.Now.AddMinutes(expire);
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetExpires(exp);
Response.Cache.SetValidUntilExpires(true);
Response.AddCacheDependency(dependency);
int expire = 3;
DateTime exp = DateTime.Now.AddMinutes(expire);
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.Cache.SetExpires(exp);
Response.Cache.SetValidUntilExpires(true);
Response.AddCacheDependency(dependency);
Az OutputCache direktívát kell szerkesztenünk. Itt meg kell adnunk a Duration-t, amivel az elévülési időt szabjuk meg, illetve a VaryByParam-ot, mely az itt felsorolt paraméterek minden egyes változatához létrehoz egy cachelt verziót az oldalból. Például ha van olyan paraméterünk, hogy Countries, akkor lesz egy Hun verziós oldal cacheitem-ünk, illetve mondjuk egy Eng is. Eddig még semmi újdonság nincs ASP.NET 1.X-hez képest. De 2.0-ban már van egy SqlDependency attribútum is. Ennek értékül most adjuk azt, hogy CommandNotification!
<%@ OutputCache Duration="3600" VaryByParam="*" SqlDependency= "CommandNotification" %>
Így futtatva az alkalmazásunkat, ugyanazt az eredményt kapjuk, mint amikor imperatívan adtuk a cache-hez az SqlCacheDependency-t.
Tábla alapú cachelés
Ehhez a verzióhoz semmilyen mögöttes kódra nincs szükségünk, csak a web.config-ra és az aspx fájlra. Web.Config-ban azt állítjuk be, melyik adatbázist szeretnénk úgy cachelni, hogy változás esetén a cache tartalma érvénytelenítődjön. Ehhez először a connectionstrings részlegben vegyünk fel egy adatkapcsolati sztringet:
Ehhez a verzióhoz semmilyen mögöttes kódra nincs szükségünk, csak a web.config-ra és az aspx fájlra. Web.Config-ban azt állítjuk be, melyik adatbázist szeretnénk úgy cachelni, hogy változás esetén a cache tartalma érvénytelenítődjön. Ehhez először a connectionstrings részlegben vegyünk fel egy adatkapcsolati sztringet:
<connectionStrings>
<clear/>
<add name="localhost" connectionstring="Data Source=.\SQLEXPRESS; DataBase=AdventureWorks; Integrated Security=True" providerName="System.Data.SqlClient">
</connectionStrings>
<clear/>
<add name="localhost" connectionstring="Data Source=.\SQLEXPRESS; DataBase=AdventureWorks; Integrated Security=True" providerName="System.Data.SqlClient">
</connectionStrings>
Majd a cache szekción belül az sqlcachedependency alszekcióban létre kell hozni egy adatbázisra való hivatkozást (ez system.web-en belül van a connectionStrings-sel ellentétben):
<caching>
<sqlCacheDependency enabled="true">
<databases>
<add name="AW" connectionStringName="localhost" pollTime="60000" />
</databases>
</sqlCacheDependency>
</caching>
<sqlCacheDependency enabled="true">
<databases>
<add name="AW" connectionStringName="localhost" pollTime="60000" />
</databases>
</sqlCacheDependency>
</caching>
Két dologra hívnám fel a figyelmet. Az egyik az, hogy a pollTime-ot (milliszekundum) nem kötelező megadni SQL Server 2005 esetén, ellentétben az SQL Server 2000-rel. 2000 esetén másképp történik a változásfigyelés, konkrétan nem triggerekkel, hanem pollingolással. A másik dolog pedig az, hogy mint minden web.config-beli szekcióhoz, ehhez is létezik egy osztály, mely segítségével egyes dolgokat képesek vagyunk manipulálni kódból. Ez az SqlCacheDependencySection osztály. Tulajdonságain keresztül el tudjuk érni a <databases> keretein belül megadott adatbázisokat, kikapcsolhatjuk a cachelést, átállíthatjuk a polltime-ot, stb. Sajnos viszont, mint ahogy az összes többi szekciót kezelő osztály, ez sem képes új dolgok felvételére, pedig szerintem hasznos lehetne, ha kódból is felvehetnénk adatbázisokat. Ez van, ezt kell szeretni.
Ezek után dobjunk az oldalra egy SqlDataSource-t, illetve egy GridView-t. (A korábbiakban használt lekérdezést használom a példaalkalmazásban). Miután megvagyunk mindenféle adatkötéssel, jöjjön a dolog érdemi része, a cachelés beállítása:
<%@ OutputCache Duration="3600" VaryByParam="None" SqlDependency= "AW:Production.Product" %>
Az SqlDependency-nél a szintaktika a következő: dependency_name:table_name. A dependency_name a web.config-ban megadott adatbázis referencianév, a table_name pedig értelemszerűen az adatbázis egy táblája. Arra is van lehetőségünk, hogy egyszerre több táblát figyeltessünk, például, ha master-details táblákat jelenítünk meg egy GridView-ban. Ilyenkor egymástól pontosvesszővel válasszuk el a két tábla referenciát, pl.: sqldependency="northwind:products; northwind:categories"
SqlCacheDependencyAdmin
Az ASP.NET 2.0 tartalmaz egy olyan objektumot, amellyel a kódunkból is tudjuk kezelni az adatbázisra/adattáblákra vonatkozó változásfigyelést. Néhány fontos metódusát emelném csak ki:
– EnableNotifications, engedélyezi a connectionstringben kapott adatbázisnál a változásfigyelést
– EnableTableForNotification, adatbázis egy adott táblájához engedélyezi a change notification-t. Második paraméterként kell megadni a táblanevét (első paraméter szintén a connstring)
– DisableNotification, DisableTableForNotifiction letiltják a változásfigyelést
– GetTablesEnabledForNotifications, visszaad egy string típusú tömböt, melyben azok a táblanevek lesznek benne, melyeknél engedélyezve van
Az ASP.NET 2.0 tartalmaz egy olyan objektumot, amellyel a kódunkból is tudjuk kezelni az adatbázisra/adattáblákra vonatkozó változásfigyelést. Néhány fontos metódusát emelném csak ki:
– EnableNotifications, engedélyezi a connectionstringben kapott adatbázisnál a változásfigyelést
– EnableTableForNotification, adatbázis egy adott táblájához engedélyezi a change notification-t. Második paraméterként kell megadni a táblanevét (első paraméter szintén a connstring)
– DisableNotification, DisableTableForNotifiction letiltják a változásfigyelést
– GetTablesEnabledForNotifications, visszaad egy string típusú tömböt, melyben azok a táblanevek lesznek benne, melyeknél engedélyezve van
Fontos még azt megjegyezni szerintem, hogy ha nem tudunk az adatbázishoz csatlakozni, akkor ez az objektum egy HttpException-t dob, nem pedig egy SqlException-t! Illetve pl.: a GetTablesEnabledForNotifications metódusnál akár még DatabaseNotEnabledForNotificationException is kaphatunk, ha nincs engedélyezve a QN!
FONTOS: Ha sémával rendelkező táblánál szeretnénk engedélyezni a QN-t,, akkor sajnos egy kicsit módosítunk kell egy tárolt eljárást. Ha nem tesszük meg, ilyesmi hibával fogunk találkozni:
Cannot create trigger ‘Owner.TableName_AspNet_SqlCacheNotification_Trigger ‘ as its schema is different from the schema of the target table or view. Failed during cache dependency registration.
Please make sure the database name and the table name are valid. Table names must conform to the format of regular identifiers in SQL.
Cannot create trigger ‘Owner.TableName_AspNet_SqlCacheNotification_Trigger ‘ as its schema is different from the schema of the target table or view. Failed during cache dependency registration.
Please make sure the database name and the table name are valid. Table names must conform to the format of regular identifiers in SQL.
Ezt a bugot úgy tudjuk kiküszöbölni, ha a példaalkalmazás mappájában lévő New_Aspnet_SqlCacheRegisterTableStoredProcedure.sql-t futtatjuk az adott adatbázisnál!
Egyéb adatobjektumok gyorsítótárazása
DataSources – Cache
Az új ADO.NET 2.0 vezérlők, azon belül az adatforrás vezérlők (DataSource controls) mindegyike képes valamilyen szintű adat cachelésre (csak SqlDataSource-os kódot tartalmazza a példaalkalmazás!). Egyetlen dolgot igényel mindegyik, mégpedig azt, hogy a DataSourceMode DataSet legyen (ez az alapértelmezett is). A kívánságuk érthető, hiszen DataReader esetén nem készítünk másolatot az adatbázisról, ha mégis ezt próbálnánk meg használni, egy NotSupportedException-t fogunk kapni.
Alapjában véve, csak egyféleképpen lehet mindegyikben a gyorsítótárazást kikényszeríteni, kivéve az SqlDataSource-nál(2) illetve SiteMapDataSource-nál(0).
Az alábbi 4 tulajdonság segítségével finoman hangolhatjuk a cachelést:
DataSources – Cache
Az új ADO.NET 2.0 vezérlők, azon belül az adatforrás vezérlők (DataSource controls) mindegyike képes valamilyen szintű adat cachelésre (csak SqlDataSource-os kódot tartalmazza a példaalkalmazás!). Egyetlen dolgot igényel mindegyik, mégpedig azt, hogy a DataSourceMode DataSet legyen (ez az alapértelmezett is). A kívánságuk érthető, hiszen DataReader esetén nem készítünk másolatot az adatbázisról, ha mégis ezt próbálnánk meg használni, egy NotSupportedException-t fogunk kapni.
Alapjában véve, csak egyféleképpen lehet mindegyikben a gyorsítótárazást kikényszeríteni, kivéve az SqlDataSource-nál(2) illetve SiteMapDataSource-nál(0).
Az alábbi 4 tulajdonság segítségével finoman hangolhatjuk a cachelést:
– EnabledCache: gyorsítótárazás engedélyezése
– CacheDuration: elévülési idő (másodpercben kell megadni, a változatosság kedvéért)
– CacheExpirationPolicy: A CacheDuration-re tudjuk megszabni, hogy Abszolút (Absolute) vagy Csúszó (Sliding) idő legyen. Amint már erről fentebb is volt szó, az abszolút: a gyorsítótárba való elhelyezéstől számított Duration idő után évül el, míg a csúszó az utolsó hozzáféréstől számítva méri ugyanezt az időt!
– CacheDependencyKey: függőségi feltétel, bár ez kicsit eltér az eddig megszokottaktól. Ez a kulcs hivatkozik az összes olyan objektumra, melyet a datasource control hozott létre cacheléskor. Amint megváltozik a kulcs értéke, akkor a cache tartalma érvénytelenítődik. Kódból a legegyszerűbb érvényteleníteni.Nézzünk egy példát:
– CacheDuration: elévülési idő (másodpercben kell megadni, a változatosság kedvéért)
– CacheExpirationPolicy: A CacheDuration-re tudjuk megszabni, hogy Abszolút (Absolute) vagy Csúszó (Sliding) idő legyen. Amint már erről fentebb is volt szó, az abszolút: a gyorsítótárba való elhelyezéstől számított Duration idő után évül el, míg a csúszó az utolsó hozzáféréstől számítva méri ugyanezt az időt!
– CacheDependencyKey: függőségi feltétel, bár ez kicsit eltér az eddig megszokottaktól. Ez a kulcs hivatkozik az összes olyan objektumra, melyet a datasource control hozott létre cacheléskor. Amint megváltozik a kulcs értéke, akkor a cache tartalma érvénytelenítődik. Kódból a legegyszerűbb érvényteleníteni.Nézzünk egy példát:
<asp:AccessDataSource ID="ProductsDSource" runat="server"
DataFile="~/App_Data/Northwind.mdb"
SelectCommand="SELECT * FROM [Products]"
CacheDuration="30"
EnableCaching="True"
CacheKeyDependency="ProdDepKey">
</asp:AccessDataSource>
DataFile="~/App_Data/Northwind.mdb"
SelectCommand="SELECT * FROM [Products]"
CacheDuration="30"
EnableCaching="True"
CacheKeyDependency="ProdDepKey">
</asp:AccessDataSource>
void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
Cache[ProductsDSource.CacheKeyDependency] = someData;
}
void OnItemUpdated(object sender, DetailsViewUpdatedEventArgs e)
{
Cache.Remove(ProductsDSource.CacheKeyDependency);
GridView1.DataBind();
}
Miért is van erre szükség? Azért, mivel se az Object, se az XML, se az Access nem tartalmaz QN-t, így nekünk kell kézzel érvénytelenítenünk (legegyszerűbb megoldás: remove). De továbbra is szinkronba (konzisztensen) tartjuk a „kinézetet”, és ismét cacheljük az adatokat. Természetesen nem csak Update esetén kell ezt végrehajtatni, hanem Insert-nél, Delete-nél is!
SqlDataSource +1 cache
Az SqlDataSource kitüntetett a DataSource-ok között, mivel az SQL Server támogatja a QN-t. Így bekerült a tulajdonságai közé egy SqlDependency is. (VS05 Beta1 illetve Beta2 esetén még az AccessDataSource-nál is volt ilyen tulajdonság, bár NotSupportedException-t dobott, de szerencsére a véglegesbe már nem került bele).
Ez az SqlDependency viszont teljesen ugyanúgy működik, mint ahogy az QutputCache-nél (dependency_name:table_name). Lássuk a medvét:
Az SqlDataSource kitüntetett a DataSource-ok között, mivel az SQL Server támogatja a QN-t. Így bekerült a tulajdonságai közé egy SqlDependency is. (VS05 Beta1 illetve Beta2 esetén még az AccessDataSource-nál is volt ilyen tulajdonság, bár NotSupportedException-t dobott, de szerencsére a véglegesbe már nem került bele).
Ez az SqlDependency viszont teljesen ugyanúgy működik, mint ahogy az QutputCache-nél (dependency_name:table_name). Lássuk a medvét:
<asp:SqlDataSource Id="SqlDSource" runat="server"
ConnectionString= "<%$ConnectionStrings:localhost%>"
SelectCommand="SELECT ProductId AS Azon, Name AS Név, ProductNumber, Color FROM Production.Product Where Color Like ‘%Black%’"
DataSourceMode="DataSet"
EnableCaching="True"
CacheDuration="60"
CacheExpirationPolicy="Sliding"
SqlCacheDependency="AW:Production.Product">
</asp:SqlDataSource>
ConnectionString= "<%$ConnectionStrings:localhost%>"
SelectCommand="SELECT ProductId AS Azon, Name AS Név, ProductNumber, Color FROM Production.Product Where Color Like ‘%Black%’"
DataSourceMode="DataSet"
EnableCaching="True"
CacheDuration="60"
CacheExpirationPolicy="Sliding"
SqlCacheDependency="AW:Production.Product">
</asp:SqlDataSource>
Ezt pedig már csak meg be kell állítani egy GridView DataSourceId-jának. Ennyi az egész, és ugyanazt csinálja, mint az eddigi kódok. Egy megjegyzés: ez egy leheletnyivel lassabb, mint az QutputCache, de cserébe egyszerűbb használni (properties ablak!).
Konklúzió
Amint azt a cikkben láthattuk az SqlDependency és Cache együttműködésének köszönhetően, adataink gyorsítótárazása és emellett konzisztenciájuk megőrzése többé nem jelent problémát.
Végszóként, összességében a Query Notification egy nagyon hasznos dolog tud lenni, ha gyorsítani szeretnénk az alkalmazásunkat, és jobb teljesítményt akarunk elérni!
Amint azt a cikkben láthattuk az SqlDependency és Cache együttműködésének köszönhetően, adataink gyorsítótárazása és emellett konzisztenciájuk megőrzése többé nem jelent problémát.
Végszóként, összességében a Query Notification egy nagyon hasznos dolog tud lenni, ha gyorsítani szeretnénk az alkalmazásunkat, és jobb teljesítményt akarunk elérni!