Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você 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 rapidamente. 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 tutoriais Caching Data with the ObjectDataSource e Caching Data in the 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 à desatualização de dados. Ao selecionar uma expiração de tempo de x segundos, um desenvolvedor de página admite desfrutar dos benefícios de desempenho do cache por apenas x segundos, mas pode ficar tranquilo de que seus dados nunca ficarão obsoletos por mais de 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 Dados de Cache na Inicialização do Aplicativo .
Ao armazenar dados de banco de dados em cache, 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áginas 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 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 ASP.NET runtime 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 ASP.NET runtime sonda periodicamente o banco de dados para verificar 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 controla 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 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 em configurar e usar a 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 – tableNamee notificationCreatedchangeId. 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 (triggers) em todas as 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 runtime ASP.NET rastreia o changeId atual para uma tabela ao armazenar dados em cache usando um objeto SqlCacheDependency. 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.exeprograma 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 nas dependências de cache do SQL no aplicativo Web. Essas tabelas, procedimentos armazenados e gatilhos podem ser criados por meio do programa aspnet_regsql.exede 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 login do banco de dados especificado deve estar nas funções db_securityadmin e db_ddladmin.
Por exemplo, para adicionar a infraestrutura para sondagem a um banco de dados do Microsoft SQL Server nomeado 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 de cache do 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, assim:
/* 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 no banco 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: Referenciando um Banco de Dados do Microsoft SQL Server 2005 Express Edition noApp_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 o SQL Server Management Studio. Se você tiver uma das versões completas do SQL Server 2005 instaladas em seu computador, provavelmente já terá o SQL Server Management Studio instalado em seu 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 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 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 com um GUID. Para evitar ter que 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, clicando com o botão direito do mouse no banco de dados apenas anexado e escolhendo Renomear. Renomeei meu banco de dados para DataTutorials.
Figura 3: Renomear 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 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, que é feito por meio Web.config da especificação dos bancos de dados a serem usados e da frequência de sondagem em milissegundos. A marcação a seguir consulta 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 do SQL, precisaremos consultar o nome do banco de dados definido aqui, bem como a 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 polling se conectará aos bancos de dados definidos nos elementos <databases> a cada pollTime milissegundos e executará o procedimento armazenado AspNet_SqlCachePollingStoredProcedure. Este procedimento armazenado - que foi adicionado novamente na Etapa 3 usando a ferramenta de linha de comando aspnet_regsql.exe - retorna os valores tableName e changeId de 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 experimente 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 opcionalmente você pode 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 do Cache SQL
Nas Etapas 1 a 4, analisamos 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 Caching Data with the ObjectDataSource explorou as capacidades declarativas de cache do ObjectDataSource. Ao simplesmente definir a propriedade EnableCaching para true e a propriedade CacheDuration para um intervalo de tempo, o ObjectDataSource armazenará automaticamente em cache os dados retornados de seu objeto subjacente durante o intervalo especificado. O ObjectDataSource também pode usar uma ou mais dependências de cache SQL.
Para demonstrar o uso das dependências de cache do SQL de forma declarativa, abra a página SqlCacheDependencies.aspx na pasta Caching e arraste um GridView da Caixa de Ferramentas para o Designer. Defina o atributo de ID do GridView para ProductsDeclarative e, de sua smart tag, escolha associá-lo a um novo ObjectDataSource chamado ProductsDataSourceDeclarative.
Figura 5: Criar um Novo ObjectDataSource Nomeado ProductsDataSourceDeclarative (Clique para exibir imagem em tamanho real)
Configure o ObjectDataSource para usar a classe ProductsBLL e configure a lista suspensa na guia SELECT para GetProducts(). Na guia UPDATE, escolha a sobrecarga UpdateProduct com três parâmetros de entrada: productName, unitPrice e productID. Defina as listas suspensas como (Nenhuma) nas guias INSERT e DELETE.
Figura 6: Use 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 (Nenhuma) 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, mas ProductName, CategoryNamee UnitPrice, e formate esses campos como você achar adequado. Na etiqueta inteligente do GridView, marque as caixas de seleção Habilitar Paginação, Habilitar Classificação e Habilitar Edição. O Visual Studio definirá a propriedade OldValuesParameterFormatString ObjectDataSource como original_{0}. Para que o recurso de edição do GridView funcione corretamente, remova essa propriedade inteiramente da sintaxe declarativa ou defina-a de volta ao seu valor padrão. {0}
Por fim, adicione um controle Web Rótulo acima do GridView e defina a sua propriedade ID como ODSEvents e a sua propriedade EnableViewState 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 Selecting e, 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ê muda de página, classifica ou edita a grade, a página deve exibir o texto "Evento de seleção acionado", 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 Caching Data with the ObjectDataSource , definir a EnableCaching propriedade para true fazer 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 de banco de dados. Por exemplo, para criar um ObjectDataSource que armazena em cache dados indefinidamente com base em uma dependência de cache do SQL na tabela Northwind Products, defina a propriedade EnableCaching do ObjectDataSource como true e sua 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 banco de dados e os nomes da tabela. O ObjectDataSource removerá seus dados quando a expiração baseada em tempo for alcançada ou quando o sistema de sondagem observar que os dados do banco de dados subjacentes foram alterados, o que ocorrer primeiro.
O GridView em SqlCacheDependencies.aspx exibe dados de duas tabelas: Products e Categories. O campo CategoryName do produto é recuperado por meio de um JOIN que é ativado 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 de 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 disparado deve aparecer na primeira visita de 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 tabelas Products ou Categories sejam modificadas ou os dados sejam atualizados por meio do GridView.
Depois de paginar pela grade e notar a falta do texto 'Texto de evento de seleção disparado', abra uma nova janela do navegador e navegue até o tutorial básico na seção de Edição, Inserção e Exclusão (~/EditInsertDelete/Basics.aspx). Atualize o nome ou o preço de um produto. Em seguida, na primeira janela do navegador, abra uma página de dados diferente, classifique a grade de dados ou clique no botão Editar de uma linha. Desta vez, o evento 'Selecionar evento acionado' deve reaparecer, pois os dados do banco de dados subjacente foram modificados (veja 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 de produtos remove os dados do produto armazenados em cache (clique para exibir a imagem em tamanho real)
Etapa 6: Trabalhar 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 classe SqlCacheDependency.
Com o sistema de sondagem, um SqlCacheDependency objeto deve ser associado a um banco de dados específico e um 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 construtor de SqlCacheDependency são, respectivamente, os nomes do banco de dados e da tabela. Assim como com a propriedade ObjectDataSource SqlCacheDependency, o nome do banco de dados usado é o mesmo que o valor especificado no atributo name do elemento <add> 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 sobrecargas de método de Insert que aceita uma dependência. O código a seguir adiciona valor ao cache de dados por tempo indeterminado, mas o associa a SqlCacheDependency na Products tabela. Em suma, o valor permanecerá no cache até ser 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);
A classe Camada de Cache ProductsCL 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 da AddCacheItem classe, 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 de uma 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 este novo GridView ID para ProductsProgrammatic e, através de sua smart tag, associe-o a um novo ObjectDataSource chamado ProductsDataSourceProgrammatic. Configure o ObjectDataSource para usar a classe ProductsCL, configurando as listas suspensas nas guias SELECT e UPDATE para GetProducts e UpdateProduct, respectivamente.
Figura 11: Configurar o ObjectDataSource para usar a ProductsCL classe (clique para exibir a imagem em tamanho real)
Selecione o método GetProducts na Lista de Drop-Down da Aba SELECT
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: Escolha 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. Como com o primeiro GridView adicionado a esta página, remova todos os campos, exceto ProductName, CategoryNamee , e UnitPriceformate esses campos conforme você achar adequado. Na etiqueta inteligente do GridView, marque 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 propriedade ProductsDataSourceProgrammatic ObjectDataSource's OldValuesParameterFormatString como original_{0}. Para que o recurso de edição do GridView funcione corretamente, restaure essa propriedade para {0} ou remova a atribuição de propriedade da sintaxe declarativa.
Depois de concluir essas tarefas, a marcação declarativa de 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 SQL na camada de cache, defina um ponto de interrupção na ProductCL classe AddCacheItem método e, em seguida, inicie a depuração. Quando você visita SqlCacheDependencies.aspxpela 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 requera 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: 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 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 Cache de Dados na Arquitetura, adicionamos a dependência de cache MasterCacheKeyArray para garantir que os dados editados por meio do método da classe ProductsCLUpdateProduct fosse removido 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: 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 em cache instâncias para cada valor exclusivo de GetProductsByCategoryID(categoryID). Se um desses objetos for removido, a dependência do 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 que mantenhamos a dependência de MasterCacheKeyArray cache ao usar as dependências de cache do SQL. No entanto, o método do cache de Insert dados permite apenas um único objeto de dependência.
Além disso, ao trabalhar com dependências de cache SQL, podemos precisar associar várias tabelas de dados como dependências. Por exemplo, o ProductsDataTable em cache na classe ProductsCL contém os nomes de categoria e fornecedor para cada produto, mas o método AddCacheItem usa apenas 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 tabela Products, mas também das tabelas Categories 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 depois disso, passe a instância AggregateCacheDependency. Quando qualquer uma das AggregateCacheDependency dependências da instância for alterada, o item armazenado em cache será removido.
O seguinte mostra o código atualizado para o ProductsCL método da AddCacheItem classe. O método cria a dependência de cache MasterCacheKeyArray junto com objetos SqlCacheDependency para as tabelas Products, Categories e Suppliers. Todos eles são combinados em um AggregateCacheDependency objeto chamado aggregateDependencies, que é 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 este novo código. Agora, as alterações nas tabelas Products, Categories, ou Suppliers fazem com que os dados armazenados em cache sejam despejados. Além disso, o método da classe ProductsCL, que é chamado ao editar um produto por meio do GridView, expulsa a dependência de cache UpdateProduct, o que faz com que o cache MasterCacheKeyArray seja expulso e os dados sejam recuperados novamente na próxima solicitação.
Observação
Dependências de cache do SQL também podem ser usadas com cache de saída. Para obter uma demonstração dessa funcionalidade, consulte: Usando o cache de saída ASP.NET com o SQL Server.
Resumo
Ao armazenar dados de banco de dados em cache, os dados permanecerão no cache até que sejam modificados no banco de dados. Com 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 da consulta for alterado. Para a Edição Expressa do 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.
Divirta-se programando!
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
SqlCacheDependencyClasse -
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 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 alcançado em mitchell@4GuysFromRolla.com.
Agradecimentos Especiais 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 revisar meus próximos artigos do MSDN? Se assim for, deixe-me uma linha em mitchell@4GuysFromRolla.com.