Partilhar via


Usando dependências de cache SQL (VB)

por Scott Mitchell

Descarregar PDF

A estratégia de cache mais simples é permitir que os dados armazenados em cache expirem após um período de tempo especificado. Mas essa abordagem simples significa que os dados armazenados em cache não mantêm nenhuma associação com sua fonte de dados subjacente, resultando em dados obsoletos que são mantidos por muito tempo ou dados atuais que expiram muito cedo. Uma abordagem melhor é usar a classe SqlCacheDependency para que os dados permaneçam armazenados em cache até que seus dados subjacentes tenham sido modificados no banco de dados SQL. Este tutorial mostra como.

Introdução

As técnicas de cache examinadas nos tutoriais Caching Data with the ObjectDataSource e Caching Data nos tutoriais Architecture usaram uma expiração baseada em tempo para remover os dados do cache após um período especificado. Essa abordagem é a maneira mais simples de equilibrar os ganhos de desempenho do cache em relação à obsolescência dos dados. Ao selecionar uma expiração de tempo de x segundos, um desenvolvedor de página admite aproveitar os benefícios de desempenho do cache por apenas x segundos, mas pode ficar tranquilo que seus dados nunca ficarão obsoletos por mais do que um máximo de x segundos. É claro que, para dados estáticos, x pode ser estendido até o tempo de vida do aplicativo Web, como foi examinado no tutorial Caching Data at Application Startup .

Ao armazenar dados de banco de dados em cache, uma expiração baseada no tempo é frequentemente escolhida por sua facilidade de uso, mas frequentemente é uma solução inadequada. Idealmente, os dados da base de dados permaneceriam armazenados em cache até que os dados subjacentes tenham sido modificados na base de dados; só então o cache seria despejado. Essa abordagem maximiza os benefícios de desempenho do cache e minimiza a duração dos dados obsoletos. No entanto, para aproveitar esses benefícios, deve haver algum sistema em vigor que saiba quando os dados do banco de dados subjacente foram modificados e remova os itens correspondentes do cache. Antes do ASP.NET 2.0, os desenvolvedores de páginas eram responsáveis pela implementação deste sistema.

ASP.NET 2.0 fornece uma SqlCacheDependency classe e a infraestrutura necessária para determinar quando ocorreu uma alteração no banco de dados para que os itens em cache correspondentes possam ser removidos. Existem duas técnicas para determinar quando os dados subjacentes foram alterados: notificação e sondagem. Depois de discutir as diferenças entre notificação e sondagem, criaremos a infraestrutura necessária para dar suporte à sondagem e, em seguida, exploraremos como usar a SqlCacheDependency classe em cenários declarativos e programáticos.

Noções básicas sobre notificação e sondagem

Há duas técnicas que podem ser usadas para determinar quando os dados em um banco de dados foram modificados: notificação e sondagem. Com a notificação, o banco de dados alerta automaticamente o tempo de execução do ASP.NET quando os resultados de uma consulta específica foram alterados desde a última vez que a consulta foi executada, momento em que os itens armazenados em cache associados à consulta são removidos. Com a sondagem, o servidor de banco de dados mantém informações sobre quando determinadas tabelas foram atualizadas pela última vez. O tempo de execução do ASP.NET sonda periodicamente o banco de dados para verificar quais tabelas foram alteradas desde que foram inseridas no cache. As tabelas cujos dados foram modificados têm seus itens de cache associados removidos.

A opção de notificação requer menos configuração do que a sondagem e é mais granular, pois controla as alterações no nível da consulta em vez do nível da tabela. Infelizmente, as notificações só estão disponíveis nas edições completas do Microsoft SQL Server 2005 (ou seja, as edições não Express). No entanto, a opção de sondagem pode ser usada para todas as versões do Microsoft SQL Server de 7.0 a 2005. Como esses tutoriais usam a edição Express do SQL Server 2005, nos concentraremos na configuração e no uso da opção de sondagem. Consulte a seção Leitura adicional no final deste tutorial para obter mais recursos sobre os recursos de notificação do SQL Server 2005.

Com a sondagem, o banco de dados deve ser configurado para incluir uma tabela nomeada AspNet_SqlCacheTablesForChangeNotification que tenha três colunas - tableName, notificationCreatede changeId. Esta tabela contém uma linha para cada tabela que tem dados que podem precisar ser usados em uma dependência de cache SQL no aplicativo Web. A tableName coluna especifica o nome da tabela enquanto notificationCreated indica a data e a hora em que a linha foi adicionada à tabela. A changeId coluna é do tipo int e tem um valor inicial de 0. Seu valor é incrementado a cada modificação na tabela.

