Uso de dependências de cache de SQL (C#)
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 dados muito longos ou atuais que expiraram muito cedo. Uma abordagem melhor é usar a classe SqlCacheDependency para que os dados permaneçam armazenados em cache até que seus dados subjacentes sejam modificados no banco de dados SQL. Este tutorial mostra como.
Introdução
As técnicas de cache examinadas nos Dados de Cache com os tutoriais ObjectDataSource e Caching Data na Arquitetura 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 à desatualização de 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 de que seus dados nunca ficarão obsoletos por mais tempo do que um máximo de x segundos. É claro que, para dados estáticos, x pode ser estendido para o tempo de vida do aplicativo Web, como foi examinado no tutorial Armazenar dados em cache na inicialização do aplicativo .
Ao armazenar em cache dados de banco de dados, uma expiração baseada em tempo geralmente é escolhida para sua facilidade de uso, mas é frequentemente uma solução inadequada. O ideal é que os dados do banco de dados permaneçam armazenados em cache até que os dados subjacentes sejam modificados no banco de dados; somente então o cache seria removido. 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 de banco de dados subjacentes foram modificados e remove os itens correspondentes do cache. Antes do ASP.NET 2.0, os desenvolvedores de página eram responsáveis por implementar esse 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 armazenados em cache correspondentes possam ser removidos. Há duas técnicas para determinar quando os dados subjacentes foram alterados: notificação e sondagem. Depois de discutir as diferenças entre a notificação e a sondagem, criaremos a infraestrutura necessária para dar suporte à sondagem e, em seguida, exploraremos como usar a SqlCacheDependency
classe em cenários declarativos e programaticamente.
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 runtime ASP.NET quando os resultados de uma consulta específica foram alterados desde a última execução da consulta, 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 runtime ASP.NET sonda periodicamente o banco de dados para marcar quais tabelas foram alteradas desde que foram inseridas no cache. Essas 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 sondagem e é mais granular, pois acompanha as alterações no nível da consulta e não no 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 Expressas). 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 em configurar e usar a opção de sondagem. Consulte a seção Leitura Adicional no final deste tutorial para obter mais recursos sobre SQL Server recursos de notificação do 2005.
Com a sondagem, o banco de dados deve ser configurado para incluir uma tabela chamada 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 com 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 incrementa o valor da changeId
tabela em AspNet_SqlCacheTablesForChangeNotification
.
O runtime ASP.NET rastreia o atual changeId
de uma tabela ao armazenar dados em cache usando um SqlCacheDependency
objeto . O banco de dados é verificado periodicamente e todos SqlCacheDependency
os objetos que changeId
diferem do valor no banco de dados são removidos, pois um valor diferente changeId
indica que houve uma alteração na tabela desde que os dados foram armazenados em cache.
Etapa 1: Explorando oaspnet_regsql.exe
programa de linha de comando
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 por meio do programa aspnet_regsql.exe
de linha de comando , que é encontrado na $WINDOWS$\Microsoft.NET\Framework\version
pasta . Para criar a AspNet_SqlCacheTablesForChangeNotification
tabela e os 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 db_securityadmin
funções e db_ddladmin
.
Por exemplo, para adicionar a infraestrutura para sondagem a um banco de dados do Microsoft SQL Server chamado pubs
em um servidor de banco de dados chamado ScottsServer
usando a Autenticação do Windows, navegue até o diretório apropriado e, na linha de comando, insira:
aspnet_regsql.exe -S ScottsServer -E -d pubs -ed
Depois que a infraestrutura no nível do banco de dados tiver sido adicionada, precisamos adicionar os gatilhos às tabelas que serão usadas nas dependências do cache SQL. Use o aspnet_regsql.exe
programa de linha de comando novamente, mas especifique o nome da tabela usando a opção -t
e, em vez de usar a opção -ed
, use -et
, da seguinte maneira:
/* 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 authors
tabelas e titles
no pubs
banco de dados no 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 Products
tabelas , Categories
e Suppliers
. Examinaremos a sintaxe de linha de comando específica na Etapa 3.
Etapa 2: Referenciando um banco de dados do Microsoft SQL Server 2005 Express Edition emApp_Data
O aspnet_regsql.exe
programa de linha de comando requer o nome do banco de dados e 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 localhost\SQLExpress
banco de dados e renomear os dados usando SQL Server Management Studio. Se você tiver uma das versões completas do SQL Server 2005 instalada no computador, provavelmente já terá SQL Server Management Studio instalados no computador. Se você tiver apenas a edição Express, poderá baixar o Microsoft SQL Server Management Studio Express Edition gratuito.
Comece fechando o Visual Studio. Em seguida, abra 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 pasta de NORTHWND.MDF
banco de dados na pasta do App_Data
aplicativo Web.
Figura 2: Anexar o NORTHWND.MDF
banco de dados da App_Data
pasta (clique para exibir 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 anexado a um GUID. Para evitar a necessidade de digitar esse nome de banco de dados longo ao usar a ferramenta de linha de comando aspnet_regsql.exe, renomeie o banco de dados para um nome mais amigável ao clicar com o botão direito do mouse no banco de dados, basta anexar e escolher Renomear. Renomeei meu banco de dados para DataTutorials.
Figura 3: renomeie o banco de dados anexado para um nome mais Human-Friendly
Etapa 3: Adicionar 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ê renomeou 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, faça uma busca detalhada no banco de dados por meio da Explorer do Servidor. Observe a nova tabela (AspNet_SqlCacheTablesForChangeNotification
), os novos procedimentos armazenados e os gatilhos nas Products
tabelas , 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, que é feito por meio Web.config
da especificação dos bancos de dados a serem usados e a frequência de sondagem em milissegundos. A marcação a seguir sonda o banco de dados Northwind uma vez 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 DO 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 a dados armazenados em cache na Etapa 6.
Depois que uma dependência de cache SQL for estabelecida, o sistema de sondagem se conectará aos bancos de dados definidos nos elementos a <databases>
cada pollTime
milissegundos e executará o AspNet_SqlCachePollingStoredProcedure
procedimento armazenado. Esse procedimento armazenado - que foi adicionado novamente na Etapa 3 usando a aspnet_regsql.exe
ferramenta de linha de comando - retorna os tableName
valores e changeId
para cada registro em AspNet_SqlCacheTablesForChangeNotification
. Dependências de cache SQL desatualizadas são removidas do cache.
A pollTime
configuração introduz uma compensação entre desempenho e desatualização de dados. Um valor pequeno pollTime
aumenta o número de solicitações para o banco de dados, mas remove dados obsoletos mais rapidamente 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 está retornando apenas algumas linhas de uma tabela simples e leve. Mas faça experimentos com valores diferentes pollTime
para encontrar um equilíbrio ideal entre o acesso ao banco de dados e a desatualização 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 será ú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 do 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 em vigor, 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 do SQL. Na Etapa 6, examinaremos a abordagem programática.
O tutorial Armazenar dados em cache com o ObjectDataSource explorou os recursos declarativos de cache do ObjectDataSource. Ao simplesmente definir 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 declarativamente das dependências de cache do SQL, abra a SqlCacheDependencies.aspx
página na Caching
pasta e arraste um GridView da Caixa de Ferramentas para o Designer. Defina o GridView s ID
como ProductsDeclarative
e, de sua marca inteligente, escolha associá-lo a um novo ObjectDataSource chamado ProductsDataSourceDeclarative
.
Figura 5: Criar um novo objetoDataSource nomeado ProductsDataSourceDeclarative
(clique para exibir a imagem em tamanho real)
Configure o ObjectDataSource para usar a ProductsBLL
classe e defina a lista suspensa na guia 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 INSERT e DELETE.
Figura 6: Usar a sobrecarga UpdateProduct com três parâmetros de entrada (clique para exibir a imagem em tamanho real)
Figura 7: Definir a lista de Drop-Down como (Nenhum) para as guias INSERT e DELETE (clique para exibir 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 desejar. Na marca inteligente GridView, marcar as caixas de seleção Habilitar Paginação, Habilitar Classificação e Habilitar Edição. O Visual Studio definirá a propriedade original_{0}
objectDataSource como OldValuesParameterFormatString
. Para que o recurso de edição do GridView funcione corretamente, remova essa propriedade inteiramente da sintaxe declarativa ou defina-a de volta para seu valor padrão, {0}
.
Por fim, adicione um controle Web Label acima do 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 e Selecting
, nele, adicione o seguinte código:
protected void ProductsDataSourceDeclarative_Selecting
(object sender, ObjectDataSourceSelectingEventArgs e)
{
ODSEvents.Text = "-- Selecting event fired";
}
Lembre-se de que o evento ObjectDataSource é Selecting
acionado somente ao recuperar dados de seu objeto subjacente. Se o ObjectDataSource acessar os dados de seu próprio cache, esse evento não será acionado.
Agora, visite esta página por meio de um navegador. Como ainda não implementamos nenhum cache, cada vez que você paginar, classificar ou editar a grade, a página deverá exibir o texto 'Selecionar evento disparado, como mostra a Figura 8.
Figura 8: o evento ObjectDataSource é Selecting
acionado sempre que o GridView é paginado, editado ou classificado (clique para exibir a imagem em tamanho real)
Como vimos no tutorial Armazenar dados em cache com o ObjectDataSource , definir a EnableCaching
propriedade true
como faz com que ObjectDataSource armazene seus dados em cache durante a 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;...
Em que databaseName é o nome do banco de dados, conforme especificado no name
atributo do <add>
elemento em Web.config
, e tableName é o nome da tabela de banco de dados. Por exemplo, para criar um ObjectDataSource que armazena dados em cache indefinidamente com base em uma dependência de cache SQL na tabela NorthwindProducts
, defina a propriedade true
ObjectDataSource como EnableCaching
e sua SqlCacheDependency
propriedade como NorthwindDB:Products.
Observação
Você pode usar uma dependência de cache SQL e uma expiração baseada em tempo definindo EnableCaching
true
como , CacheDuration
para o intervalo de tempo e SqlCacheDependency
para o banco de dados e os nomes da tabela. O ObjectDataSource removerá seus dados quando a expiração baseada em tempo for atingida ou quando o sistema de sondagem observar que os dados subjacentes do banco de dados foram alterados, o que acontecer primeiro.
O GridView em SqlCacheDependencies.aspx
exibe dados de duas tabelas – Products
e Categories
(o campo do CategoryName
produto é recuperado por meio de um JOIN
em Categories
). Portanto, queremos especificar duas dependências de cache SQL: NorthwindDB:Products; NorthwindDB:Categories .
Figura 9: Configurar o ObjectDataSource para dar suporte ao cache usando dependências do Cache SQL em Products
e Categories
(clique para exibir a imagem em tamanho real)
Depois de configurar o ObjectDataSource para dar suporte ao cache, reveja a página por meio de um navegador. Novamente, o texto "Selecionar evento acionado deve aparecer na visita da primeira 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 do ObjectDataSource, eles permanecem lá até que as Products
tabelas ou Categories
sejam modificadas ou que os dados sejam atualizados por meio do GridView.
Depois de paginar a grade e notar a falta do texto 'Selecionar evento disparado, abra uma nova janela do navegador e navegue até o tutorial Básico na seção Edição, Inserção e Exclusão (~/EditInsertDelete/Basics.aspx
). Atualize o nome ou o preço de um produto. Em seguida, de até a primeira janela do navegador, exiba 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 acionado deve reaparecer, pois os dados de banco de dados subjacentes foram modificados (consulte a Figura 10). Se o texto não aparecer, aguarde alguns instantes e tente novamente. Lembre-se de que o serviço de sondagem está verificando se há 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 remove os dados do produto armazenados em cache (clique para exibir a imagem em tamanho real)
Etapa 6: Trabalhar programaticamente com aSqlCacheDependency
classe
O tutorial Armazenando dados em cache no tutorial Arquitetura 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 do banco de Products
dados Northwind:
Caching.SqlCacheDependency productsTableDependency =
new Caching.SqlCacheDependency("NorthwindDB", "Products");
Os dois parâmetros de entrada para o SqlCacheDependency
construtor s são os nomes de banco de dados e tabela, respectivamente. Assim como acontece com a propriedade ObjectDataSource s SqlCacheDependency
, 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 de banco de dados.
Para associar um SqlCacheDependency
a um item adicionado ao cache de dados, use uma das Insert
sobrecargas de método que aceita uma dependência. O código a seguir adiciona valor ao cache de dados por uma duração indefinida, mas o associa a Products
um SqlCacheDependency
na tabela. Em suma, o valor permanecerá no cache até que seja removido devido a restrições de memória ou porque o sistema de sondagem detectou que a Products
tabela foi alterada desde que foi armazenada em cache.
Caching.SqlCacheDependency productsTableDependency =
new Caching.SqlCacheDependency("NorthwindDB", "Products");
Cache.Insert(key,
value,
productsTableDependency,
System.Web.Caching.Cache.NoAbsoluteExpiration,
System.Web.Caching.Cache.NoSlidingExpiration);
Atualmente, a classe da Camada de Cache armazena ProductsCL
em cache dados da Products
tabela usando uma expiração baseada em tempo de 60 segundos. Vamos atualizar essa classe para que ela use dependências de cache do 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 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);
}
Atualize este código para usar um SqlCacheDependency
objeto em vez da MasterCacheKeyArray
dependência de 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);
}
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, associe-o a um novo ObjectDataSource chamado ProductsDataSourceProgrammatic
. Configure o ObjectDataSource para usar a ProductsCL
classe , definindo as listas suspensas nas guias SELECT e UPDATE como GetProducts
e UpdateProduct
, respectivamente.
Figura 11: Configurar o ObjectDataSource para usar a ProductsCL
classe (clique para exibir a imagem em tamanho real)
Figura 12: Selecione o GetProducts
Método na Lista de Drop-Down da Guia SELECT (Clique para exibir a imagem em tamanho real)
Figura 13: Escolher o método UpdateProduct na lista de Drop-Down da guia UPDATE (clique para exibir 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. Assim como ocorre com o primeiro GridView adicionado a esta página, remova todos os campos, exceto ProductName
, CategoryName
e UnitPrice
, e formate esses campos como desejar. Na marca inteligente GridView, marcar as caixas de seleção Habilitar Paginação, Habilitar Classificação e Habilitar Edição. Assim como acontece com o ProductsDataSourceDeclarative
ObjectDataSource, o Visual Studio definirá a ProductsDataSourceProgrammatic
propriedade original_{0}
objectDataSource como OldValuesParameterFormatString
. Para que o recurso de edição do GridView funcione corretamente, defina essa propriedade {0}
como (ou remova a atribuição de propriedade da sintaxe declarativa completamente).
Depois de concluir essas tarefas, a marcação declarativa GridView e ObjectDataSource resultante deve ser semelhante à seguinte:
<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 de cache do SQL na Camada de Cache, defina um ponto de interrupção no método da classe s AddCacheItem
e, em ProductCL
seguida, inicie a depuração. Quando você visita SqlCacheDependencies.aspx
pela primeira vez , o ponto de interrupção deve ser atingido à medida que os dados são solicitados pela primeira vez e colocados no cache. Em seguida, vá para outra página no GridView ou classifique uma das colunas. Isso faz com que o GridView exiba seus dados, mas os dados devem ser encontrados no cache, pois a tabela de 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 Básico na seção Edição, Inserção e Exclusão (~/EditInsertDelete/Basics.aspx
). Atualize um registro da tabela Produtos e, na primeira janela do navegador, exiba uma nova página ou clique em um dos cabeçalhos de classificação.
Nesse cenário, você verá uma das duas coisas: 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 se há 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
Esse atraso é mais provável de aparecer ao editar um dos produtos por meio do GridView em SqlCacheDependencies.aspx
. No tutorial Dados de Cache no tutorial Arquitetura , adicionamos a MasterCacheKeyArray
dependência de cache para garantir que os dados que estão sendo editados por meio do ProductsCL
método da classe s UpdateProduct
sejam 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 MasterCacheKeyArray
cache na Etapa 7.
Etapa 7: Associar 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 GetProductsByCategoryID(categoryID)
método armazena em cache instâncias ProductsDataTables
para cada valor categoryID exclusivo. Se um desses objetos for removido, a dependência de MasterCacheKeyArray
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 possam estar desatualizados. Consequentemente, é importante mantermos a dependência de MasterCacheKeyArray
cache ao usar dependências de cache SQL. No entanto, o método s do cache de Insert
dados permite apenas um único objeto de dependência.
Além disso, ao trabalhar com dependências de cache SQL, talvez seja necessário associar várias tabelas de banco de dados como dependências. Por exemplo, o ProductsDataTable
armazenado em cache na ProductsCL
classe contém os nomes de categoria e fornecedor para cada produto, mas o AddCacheItem
método usa apenas uma dependência em 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 das Categories
tabelas e Suppliers
.
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 AggregateCacheDependency
instância. Quando qualquer uma das AggregateCacheDependency
dependências da instância for alterada, o item armazenado em cache será removido.
A seguir, mostra o código atualizado para o ProductsCL
método da classe s AddCacheItem
. O método cria a dependência de MasterCacheKeyArray
cache junto com SqlCacheDependency
objetos para as Products
tabelas , Categories
e Suppliers
. Todos eles são combinados em um AggregateCacheDependency
objeto chamado aggregateDependencies
, que é então passado para o Insert
método .
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);
}
Teste esse novo código. Agora, as alterações nas Products
tabelas , Categories
ou fazem Suppliers
com que os dados armazenados em cache sejam removidos. Além disso, o ProductsCL
método da classe s UpdateProduct
, que é chamado ao editar um produto por meio do GridView, remove a dependência de MasterCacheKeyArray
cache, o que faz com que o cache ProductsDataTable
seja removido e os dados sejam recuperados novamente 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 SQL Server.
Resumo
Ao armazenar em cache os dados do banco de dados, o ideal é que os dados permaneçam no cache até que sejam modificados no banco de dados. Com ASP.NET 2.0, as dependências do 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 da consulta for alterado. Para o Express Edition de SQL Server 2005 e versões mais antigas do SQL Server, um sistema de sondagem deve ser usado. Felizmente, a configuração da infraestrutura de sondagem necessária é bastante simples.
Programação feliz!
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
- Cache em ASP.NET com a
SqlCacheDependency
classe - Ferramenta de Registro de ASP.NET SQL Server (
aspnet_regsql.exe
) - Visão geral de
SqlCacheDependency
Sobre o autor
Scott Mitchell, autor de sete livros do ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Microsoft Web desde 1998. Scott trabalha como consultor independente, treinador e escritor. Seu último livro é Sams Teach Yourself ASP.NET 2.0 em 24 Horas. Ele pode ser contatado em mitchell@4GuysFromRolla.com. ou através de seu blog, que pode ser encontrado em http://ScottOnWriting.NET.
Agradecimentos Especiais
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 revisar meus próximos artigos do MSDN? Nesse caso, solte-me uma linha em mitchell@4GuysFromRolla.com.