Uso delle dipendenze della cache SQL (C#)

di Scott Mitchell

Scarica il PDF

La strategia di memorizzazione nella cache più semplice consiste nel consentire la scadenza dei dati memorizzati nella cache dopo un periodo di tempo specificato. Ma questo approccio semplice significa che i dati memorizzati nella cache non mantengono alcuna associazione con l'origine dati sottostante, causando dati non aggiornati che vengono mantenuti troppo lunghi o aggiornati che sono scaduti troppo presto. Un approccio migliore consiste nell'usare la classe SqlCacheDependency in modo che i dati rimangano memorizzati nella cache fino a quando i dati sottostanti non sono stati modificati nel database SQL. Questa esercitazione illustra come.

Introduzione

Le tecniche di memorizzazione nella cache esaminate nei dati di memorizzazione nella cache con objectDataSource e memorizzazione nella cache nelle esercitazioni sull'architettura hanno usato una scadenza basata sul tempo per rimuovere i dati dalla cache dopo un periodo specificato. Questo approccio è il modo più semplice per bilanciare i miglioramenti delle prestazioni della memorizzazione nella cache rispetto alla stalenza dei dati. Selezionando una scadenza temporale di x secondi, uno sviluppatore di pagine concede di godere dei vantaggi delle prestazioni della memorizzazione nella cache solo per x secondi, ma può essere facile che i dati non saranno mai obsoleti rispetto a un massimo di x secondi. Naturalmente, per i dati statici, x può essere esteso alla durata dell'applicazione Web, come è stato esaminato nell'esercitazione Memorizzazione nella cache dei dati all'avvio dell'applicazione .

Quando si memorizzano nella cache i dati del database, una scadenza basata sul tempo viene spesso scelta per la facilità d'uso, ma è spesso una soluzione inadeguata. Idealmente, i dati del database rimarranno memorizzati nella cache fino a quando i dati sottostanti non sono stati modificati nel database; solo la cache verrà rimossa. Questo approccio ottimizza i vantaggi delle prestazioni della memorizzazione nella cache e riduce al minimo la durata dei dati non aggiornati. Tuttavia, per usufruire di questi vantaggi, è necessario disporre di un sistema che sa quando i dati del database sottostante sono stati modificati ed espongono gli elementi corrispondenti dalla cache. Prima di ASP.NET 2.0, gli sviluppatori di pagine erano responsabili dell'implementazione di questo sistema.

ASP.NET 2.0 fornisce una classe e l'infrastruttura necessaria per determinare quando si è verificata una SqlCacheDependency modifica nel database in modo che gli elementi memorizzati nella cache corrispondenti possano essere rimossi. Esistono due tecniche per determinare quando i dati sottostanti sono stati modificati: notifica e polling. Dopo aver discusso delle differenze tra notifica e polling, verrà creata l'infrastruttura necessaria per supportare il polling e quindi si esaminerà come usare la SqlCacheDependency classe in scenari dichiarativi e a livello di codice.

Informazioni su notifica e polling

Esistono due tecniche che possono essere usate per determinare quando i dati in un database sono stati modificati: notifica e polling. Con la notifica, il database avvisa automaticamente il runtime di ASP.NET quando i risultati di una determinata query sono stati modificati dopo l'ultima esecuzione della query, a quel punto vengono eliminati gli elementi memorizzati nella cache associati alla query. Con il polling, il server di database gestisce informazioni su quando sono state aggiornate tabelle specifiche. Il runtime di ASP.NET esegue periodicamente il polling del database per verificare quali tabelle sono state modificate dopo l'immissione nella cache. Tali tabelle i cui dati sono stati modificati hanno eliminato gli elementi della cache associati.

L'opzione di notifica richiede meno configurazione rispetto al polling ed è più granulare poiché tiene traccia delle modifiche a livello di query anziché a livello di tabella. Sfortunatamente, le notifiche sono disponibili solo nelle edizioni complete di Microsoft SQL Server 2005 (ad esempio, le edizioni non Express). Tuttavia, l'opzione di polling può essere usata per tutte le versioni di Microsoft SQL Server da 7.0 a 2005. Poiché queste esercitazioni usano l'edizione Express di SQL Server 2005, ci concentreremo sulla configurazione e sull'uso dell'opzione di polling. Consultare la sezione Ulteriori letture alla fine di questa esercitazione per ulteriori risorse sulle funzionalità di notifica di SQL Server 2005.

Con il polling, il database deve essere configurato per includere una tabella denominata AspNet_SqlCacheTablesForChangeNotification con tre colonne, tableName, notificationCreatede changeId. Questa tabella contiene una riga per ogni tabella con dati che potrebbero essere usati in una dipendenza della cache SQL nell'applicazione Web. La tableName colonna specifica il nome della tabella mentre notificationCreated indica la data e l'ora di aggiunta della riga alla tabella. La changeId colonna è di tipo int e ha un valore iniziale pari a 0. Il valore viene incrementato con ogni modifica della tabella.

Oltre alla AspNet_SqlCacheTablesForChangeNotification tabella, il database deve includere anche trigger in ognuna delle tabelle che possono essere visualizzate in una dipendenza della cache SQL. Questi trigger vengono eseguiti ogni volta che una riga viene inserita, aggiornata o eliminata e incrementata il valore della changeId tabella in AspNet_SqlCacheTablesForChangeNotification.

Il runtime di ASP.NET tiene traccia dell'oggetto corrente changeId per una tabella durante la memorizzazione nella cache dei dati usando un SqlCacheDependency oggetto. Il database viene controllato periodicamente e tutti gli SqlCacheDependency oggetti che changeId differiscono dal valore del database vengono rimossi poiché un valore diverso changeId indica che è stata apportata una modifica alla tabella dal momento che i dati sono stati memorizzati nella cache.

Passaggio 1: Esplorazione del programma della rigaaspnet_regsql.exedi comando

Con l'approccio di polling il database deve essere configurato per contenere l'infrastruttura descritta in precedenza: una tabella predefinita (AspNet_SqlCacheTablesForChangeNotification), una manciata di stored procedure e trigger in ognuna delle tabelle che possono essere usate nelle dipendenze della cache SQL nell'applicazione Web. Queste tabelle, stored procedure e trigger possono essere creati tramite il programma aspnet_regsql.exedella $WINDOWS$\Microsoft.NET\Framework\version riga di comando , disponibile nella cartella. Per creare la AspNet_SqlCacheTablesForChangeNotification tabella e le stored procedure associate, eseguire le operazioni seguenti dalla riga di comando:

/* For SQL Server authentication... */
aspnet_regsql.exe -S server -U user -P password -d database -ed
/* For Windows Authentication... */
aspnet_regsql.exe -S server -E -d database -ed

Nota

Per eseguire questi comandi, l'account di accesso al database specificato deve trovarsi nei db_securityadmin ruoli e db_ddladmin .

Ad esempio, per aggiungere l'infrastruttura per il polling a un database Microsoft SQL Server denominato in un server di database denominato pubsScottsServer tramite l'autenticazione di Windows, passare alla directory appropriata e, dalla riga di comando, immettere:

aspnet_regsql.exe -S ScottsServer -E -d pubs -ed

Dopo l'aggiunta dell'infrastruttura a livello di database, è necessario aggiungere i trigger a tali tabelle che verranno usate nelle dipendenze della cache SQL. Usare di nuovo il aspnet_regsql.exe programma della riga di comando, ma specificare il nome della tabella usando l'opzione -t e anziché usare l'opzione -ed usa -et, come segue:

/* For SQL Server authentication... */
aspnet_regsql.exe -S <i>server</i>
-U <i>user</i> -P <i>password</i> -d <i>database</i> -t <i>tableName</i> -et
/* For Windows Authentication... */
aspnet_regsql.exe -S <i>server</i>
-E -d <i>database</i> -t <i>tableName</i> -et

Per aggiungere i trigger alle authors tabelle e titles nel pubs database in ScottsServer, usare:

aspnet_regsql.exe -S ScottsServer -E -d pubs -t authors -et
aspnet_regsql.exe -S ScottsServer -E -d pubs -t titles -et

Per questa esercitazione aggiungere i trigger alle Productstabelle , Categoriese Suppliers . Verrà esaminata la sintassi della riga di comando specifica nel passaggio 3.

Passaggio 2: Riferimento a un database di microsoft SQL Server 2005 Express Edition inApp_Data

Il aspnet_regsql.exe programma della riga di comando richiede il nome del database e del server per aggiungere l'infrastruttura di polling necessaria. Ma qual è il nome del database e del server per un database Express di Microsoft SQL Server 2005 che risiede nella App_Data cartella? Invece di dover individuare i nomi di database e server, è stato rilevato che l'approccio più semplice consiste nel collegare il database all'istanza del localhost\SQLExpress database e rinominare i dati usando SQL Server Management Studio. Se nel computer è installata una delle versioni complete di SQL Server 2005, è probabile che nel computer sia già installato SQL Server Management Studio. Se si ha solo l'edizione Express, è possibile scaricare microsoft SQL Server Management Studio Express Edition gratuito.

Iniziare chiudendo Visual Studio. Aprire quindi SQL Server Management Studio e scegliere di connettersi al server usando l'autenticazione localhost\SQLExpress di Windows.

Collegarsi al localhost\SQLExpress Server

Figura 1: Collegare al localhost\SQLExpress server

Dopo la connessione al server, Management Studio mostrerà il server e avrà sottocartelle per i database, la sicurezza e così via. Fare clic con il pulsante destro del mouse sulla cartella Database e scegliere l'opzione Collega. Verrà visualizzata la finestra di dialogo Collega database (vedere figura 2). Fare clic sul pulsante Aggiungi e selezionare la NORTHWND.MDF cartella di database nella cartella dell'applicazione App_Data Web.

Collegare NORTHWND. Database MDF dalla cartella App_Data

Figura 2: Collegare il database dalla App_Data cartella (fare clic per visualizzare l'immagineNORTHWND.MDF full-size)

Verrà aggiunto il database alla cartella Database. Il nome del database potrebbe essere il percorso completo del file di database o il percorso completo prependato con un GUID. Per evitare di dover digitare in questo nome di database lungo quando si usa lo strumento della riga di comando aspnet_regsql.exe, rinominare il database in un nome più descrittivo facendo clic con il pulsante destro del mouse sul database appena collegato e scegliendo Rinomina. Ho rinominato il database in DataTutorials .

Rinominare il database collegato in un nome più Human-Friendly

Figura 3: Rinominare il database collegato a un nome più Human-Friendly

Passaggio 3: Aggiunta dell'infrastruttura di polling al database Northwind

Dopo aver collegato il NORTHWND.MDF database dalla App_Data cartella, è possibile aggiungere l'infrastruttura di polling. Supponendo che il database sia stato rinominato in DataTutorials, eseguire i quattro comandi seguenti:

aspnet_regsql.exe -S localhost\SQLExpress -E -d DataTutorials -ed
aspnet_regsql.exe -S localhost\SQLExpress -E -d DataTutorials -t Products -et
aspnet_regsql.exe -S localhost\SQLExpress -E -d DataTutorials -t Categories -et
aspnet_regsql.exe -S localhost\SQLExpress -E -d DataTutorials -t Suppliers -et

Dopo aver eseguito questi quattro comandi, fare clic con il pulsante destro del mouse sul nome del database in Management Studio, passare al sottomenu Attività e scegliere Scollega. Chiudere Management Studio e riaprire Visual Studio.

Dopo aver riaperto Visual Studio, esaminare il database tramite Esplora server. Si noti la nuova tabella (AspNet_SqlCacheTablesForChangeNotification), le nuove stored procedure e i trigger nelle Productstabelle , Categoriese Suppliers .

Il database include ora l'infrastruttura di polling necessaria

Figura 4: il database include ora l'infrastruttura di polling necessaria

Passaggio 4: Configurazione del servizio di polling

Dopo aver creato le tabelle, i trigger e le stored procedure necessarie nel database, il passaggio finale consiste nel configurare il servizio di polling, che viene eseguito Web.config specificando i database da usare e la frequenza di polling in millisecondi. Il markup seguente esegue il polling del database Northwind una volta al secondo.

<?xml version="1.0"?>
<configuration>
   <connectionStrings>
      <add name="NORTHWNDConnectionString" connectionString=
          "Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\NORTHWND.MDF;
           Integrated Security=True;User Instance=True" 
           providerName="System.Data.SqlClient"/>
   </connectionStrings>
   <system.web>
      ...
      <!-- Configure the polling service used for SQL cache dependencies -->
      <caching>
         <sqlCacheDependency enabled="true" pollTime="1000" >
            <databases>
               <add name="NorthwindDB" 
                    connectionStringName="NORTHWNDConnectionString" />
            </databases>
         </sqlCacheDependency>
      </caching>
   </system.web>
</configuration>

Il name valore nell'elemento <add> ( NorthwindDB ) associa un nome leggibile a un determinato database. Quando si riguardano le dipendenze della cache SQL, è necessario fare riferimento al nome del database definito qui e alla tabella basata sui dati memorizzati nella cache. Verrà illustrato come usare la SqlCacheDependency classe per associare a livello di codice le dipendenze della cache SQL ai dati memorizzati nella cache nel passaggio 6.

Dopo aver stabilito una dipendenza della cache SQL, il sistema di polling si connetterà ai database definiti negli <databases> elementi ogni pollTime millisecondi ed eseguirà la AspNet_SqlCachePollingStoredProcedure stored procedure. Questa stored procedure, aggiunta al passaggio 3 usando lo aspnet_regsql.exe strumento della riga di comando, restituisce i tableName valori e changeId per ogni record in AspNet_SqlCacheTablesForChangeNotification. Le dipendenze della cache SQL obsolete vengono rimosse dalla cache.

L'impostazione pollTime introduce un compromesso tra prestazioni e non aggiornatità dei dati. Un valore ridotto pollTime aumenta il numero di richieste al database, ma più rapidamente elimina i dati non aggiornati dalla cache. Un valore maggiore pollTime riduce il numero di richieste di database, ma aumenta il ritardo tra quando i dati back-end cambiano e quando vengono eliminati gli elementi della cache correlati. Fortunatamente, la richiesta di database esegue una semplice stored procedure che restituisce solo poche righe da una tabella semplice e leggera. Provare tuttavia a usare valori diversi pollTime per trovare un equilibrio ideale tra l'accesso al database e l'decadimento dei dati per l'applicazione. Il valore più pollTime piccolo consentito è 500.

Nota

Nell'esempio precedente viene fornito un singolo pollTime valore nell'elemento <sqlCacheDependency> , ma facoltativamente è possibile specificare il pollTime valore nell'elemento <add> . Ciò è utile se sono stati specificati più database e si vuole personalizzare la frequenza di polling per ogni database.

Passaggio 5: Uso dichiarativo delle dipendenze della cache SQL

Nei passaggi da 1 a 4 è stato illustrato come configurare l'infrastruttura di database necessaria e configurare il sistema di polling. Con questa infrastruttura è ora possibile aggiungere elementi alla cache dei dati con una dipendenza della cache SQL associata usando tecniche programmatiche o dichiarative. In questo passaggio si esaminerà come usare in modo dichiarativo le dipendenze della cache SQL. Nel passaggio 6 verrà esaminato l'approccio programmatico.

L'esercitazione Memorizzazione nella cache dei dati con ObjectDataSource ha esaminato le funzionalità di memorizzazione nella cache dichiarativa di ObjectDataSource. Impostando semplicemente la EnableCaching proprietà su true e la CacheDuration proprietà su un intervallo di tempo, ObjectDataSource memorizza automaticamente nella cache i dati restituiti dall'oggetto sottostante per l'intervallo specificato. ObjectDataSource può anche usare una o più dipendenze della cache SQL.

Per illustrare l'uso delle dipendenze della cache SQL in modo dichiarativo, aprire la SqlCacheDependencies.aspx pagina nella Caching cartella e trascinare gridView dalla casella degli strumenti nella Designer. Impostare GridView su IDProductsDeclarative e, dallo smart tag, scegliere di associarlo a un nuovo ObjectDataSource denominato ProductsDataSourceDeclarative.

Creare un nuovo objectDataSource denominato ProductsDataSourceDeclarative

Figura 5: Creare un nuovo oggettoDataSource denominato ProductsDataSourceDeclarative (fare clic per visualizzare l'immagine a dimensione intera)

Configurare ObjectDataSource per usare la ProductsBLL classe e impostare l'elenco a discesa nella scheda SELECT su GetProducts(). Nella scheda UPDATE scegliere l'overload UpdateProduct con tre parametri di input: productName, unitPricee productID. Impostare gli elenchi a discesa su (Nessuno) nelle schede INSERT e DELETE.

Usare l'overload updateProduct con tre parametri di input

Figura 6: Usare l'overload updateProduct con tre parametri di input (fare clic per visualizzare l'immagine a dimensione intera)

Impostare l'elenco Drop-Down su (Nessuno) per le schede INSERT e DELETE

Figura 7: Impostare l'elenco Drop-Down su (Nessuno) per le schede INSERT e DELETE (fare clic per visualizzare l'immagine a dimensione intera)

Dopo aver completato la procedura guidata Configura origine dati, Visual Studio creerà BoundFields e CheckBoxFields in GridView per ognuno dei campi dati. Rimuovere tutti i campi, ma ProductName, CategoryNamee UnitPrice, e formattare questi campi in base alle esigenze. Dallo smart tag gridView selezionare le caselle di controllo Abilita paging, Abilita ordinamento e Abilita modifica. Visual Studio imposterà la proprietà original_{0}ObjectDataSource su OldValuesParameterFormatString . Affinché la funzionalità di modifica di GridView funzioni correttamente, rimuovere completamente questa proprietà dalla sintassi dichiarativa o impostarla nuovamente sul valore predefinito, {0}.

Aggiungere infine un controllo Web Etichetta sopra GridView e impostarne la ID proprietà su ODSEvents e la relativa EnableViewState proprietà su false. Dopo aver apportato queste modifiche, il markup dichiarativo della pagina dovrebbe essere simile al seguente. Si noti che sono state apportate numerose personalizzazioni estetiche ai campi GridView che non sono necessari per illustrare la funzionalità di dipendenza della cache SQL.

<asp:Label ID="ODSEvents" runat="server" EnableViewState="False" />
<asp:GridView ID="ProductsDeclarative" runat="server" 
    AutoGenerateColumns="False" DataKeyNames="ProductID" 
    DataSourceID="ProductsDataSourceDeclarative" 
    AllowPaging="True" AllowSorting="True">
    <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:TemplateField HeaderText="Product" SortExpression="ProductName">
            <EditItemTemplate>
                <asp:TextBox ID="ProductName" runat="server" 
                    Text='<%# Bind("ProductName") %>' />
                <asp:RequiredFieldValidator ID="RequiredFieldValidator1" 
                    ControlToValidate="ProductName" Display="Dynamic" 
                    ErrorMessage="You must provide a name for the product." 
                    SetFocusOnError="True"
                    runat="server">*</asp:RequiredFieldValidator>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label2" runat="server" 
                    Text='<%# Bind("ProductName") %>' />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="CategoryName" HeaderText="Category" 
            ReadOnly="True" SortExpression="CategoryName" />
        <asp:TemplateField HeaderText="Price" SortExpression="UnitPrice">
            <EditItemTemplate>
                $<asp:TextBox ID="UnitPrice" runat="server" Columns="8" 
                    Text='<%# Bind("UnitPrice", "{0:N2}") %>'></asp:TextBox>
                <asp:CompareValidator ID="CompareValidator1" runat="server" 
                    ControlToValidate="UnitPrice"
                    ErrorMessage="You must enter a valid currency value with 
                        no currency symbols. Also, the value must be greater than 
                        or equal to zero."
                    Operator="GreaterThanEqual" SetFocusOnError="True" 
                    Type="Currency" Display="Dynamic" 
                    ValueToCompare="0">*</asp:CompareValidator>
            </EditItemTemplate>
            <ItemStyle HorizontalAlign="Right" />
            <ItemTemplate>
                <asp:Label ID="Label1" runat="server" 
                    Text='<%# Bind("UnitPrice", "{0:c}") %>' />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSourceDeclarative" runat="server" 
    SelectMethod="GetProducts" TypeName="ProductsBLL" 
    UpdateMethod="UpdateProduct">
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="productID" Type="Int32" />
    </UpdateParameters>
</asp:ObjectDataSource>

Creare quindi un gestore eventi per l'evento ObjectDataSource e Selecting aggiungere il codice seguente:

protected void ProductsDataSourceDeclarative_Selecting
    (object sender, ObjectDataSourceSelectingEventArgs e)
{
    ODSEvents.Text = "-- Selecting event fired";
}

Tenere presente che l'evento ObjectDataSource viene Selecting generato solo durante il recupero dei dati dall'oggetto sottostante. Se ObjectDataSource accede ai dati dalla propria cache, questo evento non viene generato.

Visitare ora questa pagina tramite un browser. Poiché è ancora stato implementato qualsiasi memorizzazione nella cache, ogni volta che si esegue l'ordinamento, l'ordinamento o la griglia nella griglia verrà visualizzato il testo "Selezione dell'evento generato, come illustrato nella figura 8.

L'evento Di selezione di ObjectDataSource viene generato ogni volta che GridView viene sottoposto a paging, modificato o ordinato

Figura 8: L'evento ObjectDataSource viene Selecting generato ogni volta che GridView viene sottoposto a paging, modificato o ordinato (fare clic per visualizzare l'immagine a dimensione intera)