Além da AspNet_SqlCacheTablesForChangeNotification tabela, o banco de dados também precisa incluir gatilhos em cada uma das tabelas que podem aparecer em uma dependência de cache SQL. Esses gatilhos são executados sempre que uma linha é inserida, atualizada ou excluída e incrementam o valor da changeId tabela em AspNet_SqlCacheTablesForChangeNotification.

O tempo de execução do ASP.NET rastreia o atual changeId de uma tabela ao armazenar dados em cache usando um objeto SqlCacheDependency. O banco de dados é verificado periodicamente e todos os SqlCacheDependency objetos que changeId diferem do valor no banco de dados são removidos, uma vez que um valor diferente changeId indica que houve uma alteração na tabela desde que os dados foram armazenados em cache.

Etapa 1: Explorar o programa de linha de comandosaspnet_regsql.exe

Com a abordagem de sondagem, o banco de dados deve ser configurado para conter a infraestrutura descrita acima: uma tabela predefinida (AspNet_SqlCacheTablesForChangeNotification), um punhado de procedimentos armazenados e gatilhos em cada uma das tabelas que podem ser usadas em dependências de cache SQL no aplicativo Web. Essas tabelas, procedimentos armazenados e gatilhos podem ser criados através do programa aspnet_regsql.exede linha de comando, que é encontrado na $WINDOWS$\Microsoft.NET\Framework\version pasta. Para criar a tabela e os AspNet_SqlCacheTablesForChangeNotification procedimentos armazenados associados, execute o seguinte na linha de 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

Observação

Para executar esses comandos, o logon do banco de dados especificado deve estar nas funções db_securityadmin e db_ddladmin.

Por exemplo, para adicionar a infraestrutura de sondagem a um banco de dados do Microsoft SQL Server nomeado pubs em um servidor de banco de dados nomeado ScottsServer usando a Autenticação do Windows, navegue até o diretório apropriado e, na linha de comando, digite:

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

Depois que a infraestrutura no nível de banco de dados tiver sido adicionada, precisamos adicionar os gatilhos às tabelas que serão usadas nas dependências do cache SQL. Utilize o programa de linha de comando aspnet_regsql.exe novamente, mas especifique o nome da tabela utilizando a opção -t e, em vez de usar a opção -ed, use -et, desta forma:

