Поделиться через


Использование зависимостей кэша SQL (C#)

Скотт Митчелл

Загрузить PDF-файл

Самая простая стратегия кэширования — разрешить истечение срока действия кэшированных данных по истечении указанного периода времени. Но этот простой подход означает, что кэшированные данные не поддерживают связь с базовым источником данных, что приводит к тому, что устаревшие данные хранятся слишком долго или текущие данные, срок действия которых истек слишком рано. Лучший подход — использовать класс SqlCacheDependency, чтобы данные оставались в кэше до тех пор, пока их базовые данные не будут изменены в базе данных SQL. В этом учебнике рассказывается, как это сделать.

Введение

Методы кэширования, рассмотренные в разделах Кэширование данных с помощью ObjectDataSource и Кэширование данных в руководствах по архитектуре, использовали срок действия на основе времени для вытеснения данных из кэша по истечении указанного периода. Этот подход является самым простым способом сбалансировать повышение производительности кэширования и устаревание данных. Выбрав срок действия x секунд, разработчик страницы признает преимущества кэширования в течение всего x секунд, но может легко указать, что его данные никогда не будут устаревшими дольше x секунд. Конечно, для статических данных x можно расширить до времени существования веб-приложения, как было рассмотрено в учебнике Кэширование данных при запуске приложения .

При кэшировании данных базы данных для простоты использования часто выбирается срок действия на основе времени, но часто это неадекватное решение. В идеале данные базы данных будут кэшироваться до тех пор, пока базовые данные не будут изменены в базе данных; только после этого кэш будет вытеснился. Такой подход обеспечивает максимальную производительность кэширования и сокращает длительность устаревших данных. Тем не менее, чтобы воспользоваться этими преимуществами, должна быть создана система, которая знает, когда были изменены базовые данные базы данных, и вытеснает соответствующие элементы из кэша. До ASP.NET 2.0 разработчики страниц отвечали за реализацию этой системы.

ASP.NET 2.0 предоставляет класс и необходимую SqlCacheDependency инфраструктуру, чтобы определить, когда произошло изменение в базе данных, чтобы можно было вытеснять соответствующие кэшированные элементы. Существует два метода определения того, когда изменились базовые данные: уведомление и опрос. После обсуждения различий между уведомлением и опросом мы создадим инфраструктуру, необходимую для поддержки опроса, а затем рассмотрим, как использовать SqlCacheDependency класс в декларативных и программных сценариях.

Основные сведения об уведомлениях и опросах

Существует два метода, которые можно использовать для определения того, когда были изменены данные в базе данных: уведомление и опрос. С помощью уведомления база данных автоматически оповещает среду выполнения ASP.NET, когда результаты определенного запроса были изменены с момента последнего выполнения запроса, после чего кэшированные элементы, связанные с запросом, удаляются. При опросе сервер базы данных сохраняет сведения о последнем обновлении конкретных таблиц. Среда выполнения ASP.NET периодически опрашивает базу данных, чтобы проверка, какие таблицы изменились с момента их ввода в кэш. Таблицы, данные которых были изменены, вытеснили связанные элементы кэша.

Параметр уведомления требует меньше настройки, чем опрос, и является более детализированным, так как он отслеживает изменения на уровне запроса, а не на уровне таблицы. К сожалению, уведомления доступны только в полных выпусках Microsoft SQL Server 2005 (т. е. в выпусках, отличных от Express). Однако параметр опроса можно использовать для всех версий Microsoft SQL Server от 7.0 до 2005. Так как в этих руководствах используется выпуск Express SQL Server 2005, мы сосредоточимся на настройке и использовании параметра опроса. Дополнительные ресурсы по возможностям уведомлений SQL Server 2005 см. в разделе "Дополнительное чтение" в конце этого руководства.

При опросе база данных должна быть настроена так, чтобы она включала таблицу с тремя AspNet_SqlCacheTablesForChangeNotification столбцами : tableName, notificationCreatedи changeId. Эта таблица содержит по строке для каждой таблицы, содержащей данные, которые может потребоваться использовать в зависимости кэша SQL в веб-приложении. Столбец tableName указывает имя таблицы, а notificationCreated указывает дату и время добавления строки в таблицу. Столбец changeId имеет тип int и имеет начальное значение 0. Его значение увеличивается с каждым изменением таблицы.

Помимо AspNet_SqlCacheTablesForChangeNotification таблицы, база данных также должна включать триггеры для каждой из таблиц, которые могут отображаться в зависимости кэша SQL. Эти триггеры выполняются при вставке, обновлении или удалении строки и приращении значения таблицы changeId в AspNet_SqlCacheTablesForChangeNotification.

Среда выполнения ASP.NET отслеживает текущий для changeId таблицы при кэшировании данных с помощью SqlCacheDependency объекта . База данных периодически проверяется, и все SqlCacheDependency объекты, отличающиеся changeId от значения в базе данных, удаляются, так как разное значение указывает на то, что с момента кэширования changeId данных в таблице произошло изменение.

Шаг 1. Изучение программы команднойaspnet_regsql.exeстроки

При подходе к опросу база данных должна быть настроена так, чтобы она содержала инфраструктуру, описанную выше: предопределенную таблицу (AspNet_SqlCacheTablesForChangeNotification), несколько хранимых процедур и триггеры для каждой из таблиц, которые могут использоваться в зависимостях кэша SQL в веб-приложении. Эти таблицы, хранимые процедуры и триггеры можно создать с помощью программы aspnet_regsql.exeкомандной строки , которая находится в папке $WINDOWS$\Microsoft.NET\Framework\version . Чтобы создать таблицу AspNet_SqlCacheTablesForChangeNotification и связанные хранимые процедуры, выполните из командной строки следующую команду:

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

Примечание

Для выполнения этих команд указанное имя входа базы данных должно находиться в ролях db_securityadmin и db_ddladmin .

Например, чтобы добавить инфраструктуру для опроса в базу данных pubs Microsoft SQL Server на сервере базы данных с именем с помощью ScottsServer проверки подлинности Windows, перейдите в соответствующий каталог и в командной строке введите:

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

После добавления инфраструктуры на уровне базы данных необходимо добавить триггеры в таблицы, которые будут использоваться в зависимостях кэша SQL. Снова используйте программу командной aspnet_regsql.exe строки, но укажите имя таблицы с помощью -t параметра и вместо -ed параметра используйте -et, как показано ниже:

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

Чтобы добавить триггеры в authors таблицы и titles в базе данных ScottsServerв pubs , используйте:

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

В этом руководстве добавьте триггеры в Productsтаблицы , Categoriesи Suppliers . Мы рассмотрим конкретный синтаксис командной строки на шаге 3.

Шаг 2. Ссылка на базу данных Microsoft SQL Server 2005, экспресс-выпуск вApp_Data

Программе aspnet_regsql.exe командной строки требуются имя базы данных и сервера, чтобы добавить необходимую инфраструктуру опроса. Но каково имя базы данных и сервера для базы данных Microsoft SQL Server 2005 Express, которая находится в папкеApp_Data? Вместо того, чтобы узнать, что такое имена базы данных и сервера, я обнаружил, что самый простой подход заключается в присоединении базы данных к экземпляру localhost\SQLExpress базы данных и переименовании данных с помощью SQL Server Management Studio. Если на компьютере установлена одна из полных версий SQL Server 2005, скорее всего, на компьютере уже установлена SQL Server Management Studio. Если у вас есть только выпуск Express, вы можете скачать бесплатный выпуск Microsoft SQL Server Management Studio Express Edition.

Начните с закрытия Visual Studio. Затем откройте SQL Server Management Studio и выберите подключение к localhost\SQLExpress серверу с помощью проверки подлинности Windows.

Присоединение к localhost\SQLExpress Server

Рис. 1. Подключение к localhost\SQLExpress серверу

После подключения к серверу Среда Management Studio отобразит сервер и вложенные папки для баз данных, безопасности и т. д. Щелкните правой кнопкой мыши папку Базы данных и выберите параметр Присоединить. Откроется диалоговое окно Присоединение баз данных (см. рис. 2). Нажмите кнопку Добавить и выберите папку NORTHWND.MDF базы данных в папке App_Data веб-приложения.

Присоедините NORTHWND. База данных MDF из папки App_Data

Рис. 2. Присоединение NORTHWND.MDF базы данных из App_Data папки (щелкните для просмотра полноразмерного изображения)

При этом база данных будет добавлена в папку Базы данных. Имя базы данных может быть полным путем к файлу базы данных или полным путем, добавленным к GUID. Чтобы избежать необходимости вводить это длинное имя базы данных при использовании программы командной строки aspnet_regsql.exe, переименуйте базу данных на более понятное для человека имя, щелкнув правой кнопкой мыши только что присоединенную базу данных и выбрав команду Переименовать. Я переименовал свою базу данных в DataTutorials.

Переименование присоединенной базы данных в более Human-Friendly имя

Рис. 3. Переименование присоединенной базы данных в более Human-Friendly имя

Шаг 3. Добавление инфраструктуры опроса в базу данных Northwind

Теперь, когда мы подключили NORTHWND.MDF базу данных из App_Data папки, мы готовы добавить инфраструктуру опроса. Если вы переименовали базу данных в DataTutorials, выполните следующие четыре команды:

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

После выполнения этих четырех команд щелкните правой кнопкой мыши имя базы данных в Management Studio, перейдите во вложенное меню Задачи и выберите команду Отсоединить. Затем закройте Management Studio и снова откройте Visual Studio.

После повторного открытия Visual Studio выполните детализацию базы данных с помощью Обозреватель сервера. Обратите внимание на новую таблицу (AspNet_SqlCacheTablesForChangeNotification), новые хранимые процедуры и триггеры в Productsтаблицах , Categoriesи Suppliers .

База данных теперь включает необходимую инфраструктуру опроса.

Рис. 4. База данных теперь включает необходимую инфраструктуру опроса

Шаг 4. Настройка службы опроса

После создания необходимых таблиц, триггеров и хранимых процедур в базе данных последним шагом является настройка службы опроса, которая выполняется Web.config путем указания баз данных для использования и частоты опроса в миллисекундах. Следующая разметка опрашивает базу данных Northwind раз в секунду.

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

Значение name в элементе <add> ( NorthwindDB ) связывает понятное имя с определенной базой данных. При работе с зависимостями кэша SQL необходимо ссылаться на имя базы данных, определенное здесь, а также на таблицу, на основе которую основаны кэшированные данные. На шаге 6 мы рассмотрим, как использовать класс для программного SqlCacheDependency связывания зависимостей кэша SQL с кэшируемыми данными.

После установки зависимости кэша SQL система опроса будет подключаться к базам данных, определенным в <databases> элементах, каждые pollTime миллисекунд и выполнять хранимую AspNet_SqlCachePollingStoredProcedure процедуру. Эта хранимая процедура, добавленная на шаге 3 с помощью aspnet_regsql.exe программы командной tableName строки, возвращает значения и changeId для каждой записи в AspNet_SqlCacheTablesForChangeNotification. Устаревшие зависимости кэша SQL удаляются из кэша.

Параметр pollTime предоставляет компромисс между производительностью и устареванием данных. Небольшое pollTime значение увеличивает количество запросов к базе данных, но быстрее удаляет устаревшие данные из кэша. Большее pollTime значение уменьшает количество запросов к базе данных, но увеличивает задержку между изменением данных серверной части и удалением связанных элементов кэша. К счастью, запрос базы данных выполняет простую хранимую процедуру, которая возвращает всего несколько строк из простой и упрощенной таблицы. Но экспериментируйте с различными pollTime значениями, чтобы найти идеальный баланс между доступом к базе данных и устареванием данных для приложения. Наименьшее допустимое pollTime значение — 500.

Примечание

В приведенном выше примере предоставляется одно pollTime значение в элементе <sqlCacheDependency> , но при необходимости можно указать pollTime значение в элементе <add> . Это полезно, если указано несколько баз данных и вы хотите настроить частоту опроса для каждой базы данных.

Шаг 5. Декларативная работа с зависимостями кэша SQL

В шагах 1–4 мы рассмотрели, как настроить необходимую инфраструктуру базы данных и систему опроса. С помощью этой инфраструктуры теперь можно добавлять элементы в кэш данных с связанной зависимостью кэша SQL с помощью программных или декларативных методов. На этом шаге мы рассмотрим декларативную работу с зависимостями кэша SQL. На шаге 6 мы рассмотрим программный подход.

В учебнике Кэширование данных с помощью ObjectDataSource рассматриваются возможности декларативного кэширования ObjectDataSource. Просто задав EnableCaching для свойства значение true , а CacheDuration для свойства — определенный интервал времени, ObjectDataSource автоматически кэширует данные, возвращаемые из базового объекта, в течение указанного интервала. ObjectDataSource также может использовать одну или несколько зависимостей кэша SQL.

Чтобы декларативно продемонстрировать использование зависимостей кэша SQL, откройте SqlCacheDependencies.aspx страницу в Caching папке и перетащите элемент GridView с панели элементов на Designer. Задайте для gridView значение IDProductsDeclarative и из смарт-тега привяжите его к новому объекту ObjectDataSource с именем ProductsDataSourceDeclarative.

Создание объекта ObjectDataSource с именем ProductsDataSourceDeclarative

Рис. 5. Создание объекта ObjectDataSource с именем ProductsDataSourceDeclarative (щелкните для просмотра полноразмерного изображения)

Настройте ObjectDataSource для использования ProductsBLL класса и задайте для раскрывающегося списка на вкладке SELECT значение GetProducts(). На вкладке ОБНОВЛЕНИЕ выберите перегрузку UpdateProduct с тремя входными параметрами : productName, unitPriceи productID. Установите для раскрывающихся списков значение (Нет) на вкладках INSERT и DELETE.

Использование перегрузки UpdateProduct с тремя входными параметрами

Рис. 6. Использование перегрузки UpdateProduct с тремя входными параметрами (щелкните для просмотра полноразмерного изображения)

Задайте для Drop-Down List значение (Нет) для вкладок INSERT и DELETE

Рис. 7. Задайте для Drop-Down List значение (Нет) для вкладок INSERT и DELETE (Щелкните для просмотра полноразмерного изображения)

После завершения работы мастера настройки источника данных Visual Studio создаст BoundFields и CheckBoxFields в GridView для каждого поля данных. Удалите все поля, кроме ProductName, CategoryNameи , и UnitPriceотформатируйте эти поля так, как вы считаете нужным. В смарт-теге GridView проверка флажки Включить разбиение по страницам, Включить сортировку и Включить редактирование. Visual Studio установит для свойства ObjectDataSource значение OldValuesParameterFormatStringoriginal_{0}. Чтобы функция редактирования GridView работала правильно, либо полностью удалите это свойство из декларативного синтаксиса, либо присвойте ему значение {0}по умолчанию .

Наконец, добавьте элемент управления Label Web над GridView и задайте для его ID свойства значение ODSEvents , а для свойства EnableViewState — значение false. После внесения этих изменений декларативная разметка страницы должна выглядеть примерно так: Обратите внимание, что в поля GridView внесено несколько эстетических настроек, которые не являются обязательными для демонстрации функциональности зависимостей кэша 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>

Затем создайте обработчик событий для события ObjectDataSource Selecting и добавьте в него следующий код:

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

Помните, что событие ObjectDataSource Selecting срабатывает только при получении данных из базового объекта. Если ObjectDataSource обращается к данным из собственного кэша, это событие не запускается.

Теперь перейдите на эту страницу через браузер. Так как мы еще не реализовали кэширование, каждый раз, когда вы страницы, сортировки или изменения сетки, на странице должен отображаться текст "Выбор события, как показано на рисунке 8.

Событие Selecting ObjectDataSource срабатывает каждый раз, когда gridView выстраивается, редактируется или отсортировано

Рис. 8. Событие ObjectDataSource Selecting срабатывает каждый раз, когда GridView выстраивается, редактируется или сортируется (щелкните, чтобы просмотреть полноразмерное изображение)

Как мы видели в руководстве по кэшированию данных в objectDataSource , установка EnableCaching свойства в true значение приводит к тому, что ObjectDataSource будет кэшировать свои данные в течение времени, указанного его CacheDuration свойством. ObjectDataSource также имеет SqlCacheDependency свойство , которое добавляет одну или несколько зависимостей кэша SQL к кэшируемым данным с помощью шаблона :

databaseName1:tableName1;databaseName2:tableName2;...

Где databaseName — это имя базы данных, указанное в name атрибуте <add> элемента в Web.config, а tableName — имя таблицы базы данных. Например, чтобы создать объект ObjectDataSource, который кэширует данные на неопределенный срок на основе зависимости кэша Products SQL от таблицы Northwind, присвойте свойству ObjectDataSource EnableCaching значение true , а его SqlCacheDependency свойству — NorthwindDB:Products .

Примечание

Вы можете использовать зависимость кэша SQL и срок действия на основе времени, задав значение EnableCachingtrue, CacheDuration для интервала времени, а SqlCacheDependency также для имен баз данных и таблиц. ObjectDataSource будет вытеснить свои данные по истечении срока действия на основе времени или когда система опроса отмечает, что базовые данные базы данных изменились, в зависимости от того, что произойдет в первую очередь.

GridView в отображает SqlCacheDependencies.aspx данные из двух таблиц — Products и Categories (поле products CategoryName извлекается через JOIN в Categories). Поэтому необходимо указать две зависимости кэша SQL: NorthwindDB:Products; NorthwindDB:Категории .

Настройка ObjectDataSource для поддержки кэширования с помощью зависимостей кэша SQL для продуктов и категорий

Рис. 9. Настройка ObjectDataSource для поддержки кэширования с помощью зависимостей Products кэша SQL для и Categories (щелкните для просмотра полноразмерного изображения)

Настроив ObjectDataSource для поддержки кэширования, вернитесь на страницу через браузер. Опять же, текст "Сработавшее событие выбора" должен отображаться при первом посещении страницы, но должен исчезнуть при разбиении по страницам, сортировке или нажатии кнопок Изменить или Отмена. Это связано с тем, что после загрузки данных в кэш ObjectDataSource они остаются там до тех пор, пока Products таблицы или не Categories будут изменены или данные не будут обновлены с помощью GridView.

После разбиения по страницам сетки и замечая отсутствие сработающего текста "Выбор события", откройте новое окно браузера и перейдите к учебнику Основные сведения в разделе Редактирование, вставка и удаление (~/EditInsertDelete/Basics.aspx). Обновите название или цену продукта. Затем в первом окне браузера просмотрите другую страницу данных, отсортируйте сетку или нажмите кнопку Изменить в строке. На этот раз должно появиться событие Selecting , так как базовые данные базы данных были изменены (см. рис. 10). Если текст не отображается, подождите несколько секунд и повторите попытку. Помните, что служба опроса проверяет наличие изменений в Products таблице каждые pollTime миллисекунды, поэтому между обновлением базовых данных и удалением кэшированных данных существует задержка.

При изменении таблицы Products кэшированные данные о продуктах вытесляются

Рис. 10. Изменение таблицы Products удаляет кэшированные данные о продукте (щелкните, чтобы просмотреть полноразмерное изображение)

Шаг 6. Программная работа с классомSqlCacheDependency

В руководстве по кэшированию данных в учебнике по архитектуре были описаны преимущества использования отдельного слоя кэширования в архитектуре, а не тесного связывания кэширования с ObjectDataSource. В этом руководстве мы создали класс для ProductsCL демонстрации программной работы с кэшем данных. Чтобы использовать зависимости кэша SQL на уровне кэширования, используйте SqlCacheDependency класс .

В опрашивочной системе SqlCacheDependency объект должен быть связан с определенной парой базы данных и таблицы. Например, следующий код создает SqlCacheDependency объект на основе таблицы базы данных Products Northwind:

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

Два входных параметра конструктора SqlCacheDependency — это имена базы данных и таблицы соответственно. Как и в случае со свойством ObjectDataSource SqlCacheDependency , используемое имя базы данных совпадает со значением, указанным в name атрибуте <add> элемента в Web.config. Имя таблицы — это фактическое имя таблицы базы данных.

Чтобы связать SqlCacheDependency с элементом, добавленным в кэш данных, используйте одну из Insert перегрузок метода, которая принимает зависимость. Следующий код добавляет значение в кэш данных на неопределенный срок, но связывает его с SqlCacheDependencyProducts в таблице. Короче говоря, значение будет оставаться в кэше до тех пор, пока оно не будет вытесно из-за ограничений памяти или из-за того, что система опроса обнаружила, что Products таблица изменилась с момента кэширования.

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

Класс Caching Layer в ProductsCL настоящее время кэширует данные из Products таблицы, используя срок действия, основанный на времени, 60 секунд. Давайте обновим этот класс так, чтобы он использовал зависимости кэша SQL. Метод ProductsCL класса , AddCacheItem который отвечает за добавление данных в кэш, в настоящее время содержит следующий код:

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);
}