Come illustrato nell'esercitazione Memorizzazione nella cache dei dati con ObjectDataSource, l'impostazione della EnableCaching proprietà su true fa sì che ObjectDataSource memorizza nella cache i dati per la durata specificata dalla relativa CacheDuration proprietà. ObjectDataSource include anche una SqlCacheDependency proprietà che aggiunge una o più dipendenze della cache SQL ai dati memorizzati nella cache usando il modello :

databaseName1:tableName1;databaseName2:tableName2;...

Dove databaseName è il nome del database come specificato nell'attributo dell'elemento name<add> in Web.confige tableName è il nome della tabella di database. Ad esempio, per creare un ObjectDataSource che memorizza nella cache i dati a tempo indefinito in base a una dipendenza della cache SQL dalla tabella NorthwindProducts, impostare la proprietà true ObjectDataSource su EnableCaching e la relativa SqlCacheDependency proprietà su NorthwindDB:Products.

Nota

È possibile usare una dipendenza della cache SQL e una scadenza basata sul tempo impostando EnableCachingtruesu , CacheDuration sull'intervallo di tempo e SqlCacheDependency sui nomi del database e della tabella. ObjectDataSource rimuoverà i dati quando viene raggiunta la scadenza basata sul tempo o quando il sistema di polling rileva che i dati del database sottostanti sono stati modificati, a seconda di quale situazione si verifica per prima.

