Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
por Scott Mitchell
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
, notificationCreated
e 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.exe
de 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\SQLExpress
SQL 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.
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.
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 .
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
.
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
.
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
, unitPrice
e productID
. Defina as listas suspensas como (Nenhum) nas guias INSERIR e EXCLUIR.
Figura 6: Usar a sobrecarga UpdateProduct com três parâmetros de entrada (Clique para visualizar a imagem em tamanho real)
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.
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 .
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.
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 aSqlCacheDependency
classe
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.
Figura 11: Configurar o ObjectDataSource para usar a classe (ProductsCL
imagem em tamanho real)
Figura 12: Selecione o GetProducts
método na lista da aba SELECT s Drop-Down (Clique para visualizar a imagem em tamanho real)
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
, 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. 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:
- Usando notificações de consulta no Microsoft SQL Server 2005
- Criando uma notificação de consulta
-
Armazenamento em cache em ASP.NET com a Classe
SqlCacheDependency
-
ASP.NET Ferramenta de Registro do SQL Server (
aspnet_regsql.exe
) -
Visão geral de
SqlCacheDependency
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.