Обновите этот код, чтобы использовать SqlCacheDependency объект вместо зависимости кэша MasterCacheKeyArray :

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);
}

Чтобы проверить эту функцию, добавьте GridView на страницу под существующим ProductsDeclarative Элементом GridView. Задайте для этого нового элемента GridView ID значение ProductsProgrammatic и с помощью смарт-тега привяжите его к новому объекту ObjectDataSource с именем ProductsDataSourceProgrammatic. Настройте ObjectDataSource для использования ProductsCL класса , установив для раскрывающихся списков на вкладках SELECT и UPDATE значения GetProducts и UpdateProductсоответственно.

Настройка ObjectDataSource для использования класса ProductsCL

Рис. 11. Настройка ObjectDataSource для использования ProductsCL класса (щелкните для просмотра полноразмерного изображения)

Выберите метод GetProducts в списке Drop-Down вкладок SELECT.

Рис. 12. Выбор GetProducts метода из списка Drop-Down вкладок SELECT (щелкните для просмотра полноразмерного изображения)

Выберите метод UpdateProduct в списке Drop-Down вкладок UPDATE.

Рис. 13. Выберите метод UpdateProduct в списке Drop-Down вкладки UPDATE (щелкните для просмотра полноразмерного изображения)

После завершения работы мастера настройки источника данных Visual Studio создаст BoundFields и CheckBoxFields в GridView для каждого поля данных. Как и в случае с первым элементом GridView, добавленным на эту страницу, удалите все поля, кроме ProductName, CategoryNameи , и UnitPriceотформатируйте эти поля по своему типу. В смарт-теге GridView проверка флажки Включить разбиение по страницам, Включить сортировку и Включить редактирование. Как и в случае ProductsDataSourceDeclarative с ObjectDataSource, Visual Studio присвоит свойству original_{0}ProductsDataSourceProgrammatic ObjectDataSource значение OldValuesParameterFormatString . Чтобы функция редактирования GridView работала правильно, присвойте этому свойству {0} значение (или вообще удалите назначение свойства из декларативного синтаксиса).