GridView in SqlCacheDependencies.aspx visualizza i dati di due tabelle e ProductsCategories (il campo del CategoryName prodotto viene recuperato tramite un oggetto JOIN su Categories). Si vogliono quindi specificare due dipendenze della cache SQL: NorthwindDB:Products; NorthwindDB:Categories .

Configurare ObjectDataSource per supportare la memorizzazione nella cache tramite dipendenze della cache SQL in prodotti e categorie

Figura 9: Configurare ObjectDataSource per supportare la memorizzazione nella cache usando le dipendenze della cache SQL in Products e Categories (fare clic per visualizzare l'immagine a dimensione intera)

Dopo aver configurato ObjectDataSource per supportare la memorizzazione nella cache, rivedere la pagina tramite un browser. Anche in questo caso, il testo 'Selezione evento generato dovrebbe essere visualizzato nella prima pagina visita, ma dovrebbe andare via durante il paging, l'ordinamento o facendo clic sui pulsanti Modifica o Annulla. Ciò è dovuto al fatto che dopo il caricamento dei dati nella cache objectDataSource rimane presente fino a quando le Products tabelle o Categories non vengono modificate o i dati vengono aggiornati tramite GridView.

Dopo aver eseguito il paging nella griglia e aver notato la mancanza del testo generato dall'evento di selezione, aprire una nuova finestra del browser e passare all'esercitazione Informazioni di base nella sezione Modifica, inserimento ed eliminazione (~/EditInsertDelete/Basics.aspx). Aggiornare il nome o il prezzo di un prodotto. Quindi, dalla prima finestra del browser, visualizzare una pagina diversa di dati, ordinare la griglia o fare clic sul pulsante Modifica di una riga. Questa volta, l'evento di selezione generato dovrebbe essere nuovamente visualizzato, perché i dati del database sottostanti sono stati modificati (vedere la figura 10). Se il testo non viene visualizzato, attendere alcuni istanti e riprovare. Tenere presente che il servizio di polling controlla le modifiche apportate alla Products tabella ogni pollTime millisecondo, pertanto si verifica un ritardo tra l'aggiornamento dei dati sottostanti e la rimozione dei dati memorizzati nella cache.

La modifica della tabella Products rimuove i dati del prodotto memorizzati nella cache

Figura 10: La modifica della tabella Products rimuove i dati del prodotto memorizzati nella cache (fare clic per visualizzare l'immagine a dimensione intera)

Passaggio 6: Utilizzo dellaSqlCacheDependencyclasse a livello di codice

L'esercitazione Memorizzazione nella cache dei dati nell'architettura ha esaminato i vantaggi dell'uso di un livello di memorizzazione nella cache separato nell'architettura anziché associare strettamente la memorizzazione nella cache con ObjectDataSource. In questa esercitazione è stata creata una ProductsCL classe per illustrare a livello di codice l'uso della cache dei dati. Per usare le dipendenze della cache SQL nel livello di memorizzazione nella cache, usare la SqlCacheDependency classe .

Con il sistema di polling, un SqlCacheDependency oggetto deve essere associato a una determinata coppia di database e tabelle. Il codice seguente, ad esempio, crea un SqlCacheDependency oggetto basato sulla tabella del Products database Northwind:

Caching.SqlCacheDependency productsTableDependency = 
    new Caching.SqlCacheDependency("NorthwindDB", "Products");

I due parametri di input per il SqlCacheDependency costruttore s sono rispettivamente i nomi di database e tabella. Analogamente alla proprietà ObjectDataSource, SqlCacheDependency il nome del database usato corrisponde al valore specificato nell'attributo dell'elemento name<add> in Web.config. Il nome della tabella è il nome effettivo della tabella di database.

Per associare un oggetto a un SqlCacheDependency elemento aggiunto alla cache dei dati, usare uno degli overload del Insert metodo che accetta una dipendenza. Il codice seguente aggiunge valore alla cache dei dati per una durata indefinita, ma la associa a una SqlCacheDependency nella Products tabella. In breve, il valore rimarrà nella cache finché non viene rimosso a causa di vincoli di memoria o perché il sistema di polling ha rilevato che la Products tabella è stata modificata dopo la memorizzazione nella cache.

Caching.SqlCacheDependency productsTableDependency = 
    new Caching.SqlCacheDependency("NorthwindDB", "Products");
Cache.Insert(key, 
             value, 
             productsTableDependency, 
             System.Web.Caching.Cache.NoAbsoluteExpiration, 
             System.Web.Caching.Cache.NoSlidingExpiration);

La classe Caching Layer attualmente ProductsCL memorizza nella cache i dati della Products tabella usando una scadenza basata sul tempo di 60 secondi. Aggiornare questa classe in modo che usi invece le dipendenze della cache SQL. Il ProductsCL metodo della AddCacheItem classe, responsabile dell'aggiunta dei dati alla cache, contiene attualmente il codice seguente:

private void AddCacheItem(string rawKey, object value)
{
    System.Web.Caching.Cache DataCache = HttpRuntime.Cache;
    // Make sure MasterCacheKeyArray[0] is in the cache
    DataCache[MasterCacheKeyArray[0]] = DateTime.Now;
    // Add a CacheDependency
    Caching.CacheDependency dependency =
        new Caching.CacheDependency(null, MasterCacheKeyArray);
    DataCache.Insert(GetCacheKey(rawKey), value, dependency, 
        DateTime.Now.AddSeconds(CacheDuration), 
        System.Web.Caching.Cache.NoSlidingExpiration);
}

Aggiornare questo codice per usare un SqlCacheDependency oggetto anziché la dipendenza della MasterCacheKeyArray cache:

private void AddCacheItem(string rawKey, object value)
{
    System.Web.Caching.Cache DataCache = HttpRuntime.Cache;
    // Add the SqlCacheDependency objects for Products
    Caching.SqlCacheDependency productsTableDependency = 
        new Caching.SqlCacheDependency("NorthwindDB", "Products");
    // Add the item to the data cache using productsTableDependency
    DataCache.Insert(GetCacheKey(rawKey), value, productsTableDependency, 
        Caching.Cache.NoAbsoluteExpiration, Caching.Cache.NoSlidingExpiration);
}

Per testare questa funzionalità, aggiungere un controllo GridView alla pagina sotto il controllo GridView esistente ProductsDeclarative . Impostare questo nuovo oggetto GridView su IDProductsProgrammatic e, tramite il relativo smart tag, associarlo a un nuovo ObjectDataSource denominato ProductsDataSourceProgrammatic. Configurare ObjectDataSource per l'uso della ProductsCL classe , impostando rispettivamente gli elenchi a discesa nelle schede GetProducts SELECT e UPDATE su e UpdateProduct.

Configurare ObjectDataSource per l'uso della classe ProductsCL

Figura 11: Configurare ObjectDataSource per l'uso della classe (fare clic per visualizzare l'immagineProductsCL a dimensione intera)

Selezionare il metodo GetProducts dall'elenco di Drop-Down della scheda SELECT

Figura 12: Selezionare il GetProducts metodo dall'elenco select tab Drop-Down (fare clic per visualizzare l'immagine a dimensione intera)