/* 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

Para adicionar os gatilhos às tabelas authors e titles na base de dados pubs em ScottsServer, use:

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

Para este tutorial, adicione os gatilhos às tabelas Products, Categories e Suppliers. Examinaremos a sintaxe de linha de comando específica na Etapa 3.

Etapa 2: Fazendo referência a um banco de dados do Microsoft SQL Server 2005 Express Edition emApp_Data

O aspnet_regsql.exe programa de linha de comando requer o banco de dados e o nome do servidor para adicionar a infraestrutura de sondagem necessária. Mas qual é o nome do banco de dados e do servidor para um banco de dados do Microsoft SQL Server 2005 Express que reside na App_Data pasta? Em vez de ter que descobrir quais são os nomes do banco de dados e do servidor, descobri que a abordagem mais simples é anexar o banco de dados à instância do banco de dados e renomear os dados usando o localhost\SQLExpressSQL Server Management Studio. Se você tiver uma das versões completas do SQL Server 2005 instalada em sua máquina, provavelmente já terá o SQL Server Management Studio instalado em seu computador. Se você tiver apenas a edição Express, poderá baixar gratuitamente o Microsoft SQL Server Management Studio.

Comece fechando o Visual Studio. Em seguida, abra o SQL Server Management Studio e escolha se conectar ao servidor usando a Autenticação do localhost\SQLExpress Windows.

Anexar ao localhost\SQLExpress Server

Figura 1: Anexar ao localhost\SQLExpress servidor

Depois de se conectar ao servidor, o Management Studio mostrará o servidor e terá subpastas para os bancos de dados, segurança e assim por diante. Clique com o botão direito do mouse na pasta Bancos de dados e escolha a opção Anexar. Isso abrirá a caixa de diálogo Anexar bancos de dados (consulte a Figura 2). Clique no botão Adicionar e selecione a NORTHWND.MDF pasta do banco de dados na pasta do App_Data aplicativo Web.

Anexe a base de dados NORTHWND.MDF da pasta App_Data

Figura 2: Anexar a NORTHWND.MDF Base de Dados da App_Data Pasta (Clique para visualizar a imagem em tamanho real)

Isso adicionará o banco de dados à pasta Bancos de dados. O nome do banco de dados pode ser o caminho completo para o arquivo de banco de dados ou o caminho completo precedido de um GUID. Para evitar ter que digitar esse nome de banco de dados extenso ao usar a ferramenta de linha de comando aspnet_regsql.exe, renomeie o banco de dados para um nome mais amigável ao ser humano clicando com o botão direito do mouse no banco de dados anexado e escolhendo Renomear. Eu renomeei meu banco de dados para DataTutorials .

Renomeie o banco de dados anexado para um nome mais Human-Friendly

Figura 3: Renomear a base de dados anexada para um nome mais apropriado Human-Friendly

Etapa 3: Adicionando a infraestrutura de sondagem ao banco de dados Northwind

Agora que anexamos o NORTHWND.MDF banco de dados da App_Data pasta, estamos prontos para adicionar a infraestrutura de sondagem. Supondo que você tenha renomeado o banco de dados para DataTutorials, execute os quatro comandos a seguir:

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

Depois de executar esses quatro comandos, clique com o botão direito do mouse no nome do banco de dados no Management Studio, vá para o submenu Tarefas e escolha Desanexar. Em seguida, feche o Management Studio e reabra o Visual Studio.

Depois que o Visual Studio for reaberto, analise o banco de dados por meio do Gerenciador de Servidores. Observe a nova tabela (AspNet_SqlCacheTablesForChangeNotification), os novos procedimentos armazenados, e os gatilhos nas tabelas Products, Categories e Suppliers.

A base de dados inclui agora a infraestrutura de sondagem necessária

Figura 4: O banco de dados agora inclui a infraestrutura de sondagem necessária

Etapa 4: Configurando o serviço de sondagem

Depois de criar as tabelas, gatilhos e procedimentos armazenados necessários no banco de dados, a etapa final é configurar o serviço de sondagem, o que é feito especificando Web.config os bancos de dados a serem usados e a frequência de sondagem em milissegundos. O código seguinte sonda o banco de dados Northwind a cada segundo.

<?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>

O name valor no <add> elemento ( NorthwindDB ) associa um nome legível por humanos a um banco de dados específico. Ao trabalhar com dependências de cache SQL, precisaremos nos referir ao nome do banco de dados definido aqui, bem como à tabela na qual os dados armazenados em cache se baseiam. Veremos como usar a SqlCacheDependency classe para associar programaticamente dependências de cache SQL com dados armazenados em cache na Etapa 6.

Uma vez estabelecida uma dependência de cache SQL, o sistema de sondagem irá ligar-se aos bases de dados definidos nos elementos <databases> a cada pollTime milissegundos e executará a procedure armazenada AspNet_SqlCachePollingStoredProcedure. ** Esse procedimento armazenado - que foi reintroduzido na Etapa 3 usando a ferramenta de linha de comandos aspnet_regsql.exe - retorna os valores de tableName e changeId para cada registro no AspNet_SqlCacheTablesForChangeNotification. Dependências desatualizadas do cache SQL são removidas do cache.

A pollTime configuração introduz uma compensação entre desempenho e obsolescência de dados. Um pequeno pollTime valor aumenta o número de solicitações para o banco de dados, mas mais rapidamente remove dados obsoletos do cache. Um valor maior pollTime reduz o número de solicitações de banco de dados, mas aumenta o atraso entre quando os dados de back-end são alterados e quando os itens de cache relacionados são removidos. Felizmente, a solicitação de banco de dados está executando um procedimento armazenado simples que retorna apenas algumas linhas de uma tabela simples e leve. Mas experimente valores diferentes pollTime para encontrar um equilíbrio ideal entre o acesso ao banco de dados e a obsolescência de dados para seu aplicativo. O menor pollTime valor permitido é 500.

Observação

O exemplo acima fornece um único pollTime valor no <sqlCacheDependency> elemento , mas você pode, opcionalmente, especificar o pollTime valor no <add> elemento . Isso é útil se você tiver vários bancos de dados especificados e quiser personalizar a frequência de sondagem por banco de dados.

Etapa 5: Trabalhando declarativamente com dependências de cache SQL

Nas etapas 1 a 4, examinamos como configurar a infraestrutura de banco de dados necessária e configurar o sistema de sondagem. Com essa infraestrutura instalada, agora podemos adicionar itens ao cache de dados com uma dependência de cache SQL associada usando técnicas programáticas ou declarativas. Nesta etapa, examinaremos como trabalhar declarativamente com dependências de cache SQL. Na Etapa 6, veremos a abordagem programática.

O tutorial Caching Data with the ObjectDataSource explorou os recursos de cache declarativo do ObjectDataSource. Simplesmente definindo a EnableCaching propriedade como True e a CacheDuration propriedade para algum intervalo de tempo, o ObjectDataSource armazenará automaticamente em cache os dados retornados de seu objeto subjacente para o intervalo especificado. O ObjectDataSource também pode usar uma ou mais dependências de cache SQL.

Para demonstrar o uso declarativo de dependências de cache SQL, abra a página SqlCacheDependencies.aspx na pasta Caching e arraste um GridView da Caixa de Ferramentas para o Designer. Defina o GridView ID como ProductsDeclarative e, a partir da sua tag inteligente, escolha vinculá-lo a um novo ObjectDataSource chamado ProductsDataSourceDeclarative.

Criar um novo ObjectDataSource chamado ProductsDataSourceDeclarative

Figura 5: Criar um novo ObjectDataSource nomeado ProductsDataSourceDeclarative (Clique para visualizar a imagem em tamanho real)

Configure o ObjectDataSource para usar a classe ProductsBLL e configure a lista suspensa na aba SELECT como GetProducts(). Na guia UPDATE, escolha a UpdateProduct sobrecarga com três parâmetros de entrada - productName, unitPricee productID. Defina as listas suspensas como (Nenhum) nas guias INSERIR e EXCLUIR.

Use a sobrecarga do método UpdateProduct com três parâmetros de entrada

Figura 6: Usar a sobrecarga UpdateProduct com três parâmetros de entrada (Clique para visualizar a imagem em tamanho real)

Defina a lista de Drop-Down como (Nenhum) para as guias INSERT e DELETE

Figura 7: Defina a lista de Drop-Down como (Nenhum) para as guias INSERT e DELETE (Clique para visualizar a imagem em tamanho real)

Depois de concluir o assistente Configurar Fonte de Dados, o Visual Studio criará BoundFields e CheckBoxFields no GridView para cada um dos campos de dados. Remova todos os campos, exceto ProductName, CategoryName, e UnitPrice, e formate esses campos como achar melhor. Na etiqueta inteligente do GridView, marque as caixas de seleção Ativar paginação, Ativar classificação e Ativar edição. O Visual Studio definirá a propriedade s OldValuesParameterFormatString de ObjectDataSource como original_{0}. Para que o recurso de edição de GridView funcione corretamente, remova essa propriedade inteiramente da sintaxe declarativa ou defina-a de volta ao seu valor padrão, {0}.

Finalmente, adicione um controle Web Label acima de GridView e defina sua ID propriedade como ODSEvents e sua EnableViewState propriedade como False. Depois de fazer essas alterações, a marcação declarativa da página deve ser semelhante à seguinte. Observe que fiz várias personalizações estéticas nos campos GridView que não são necessárias para demonstrar a funcionalidade de dependência do 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>

Em seguida, crie um manipulador de eventos para o evento ObjectDataSource s Selecting e nele adicione o seguinte código:

Protected Sub ProductsDataSourceDeclarative_Selecting _
    (sender As Object, e As ObjectDataSourceSelectingEventArgs) _
    Handles ProductsDataSourceDeclarative.Selecting
    ODSEvents.Text = "-- Selecting event fired"
End Sub

Lembre-se de que o evento Selecting do ObjectDataSource é acionado apenas ao recuperar dados do seu objeto subjacente. Se o ObjectDataSource acessa os dados de seu próprio cache, esse evento não é acionado.

Agora, visite esta página através de um navegador. Como ainda não implementámos nenhum caching, cada vez que navega, classifica ou edita a grade, a página deverá exibir o texto 'Evento de seleção disparado', como mostra a Figura 8.

O evento de seleção de ObjectDataSource é acionado cada vez que o GridView é paginado, editado ou classificado

Figura 8: O evento de ObjectDataSource é Selecting acionado cada vez que o GridView é paginado, editado ou classificado (Clique para visualizar a imagem em tamanho real)

Como vimos no tutorial Caching Data with the ObjectDataSource , definir a EnableCaching propriedade para True faz com que o ObjectDataSource armazene seus dados em cache pela duração especificada por sua CacheDuration propriedade. O ObjectDataSource também tem uma SqlCacheDependency propriedade, que adiciona uma ou mais dependências de cache SQL aos dados armazenados em cache usando o padrão:

databaseName1:tableName1;databaseName2:tableName2;...

Onde databaseName é o nome do banco de dados conforme especificado no name atributo do <add> elemento em Web.config, e tableName é o nome da tabela do banco de dados. Por exemplo, para criar um ObjectDataSource que armazena dados em cache indefinidamente com base em uma dependência de cache SQL em relação à tabela Northwind Products, defina a propriedade EnableCaching de ObjectDataSource como True e a propriedade SqlCacheDependency como NorthwindDB:Products.

Observação

Você pode usar uma dependência de cache SQL e uma expiração baseada em tempo definindo EnableCaching como True, CacheDuration para o intervalo de tempo e SqlCacheDependency para o(s) nome(s) do banco de dados e da tabela. O ObjectDataSource removerá seus dados quando a expiração baseada no tempo for atingida ou quando o sistema de sondagem notar que os dados do banco de dados subjacente foram alterados, o que acontecer primeiro.

O GridView no SqlCacheDependencies.aspx exibe dados de duas tabelas - Products e Categories (o campo do produto CategoryName é recuperado através de um JOIN em Categories). Portanto, queremos especificar duas dependências de cache SQL: NorthwindDB:Products; NorthwindDB:Categorias .

Configurar o ObjectDataSource para dar suporte ao cache usando dependências de cache SQL em produtos e categorias

Figura 9: Configurar o ObjectDataSource para dar suporte ao cache usando dependências de cache SQL em Products e Categories (Clique para exibir a imagem em tamanho real)

Depois de configurar o ObjectDataSource para suportar o cache, revisite a página através de um navegador. Novamente, o texto "Selecionando evento disparado deve aparecer na primeira visita à página, mas deve desaparecer ao paginar, classificar ou clicar nos botões Editar ou Cancelar. Isso ocorre porque depois que os dados são carregados no cache de ObjectDataSource, eles permanecem lá até que as Products tabelas ou Categories sejam modificadas ou os dados sejam atualizados por meio do GridView.

Depois de percorrer a grelha e notar a ausência do texto 'Selecting event fired', abra uma nova janela do browser e navegue até o tutorial de Noções básicas na secção Edição, Inserção e Exclusão (~/EditInsertDelete/Basics.aspx). Atualize o nome ou o preço de um produto. Em seguida, a partir da primeira janela do navegador, visualize uma página de dados diferente, classifique a grade ou clique no botão Editar de uma linha. Desta vez, o evento de "seleção disparado" deve aparecer novamente, pois os dados do banco de dados subjacente foram modificados (veja a Figura 10). Se o texto não aparecer, aguarde alguns momentos e tente novamente. Lembre-se de que o serviço de sondagem está verificando alterações na tabela a Products cada pollTime milissegundos, portanto, há um atraso entre quando os dados subjacentes são atualizados e quando os dados armazenados em cache são removidos.

A modificação da tabela Produtos elimina os dados do produto armazenados em cache

Figura 10: Modificar a tabela Produtos Elimina os dados do produto em cache (Clique para visualizar a imagem em tamanho real)

Etapa 6: Trabalhando programaticamente com aSqlCacheDependencyclasse

O tutorial Caching Data in the Architecture analisou os benefícios de usar uma camada de cache separada na arquitetura, em vez de acoplar firmemente o cache com o ObjectDataSource. Nesse tutorial, criamos uma ProductsCL classe para demonstrar programaticamente o trabalho com o cache de dados. Para utilizar dependências de cache SQL na camada de cache, use a SqlCacheDependency classe.

Com o sistema de sondagem, um SqlCacheDependency objeto deve ser associado a um determinado banco de dados e par de tabelas. O código a seguir, por exemplo, cria um SqlCacheDependency objeto com base na tabela s do Products banco de dados Northwind:

Dim productsTableDependency As _
    New Caching.SqlCacheDependency("NorthwindDB", "Products")

Os dois parâmetros de entrada para o construtor do SqlCacheDependency são o nome do banco de dados e o nome da tabela, respectivamente. Como com a propriedade s SqlCacheDependency de ObjectDataSource, o nome do banco de dados usado é o mesmo que o valor especificado no name atributo do <add> elemento em Web.config. O nome da tabela é o nome real da tabela do banco de dados.

Para associar um SqlCacheDependency a um item adicionado ao cache de dados, use uma das Insert sobrecargas de método que aceitam uma dependência. O código a seguir adiciona valor ao cache de dados por uma duração indefinida, mas associa-o a um SqlCacheDependency na tabela Products. Em resumo, o valor permanecerá no cache até que seja removido devido a restrições de memória ou porque o sistema de sondagem detetou que a Products tabela foi alterada desde que foi armazenada em cache.

Dim productsTableDependency As _
    New Caching.SqlCacheDependency("NorthwindDB", "Products")
Cache.Insert(key, _
             value, _ 
             productsTableDependency, _
             System.Web.Caching.Cache.NoAbsoluteExpiration, _
             System.Web.Caching.Cache.NoSlidingExpiration)

A classe s ProductsCL da camada de cache atualmente armazena em cache dados da tabela Products usando uma expiração de tempo de 60 segundos. Vamos atualizar essa classe para que ela use dependências de cache SQL. O ProductsCL método de classe s AddCacheItem , que é responsável por adicionar os dados ao cache, atualmente contém o seguinte código:

Private Sub AddCacheItem(ByVal rawKey As String, ByVal value As Object)
    Dim DataCache As System.Web.Caching.Cache = HttpRuntime.Cache
    ' Make sure MasterCacheKeyArray(0) is in the cache - if not, add it
    If DataCache(MasterCacheKeyArray(0)) Is Nothing Then
        DataCache(MasterCacheKeyArray(0)) = DateTime.Now
    End If
    ' Add a CacheDependency
    Dim dependency As _
        New Caching.CacheDependency(Nothing, MasterCacheKeyArray)
    DataCache.Insert(GetCacheKey(rawKey), value, dependency, _
        DateTime.Now.AddSeconds(CacheDuration), _
        Caching.Cache.NoSlidingExpiration)
End Sub

Atualize este código para utilizar um objeto SqlCacheDependency em vez de uma dependência de cache MasterCacheKeyArray.

Private Sub AddCacheItem(ByVal rawKey As String, ByVal value As Object)
    Dim DataCache As System.Web.Caching.Cache = HttpRuntime.Cache
    ' Add the SqlCacheDependency objects for Products
    Dim productsTableDependency As New _
        Caching.SqlCacheDependency("NorthwindDB", "Products")
    DataCache.Insert(GetCacheKey(rawKey), value, productsTableDependency, _
        Cache.NoAbsoluteExpiration, Caching.Cache.NoSlidingExpiration)
End Sub

Para testar essa funcionalidade, adicione um GridView à página abaixo do GridView existente ProductsDeclarative . Defina esse novo GridView s ID como ProductsProgrammatic e, por meio de sua marca inteligente, vincule-o a um novo ObjectDataSource chamado ProductsDataSourceProgrammatic. Configure o ObjectDataSource para usar a classe ProductsCL, configurando as listas suspensas nas guias SELECT e UPDATE como GetProducts e UpdateProduct, respectivamente.

Configurar o ObjectDataSource para usar a classe ProductsCL

Figura 11: Configurar o ObjectDataSource para usar a classe (ProductsCL imagem em tamanho real)

Selecione o Método GetProducts da lista Drop-Down do separador SELECT

Figura 12: Selecione o GetProducts método na lista da aba SELECT s Drop-Down (Clique para visualizar a imagem em tamanho real)

Escolha o método UpdateProduct na lista de separadores UPDATE Drop-Down

Figura 13: Escolha o método UpdateProduct na lista do separador UPDATE do Drop-Down (Clique para visualizar a imagem em tamanho real)

Depois de concluir o assistente Configurar Fonte de Dados, o Visual Studio criará BoundFields e CheckBoxFields no GridView para cada um dos campos de dados. Como no primeiro GridView adicionado a esta página, remova todos os campos, exceto ProductName, CategoryNamee UnitPrice, e formate esses campos como achar melhor. Na etiqueta inteligente do GridView, marque as caixas de seleção Ativar paginação, Ativar classificação e Ativar edição. Assim como acontece com o ProductsDataSourceDeclarative ObjectDataSource, o Visual Studio definirá a propriedade do ProductsDataSourceProgrammatic ObjectDataSource para OldValuesParameterFormatString. Para que o recurso de edição de GridView funcione corretamente, defina essa propriedade de volta para {0} (ou remova completamente a atribuição de propriedade da sintaxe declarativa).

Depois de concluir essas tarefas, a marcação declarativa GridView e ObjectDataSource resultante deve ter a seguinte aparência:

<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>

Para testar a dependência do cache SQL na camada de cache, defina um ponto de interrupção na classe ProductCL e no método AddCacheItem, e inicie a depuração. Quando visitar SqlCacheDependencies.aspx, o ponto de interrupção deve ser atingido à medida que os dados são solicitados pela primeira vez e colocados no cache. Em seguida, mova para outra página no GridView ou classifique uma das colunas. Isso faz com que o GridView consulte novamente seus dados, mas os dados devem ser encontrados no cache, pois a tabela do Products banco de dados não foi modificada. Se os dados não forem encontrados repetidamente no cache, verifique se há memória suficiente disponível no computador e tente novamente.

Depois de paginar algumas páginas do GridView, abra uma segunda janela do navegador e navegue até o tutorial Noções básicas na seção Edição, inserção e exclusão (~/EditInsertDelete/Basics.aspx). Atualize um registro da tabela Produtos e, em seguida, na primeira janela do navegador, visualize uma nova página ou clique em um dos cabeçalhos de classificação.

Nesse cenário, você verá uma de duas coisas: ou o ponto de interrupção será atingido, indicando que os dados armazenados em cache foram removidos devido à alteração no banco de dados; Ou, o ponto de interrupção não será atingido, o que significa que SqlCacheDependencies.aspx agora está mostrando dados obsoletos. Se o ponto de interrupção não for atingido, é provável que o serviço de sondagem ainda não tenha sido acionado desde que os dados foram alterados. Lembre-se de que o serviço de sondagem está verificando alterações na tabela a Products cada pollTime milissegundos, portanto, há um atraso entre quando os dados subjacentes são atualizados e quando os dados armazenados em cache são removidos.

Observação

É mais provável que esse atraso apareça ao editar um dos produtos por meio do GridView em SqlCacheDependencies.aspx. No tutorial Caching Data in the Architecture , adicionamos a dependência de MasterCacheKeyArray cache para garantir que os dados que estão sendo editados por meio do ProductsCL método class s UpdateProduct fossem removidos do cache. No entanto, substituímos essa dependência de cache ao modificar o AddCacheItem método anteriormente nesta etapa e, portanto, a ProductsCL classe continuará a mostrar os dados armazenados em cache até que o sistema de sondagem observe a alteração na Products tabela. Veremos como reintroduzir a dependência de cache do MasterCacheKeyArray na Etapa 7.

Etapa 7: Associando várias dependências a um item armazenado em cache

Lembre-se de que a dependência de MasterCacheKeyArray cache é usada para garantir que todos os dados relacionados ao produto sejam removidos do cache quando qualquer item associado a ele for atualizado. Por exemplo, o método armazena instâncias em cache para cada valor exclusivo de GetProductsByCategoryID(categoryID). Se um desses objetos for removido, a MasterCacheKeyArray dependência de cache garantirá que os outros também sejam removidos. Sem essa dependência de cache, quando os dados armazenados em cache são modificados, existe a possibilidade de que outros dados do produto armazenados em cache estejam desatualizados. Consequentemente, é importante que mantenhamos a dependência de cache ao utilizar dependências de cache SQL com MasterCacheKeyArray. No entanto, o método de cache de dados s Insert só permite um único objeto de dependência.

Além disso, ao trabalhar com dependências de cache SQL, podemos precisar associar várias tabelas de banco de dados como dependências. Por exemplo, o cache ProductsDataTable na classe ProductsCL contém os nomes de categoria e de fornecedor para cada produto, mas o método AddCacheItem apenas usa uma dependência de Products. Nessa situação, se o usuário atualizar o nome de uma categoria ou fornecedor, os dados do produto armazenados em cache permanecerão no cache e estarão desatualizados. Portanto, queremos tornar os dados do produto armazenados em cache dependentes não apenas da Products tabela, mas também da Categories tabela e da Suppliers tabela.

A AggregateCacheDependency classe fornece um meio para associar várias dependências a um item de cache. Comece criando uma AggregateCacheDependency instância. Em seguida, adicione o conjunto de dependências usando o AggregateCacheDependency método s Add . Ao inserir o item no cache de dados posteriormente, passe a instância de AggregateCacheDependency. Quando qualquer uma das dependências da AggregateCacheDependency instância for alterada, o item armazenado em cache será removido.

A seguir mostra o código atualizado para o ProductsCL método s de AddCacheItem classe. O método cria a dependência de MasterCacheKeyArray cache junto com SqlCacheDependency objetos para o Products, Categories e Suppliers tabelas. Todos eles são combinados em um AggregateCacheDependency objeto chamado aggregateDependencies, que é então passado para o Insert método.

Private Sub AddCacheItem(ByVal rawKey As String, ByVal value As Object)
    Dim DataCache As System.Web.Caching.Cache = HttpRuntime.Cache
    ' Make sure MasterCacheKeyArray(0) is in the cache - if not, add it.
    If DataCache(MasterCacheKeyArray(0)) Is Nothing Then
        DataCache(MasterCacheKeyArray(0)) = DateTime.Now
    End If
    'Create the CacheDependency
    Dim masterCacheKeyDependency As _
        New Caching.CacheDependency(Nothing, MasterCacheKeyArray)
    ' Add the SqlCacheDependency objects for Products, Categories, and Suppliers
    Dim productsTableDependency As _
        New Caching.SqlCacheDependency("NorthwindDB", "Products")
    Dim categoriesTableDependency As _
        New Caching.SqlCacheDependency("NorthwindDB", "Categories")
    Dim suppliersTableDependency As _
        New Caching.SqlCacheDependency("NorthwindDB", "Suppliers")
    ' Create an AggregateCacheDependency
    Dim aggregateDependencies As New Caching.AggregateCacheDependency()
    aggregateDependencies.Add(masterCacheKeyDependency, productsTableDependency, _
        categoriesTableDependency, suppliersTableDependency)
    DataCache.Insert(GetCacheKey(rawKey), value, aggregateDependencies, _
        Caching.Cache.NoAbsoluteExpiration, Caching.Cache.NoSlidingExpiration)
End Sub

Teste este novo código. Agora, alterações nas tabelas Products, Categories ou Suppliers fazem com que os dados armazenados em cache sejam removidos. Além disso, o método da classe s ProductsCL, que é chamado ao editar um produto por meio do GridView, remove a dependência de cache UpdateProduct, o que faz com que o cache MasterCacheKeyArray seja removido e os dados sejam novamente recuperados na próxima solicitação.

Observação

As dependências do cache SQL também podem ser usadas com o cache de saída. Para obter uma demonstração dessa funcionalidade, consulte: Usando ASP.NET cache de saída com o SQL Server.

Resumo

Ao armazenar dados do banco de dados em cache, o ideal é que os dados permaneçam no cache até que sejam modificados no banco de dados. Com o ASP.NET 2.0, as dependências de cache SQL podem ser criadas e usadas em cenários declarativos e programáticos. Um dos desafios dessa abordagem é descobrir quando os dados foram modificados. As versões completas do Microsoft SQL Server 2005 fornecem recursos de notificação que podem alertar um aplicativo quando um resultado de consulta for alterado. Para a Edição Express do SQL Server 2005 e de versões anteriores, um sistema de sondagem deve ser usado. Felizmente, a criação da infraestrutura de votação necessária é bastante simples.

Feliz Programação!

Leitura adicional

Para obter mais informações sobre os tópicos discutidos neste tutorial, consulte os seguintes recursos:

Sobre o Autor

Scott Mitchell, autor de sete livros sobre ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias Web da Microsoft desde 1998. Scott trabalha como consultor, formador e escritor independente. Seu último livro é Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Ele pode ser contatado em mitchell@4GuysFromRolla.com.

Um agradecimento especial a

Esta série de tutoriais foi revisada por muitos revisores úteis. Os principais revisores deste tutorial foram Marko Rangel, Teresa Murphy e Hilton Giesenow. Interessado em rever meus próximos artigos do MSDN? Se for o caso, envie-me uma mensagem para mitchell@4GuysFromRolla.com.