После выполнения этих задач итоговая декларативная разметка GridView и ObjectDataSource должна выглядеть следующим образом:

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

Чтобы проверить зависимость кэша SQL в слое кэширования, установите точку останова в методе ProductCL класса , AddCacheItem а затем начните отладку. При первом посещении SqlCacheDependencies.aspxнеобходимо достичь точки останова, так как данные запрашивается в первый раз и помещаются в кэш. Затем перейдите на другую страницу в GridView или отсортируйте один из столбцов. Это приводит к тому, что GridView повторно запросит свои данные, но данные должны быть найдены в кэше Products , так как таблица базы данных не была изменена. Если данные не найдены в кэше, убедитесь, что на компьютере достаточно памяти, и повторите попытку.

После разбиения на несколько страниц GridView откройте второе окно браузера и перейдите к учебнику Основные сведения в разделе Редактирование, вставка и удаление (~/EditInsertDelete/Basics.aspx). Обновите запись из таблицы Products, а затем в первом окне браузера просмотрите новую страницу или щелкните один из заголовков сортировки.

В этом сценарии вы увидите одну из двух вещей: будет достигнута точка останова, указывающая, что кэшированные данные были исключены из-за изменения в базе данных; или точка останова не будет достигнута, то SqlCacheDependencies.aspx есть теперь отображаются устаревшие данные. Если точка останова не достигнута, скорее всего, служба опроса еще не сработала с момента изменения данных. Помните, что служба опроса проверяет наличие изменений в Products таблице каждые pollTime миллисекунды, поэтому между обновлением базовых данных и удалением кэшированных данных существует задержка.