Scegliere il metodo UpdateProduct dall'elenco Drop-Down scheda UPDATE

Figura 13: Scegliere il metodo UpdateProduct dall'elenco Drop-Down scheda UPDATE (fare clic per visualizzare l'immagine a dimensione intera)

Dopo aver completato la procedura guidata Configura origine dati, Visual Studio creerà BoundFields e CheckBoxFields in GridView per ognuno dei campi dati. Come per il primo controllo GridView aggiunto a questa pagina, rimuovere tutti i campi, ma ProductName, CategoryNamee UnitPrice, e formattare questi campi in base alle esigenze. Dallo smart tag gridView selezionare le caselle di controllo Abilita paging, Abilita ordinamento e Abilita modifica. Come per ProductsDataSourceDeclarative ObjectDataSource, Visual Studio imposterà la ProductsDataSourceProgrammatic proprietà original_{0}ObjectDataSource su OldValuesParameterFormatString . Affinché la funzionalità di modifica di GridView funzioni correttamente, impostare nuovamente questa proprietà su {0} o rimuovere completamente l'assegnazione di proprietà dalla sintassi dichiarativa.

Dopo aver completato queste attività, il markup dichiarativo dichiarativo GridView e ObjectDataSource risultante dovrebbe essere simile al seguente:

<asp:GridView ID="ProductsProgrammatic" runat="server" 
    AutoGenerateColumns="False" DataKeyNames="ProductID" 
    DataSourceID="ProductsDataSourceProgrammatic" AllowPaging="True" 
    AllowSorting="True">
    <Columns>
        <asp:CommandField ShowEditButton="True" />
        <asp:TemplateField HeaderText="Product" SortExpression="ProductName">
            <EditItemTemplate>
                <asp:TextBox ID="ProductName" runat="server" 
                    Text='<%# Bind("ProductName") %>' />
                <asp:RequiredFieldValidator ID="RequiredFieldValidator1"  
                    ControlToValidate="ProductName" Display="Dynamic" 
                    ErrorMessage="You must provide a name for the product." 
                    SetFocusOnError="True"
                    runat="server">*</asp:RequiredFieldValidator>
            </EditItemTemplate>
            <ItemTemplate>
                <asp:Label ID="Label2" runat="server" 
                    Text='<%# Bind("ProductName") %>' />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField DataField="CategoryName" HeaderText="Category" 
            ReadOnly="True" SortExpression="CategoryName" />
        <asp:TemplateField HeaderText="Price" SortExpression="UnitPrice">
            <EditItemTemplate>
                $<asp:TextBox ID="UnitPrice" runat="server" Columns="8" 
                    Text='<%# Bind("UnitPrice", "{0:N2}") %>'></asp:TextBox>
                <asp:CompareValidator ID="CompareValidator1" runat="server" 
                    ControlToValidate="UnitPrice" Display="Dynamic" 
                    ErrorMessage="You must enter a valid currency value with 
                        no currency symbols. Also, the value must be greater than 
                        or equal to zero."
                    Operator="GreaterThanEqual" SetFocusOnError="True" 
                    Type="Currency" ValueToCompare="0">*</asp:CompareValidator>
            </EditItemTemplate>
            <ItemStyle HorizontalAlign="Right" />
            <ItemTemplate>
                <asp:Label ID="Label1" runat="server" 
                    Text='<%# Bind("UnitPrice", "{0:c}") %>' />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSourceProgrammatic" runat="server" 
    OldValuesParameterFormatString="{0}" SelectMethod="GetProducts" 
    TypeName="ProductsCL" UpdateMethod="UpdateProduct">
    <UpdateParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="productID" Type="Int32" />
    </UpdateParameters>
</asp:ObjectDataSource>

Per testare la dipendenza della cache SQL nel livello di memorizzazione nella cache, impostare un punto di interruzione nel ProductCL metodo della classe e AddCacheItem quindi avviare il debug. Quando si visita SqlCacheDependencies.aspxper la prima volta , il punto di interruzione deve essere raggiunto quando i dati vengono richiesti per la prima volta e inseriti nella cache. Passare quindi a un'altra pagina in GridView o ordinare una delle colonne. In questo modo GridView esegue nuovamente la query sui dati, ma i dati devono essere trovati nella cache perché la Products tabella di database non è stata modificata. Se i dati non sono stati trovati ripetutamente nella cache, assicurarsi che nel computer sia disponibile memoria sufficiente e riprovare.

Dopo aver eseguito il paging in alcune pagine di GridView, aprire una seconda finestra del browser e passare all'esercitazione Informazioni di base nella sezione Modifica, inserimento ed eliminazione (~/EditInsertDelete/Basics.aspx). Aggiornare un record dalla tabella Products e quindi, dalla prima finestra del browser, visualizzare una nuova pagina o fare clic su una delle intestazioni di ordinamento.

In questo scenario verrà visualizzato uno dei due elementi seguenti: verrà raggiunto il punto di interruzione, a indicare che i dati memorizzati nella cache sono stati rimossi a causa della modifica nel database; oppure, il punto di interruzione non verrà raggiunto, ovvero SqlCacheDependencies.aspx ora visualizza i dati non aggiornati. Se il punto di interruzione non viene raggiunto, è probabile che il servizio di polling non sia ancora stato attivato dopo la modifica dei dati. Tenere presente che il servizio di polling verifica le modifiche apportate alla Products tabella ogni pollTime millisecondi, pertanto si verifica un ritardo tra l'aggiornamento dei dati sottostanti e l'eliminazione dei dati memorizzati nella cache.