Примечание

Эта задержка, скорее всего, появится при редактировании одного из продуктов с помощью GridView в SqlCacheDependencies.aspx. В учебнике По кэшированию данных в архитектуре мы добавилиMasterCacheKeyArray зависимость кэша, чтобы убедиться, что данные, редактируемые с помощью ProductsCL метода класса s UpdateProduct , были вытеснили из кэша. Однако мы заменили эту зависимость кэша при изменении AddCacheItem метода ранее на этом шаге ProductsCL , и поэтому класс будет продолжать отображать кэшированные данные до тех пор, пока система опроса не заметит изменения в Products таблице. Мы посмотрим, как повторно ввести зависимость кэша на MasterCacheKeyArray шаге 7.

Шаг 7. Связывание нескольких зависимостей с кэшируемым элементом

Помните, что зависимость кэша MasterCacheKeyArray используется для обеспечения того, чтобы все связанные с продуктом данные вытеснили из кэша при обновлении любого отдельного элемента, связанного в нем. Например, GetProductsByCategoryID(categoryID) метод кэширует экземпляры ProductsDataTables для каждого уникального значения categoryID . Если один из этих объектов вытеснился, зависимость кэша MasterCacheKeyArray гарантирует, что другие объекты также будут удалены. Без этой зависимости кэша при изменении кэшированных данных существует вероятность того, что другие данные кэшированного продукта могут быть устаревшими. Следовательно, важно сохранить зависимость кэша MasterCacheKeyArray при использовании зависимостей кэша SQL. Однако метод кэша Insert данных допускает только один объект зависимости.