Nota

Questo ritardo è più probabile che venga visualizzato quando si modifica uno dei prodotti tramite GridView in SqlCacheDependencies.aspx. Nell'esercitazione Memorizzazione nella cache dei dati nell'esercitazione Sull'architettura è stata aggiunta la MasterCacheKeyArray dipendenza della cache per assicurarsi che i dati modificati tramite il ProductsCL metodo della UpdateProduct classe siano stati rimossi dalla cache. Tuttavia, questa dipendenza della cache è stata sostituita quando si modifica il AddCacheItem metodo precedente in questo passaggio e pertanto la ProductsCL classe continuerà a visualizzare i dati memorizzati nella cache fino a quando il sistema di polling non annota la modifica alla Products tabella. Verrà illustrato come reintrodurre la dipendenza della MasterCacheKeyArray cache nel passaggio 7.

Passaggio 7: Associazione di più dipendenze con un elemento memorizzato nella cache

Tenere presente che la MasterCacheKeyArray dipendenza della cache viene usata per assicurarsi che tutti i dati correlati al prodotto vengano rimossi dalla cache quando viene aggiornato qualsiasi singolo elemento associato. Ad esempio, le istanze del GetProductsByCategoryID(categoryID) metodo memorizzano ProductsDataTables nella cache le istanze per ogni valore categoryID univoco. Se uno di questi oggetti viene rimosso, la dipendenza della MasterCacheKeyArray cache garantisce che anche gli altri vengano rimossi. Senza questa dipendenza della cache, quando i dati memorizzati nella cache vengono modificati, la possibilità che altri dati del prodotto memorizzati nella cache non siano aggiornati. Di conseguenza, è importante mantenere la dipendenza della MasterCacheKeyArray cache quando si usano le dipendenze della cache SQL. Tuttavia, il metodo della Insert cache dei dati consente solo un singolo oggetto di dipendenza.

Inoltre, quando si usano dipendenze della cache SQL, potrebbe essere necessario associare più tabelle di database come dipendenze. Ad esempio, la ProductsDataTable cache nella ProductsCL classe contiene i nomi di categoria e fornitori per ogni prodotto, ma il AddCacheItem metodo usa solo una dipendenza da Products. In questa situazione, se l'utente aggiorna il nome di una categoria o un fornitore, i dati del prodotto memorizzati nella cache rimarranno nella cache e non saranno aggiornati. Pertanto, si vuole rendere i dati del prodotto memorizzati nella cache non solo sulla Products tabella, ma anche sulle Categories tabelle e Suppliers .

La AggregateCacheDependency classe fornisce un mezzo per associare più dipendenze a un elemento della cache. Iniziare creando un'istanza AggregateCacheDependency . Aggiungere quindi il set di dipendenze usando il AggregateCacheDependency metodo s Add . Quando si inserisce l'elemento nella cache dei dati successivamente, passare l'istanza AggregateCacheDependency . Quando una delle dipendenze dell'istanza cambia, l'elemento AggregateCacheDependency memorizzato nella cache verrà rimosso.

Di seguito viene illustrato il codice aggiornato per il ProductsCL metodo della AddCacheItem classe. Il metodo crea la dipendenza della MasterCacheKeyArray cache insieme agli SqlCacheDependency oggetti per le Productstabelle , Categoriese Suppliers . Questi sono tutti combinati in un AggregateCacheDependency oggetto denominato aggregateDependencies, che viene quindi passato al Insert metodo .