Кроме того, при работе с зависимостями кэша SQL может потребоваться связать несколько таблиц базы данных с зависимостями. Например, ProductsDataTable кэшированный в ProductsCL классе содержит имена категорий и поставщиков для каждого продукта, но AddCacheItem метод использует только зависимость Productsот . В этом случае, если пользователь обновит имя категории или поставщика, кэшированные данные продукта останутся в кэше и будут устаревшими. Поэтому мы хотим сделать кэшированные данные продуктов зависимыми не только Products от таблицы, но Categories и от таблиц и Suppliers .

КлассAggregateCacheDependency предоставляет средства для связывания нескольких зависимостей с элементом кэша. Начните с создания экземпляра AggregateCacheDependency . Затем добавьте набор зависимостей с помощью AggregateCacheDependency метода s Add . После вставки элемента в кэш данных передайте AggregateCacheDependency экземпляр . AggregateCacheDependencyПри изменении зависимостей экземпляра кэшированный элемент будет вытеснен.

Ниже показан обновленный код для ProductsCL метода класса .AddCacheItem Метод создает зависимость кэша MasterCacheKeyArray вместе с SqlCacheDependency объектами Productsдля таблиц , Categoriesи Suppliers . Все они объединяются в один AggregateCacheDependency объект с именем aggregateDependencies, который затем передается в Insert метод .

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);
}