private void AddCacheItem(string rawKey, object value)
{
    System.Web.Caching.Cache DataCache = HttpRuntime.Cache;
    // Make sure MasterCacheKeyArray[0] is in the cache and create a depedency
    DataCache[MasterCacheKeyArray[0]] = DateTime.Now;
    Caching.CacheDependency masterCacheKeyDependency = 
        new Caching.CacheDependency(null, MasterCacheKeyArray);
    // Add the SqlCacheDependency objects for Products, Categories, and Suppliers
    Caching.SqlCacheDependency productsTableDependency = 
        new Caching.SqlCacheDependency("NorthwindDB", "Products");
    Caching.SqlCacheDependency categoriesTableDependency = 
        new Caching.SqlCacheDependency("NorthwindDB", "Categories");
    Caching.SqlCacheDependency suppliersTableDependency = 
        new Caching.SqlCacheDependency("NorthwindDB", "Suppliers");
    // Create an AggregateCacheDependency
    Caching.AggregateCacheDependency aggregateDependencies = 
        new Caching.AggregateCacheDependency();
    aggregateDependencies.Add(masterCacheKeyDependency, productsTableDependency, 
        categoriesTableDependency, suppliersTableDependency);
    DataCache.Insert(GetCacheKey(rawKey), value, aggregateDependencies, 
        Caching.Cache.NoAbsoluteExpiration, Caching.Cache.NoSlidingExpiration);
}

Testare questo nuovo codice. Le modifiche apportate alle tabelle , Categorieso Suppliers causano l'eliminazione dei dati memorizzati nella Productscache. Inoltre, il ProductsCL metodo della UpdateProduct classe, che viene chiamato quando si modifica un prodotto tramite GridView, elimina la dipendenza della cache, che causa l'eliminazione MasterCacheKeyArray della cache ProductsDataTable e il recupero dei dati nella richiesta successiva.

Nota

Le dipendenze della cache SQL possono essere usate anche con la memorizzazione nella cache di output. Per una dimostrazione di questa funzionalità, vedere: Uso della cache di output ASP.NET con SQL Server.

Riepilogo

Quando si memorizzano nella cache i dati, i dati rimarranno idealmente nella cache finché non verranno modificati nel database. Con ASP.NET 2.0, è possibile creare e usare le dipendenze della cache SQL in scenari dichiarativi e programmatici. Una delle sfide con questo approccio consiste nell'individuare quando i dati sono stati modificati. Le versioni complete di Microsoft SQL Server 2005 forniscono funzionalità di notifica che possono avvisare un'applicazione quando è stato modificato un risultato della query. Per Express Edition di SQL Server 2005 e versioni precedenti di SQL Server, è necessario usare invece un sistema di polling. Fortunatamente, la configurazione dell'infrastruttura di polling necessaria è abbastanza semplice.

Programmazione felice!

Altre informazioni

Per altre informazioni sugli argomenti illustrati in questa esercitazione, vedere le risorse seguenti:

Informazioni sull'autore

Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, ha lavorato con le tecnologie Microsoft Web dal 1998. Scott lavora come consulente indipendente, allenatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2,0 in 24 Ore. Può essere raggiunto a mitchell@4GuysFromRolla.com. o tramite il suo blog, che può essere trovato in http://ScottOnWriting.NET.

Grazie speciali

Questa serie di esercitazioni è stata esaminata da molti revisori utili. I revisori principali per questa esercitazione sono stati Marko Rangel, Teresa Murphy e Hilton Giesenow. Interessati a esaminare i prossimi articoli MSDN? In tal caso, lasciami una riga in mitchell@4GuysFromRolla.com.