Протестируйте этот новый код. Теперь изменения в таблицах Products, Categoriesили Suppliers приводят к вытеснениям кэшированных данных. Кроме того, ProductsCL метод класса UpdateProduct , который вызывается при редактировании продукта с помощью GridView, вытесняя MasterCacheKeyArray зависимость кэша, что приводит к вытеснениям кэша ProductsDataTable и повторному извлечению данных при следующем запросе.

Примечание

Зависимости кэша SQL также можно использовать с кэшированием выходных данных. Демонстрацию этой функции см. в статье Использование кэширования выходных данных ASP.NET с SQL Server.

Сводка

При кэшировании данных базы данных данные в идеале будут оставаться в кэше до тех пор, пока они не будут изменены в базе данных. В ASP.NET 2.0 зависимости кэша SQL можно создавать и использовать как в декларативных, так и в программных сценариях. Одна из проблем при таком подходе заключается в обнаружении времени изменения данных. Полные версии Microsoft SQL Server 2005 предоставляют возможности уведомлений, которые могут оповещать приложение об изменении результата запроса. Для Express Edition SQL Server 2005 и более ранних версий SQL Server следует использовать систему опроса. К счастью, настроить необходимую инфраструктуру опроса довольно просто.

Счастливое программирование!

Дополнительные материалы

Дополнительные сведения по темам, рассматриваемым в этом руководстве, см. в следующих ресурсах:

Об авторе

Скотт Митчелл (Scott Mitchell), автор семи книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с Веб-технологиями Майкрософт с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Sams Teach Yourself ASP.NET 2.0 в 24 часа. Его можно связать по адресу mitchell@4GuysFromRolla.com. или через его блог, который можно найти по адресу http://ScottOnWriting.NET.

Отдельная благодарность

Эта серия учебников была проверена многими полезными рецензентами. В качестве ведущих рецензентов этого руководства были Марко Рейнджл, Тереса Мерфи и Хилтон Гизеноу. Хотите ознакомиться с моими предстоящими статьями MSDN? Если да, опустите мне строку в mitchell@4GuysFromRolla.com.