SQL キャッシュ依存関係を使用する (C#)
最も簡単なキャッシュ方法は、キャッシュされたデータが指定された期間経過後に期限切れになることです。 しかし、この単純な方法は、キャッシュされたデータが基になるデータ ソースとの関連付けを維持しないため、古いデータが保持されすぎて保持されたり、現在のデータの有効期限が早すぎたりすることを意味します。 SqlCacheDependency クラスを使用すると、基になるデータが SQL データベースで変更されるまでデータがキャッシュされたままになります。 このチュートリアルでは、その方法を説明します。
はじめに
アーキテクチャのチュートリアルの 「ObjectDataSource を使用したデータのキャッシュ 」と 「データのキャッシュ」のチュートリアルで 調べたキャッシュ手法では、時間ベースの有効期限を使用して、指定した期間が経過した後にキャッシュからデータを削除しました。 この方法は、キャッシュのパフォーマンス向上とデータの古さのバランスを取る最も簡単な方法です。 ページ開発者は、 x 秒の有効期限を選択することで、キャッシュのパフォーマンス上の利点を x 秒だけ利用することを認めますが、データが最大 x 秒を超えて古くなることは決してありません。 もちろん、静的データの場合、「アプリケーションの起動時にデータをキャッシュする」チュートリアルで説明したように、x は Web アプリケーションの有効期間まで拡張できます。
データベース データをキャッシュする場合、多くの場合、時間ベースの有効期限は使いやすさのために選択されますが、多くの場合、不十分な解決策です。 データベース 内の基になるデータが変更されるまで、データベース データはキャッシュされたままになります。その場合にのみキャッシュが削除されます。 この方法により、キャッシュのパフォーマンス上の利点が最大化され、古いデータの期間が最小限に抑えられます。 ただし、これらの利点を享受するには、基になるデータベース データがいつ変更されたかを認識し、対応する項目をキャッシュから削除するシステムが存在する必要があります。 ASP.NET 2.0 より前は、ページ開発者がこのシステムの実装を担当していました。
ASP.NET 2.0 は、対応するキャッシュされた項目を削除できるように、データベースで変更がいつ発生したかを判断するために必要なクラスとインフラストラクチャを提供SqlCacheDependency
します。 基になるデータがいつ変更されたかを判断するには、通知とポーリングという 2 つの手法があります。 通知とポーリングの違いについて説明した後、ポーリングをサポートするために必要なインフラストラクチャを作成し、宣言型およびプログラム的なシナリオで クラスを SqlCacheDependency
使用する方法について説明します。
通知とポーリングについて
データベース内のデータがいつ変更されたかを判断するために使用できる方法は、通知とポーリングの 2 つあります。 通知を使用すると、データベースは、クエリが最後に実行されてから特定のクエリの結果が変更されたときに、ASP.NET ランタイムに自動的に警告します。この時点で、クエリに関連付けられているキャッシュされたアイテムが削除されます。 ポーリングでは、データベース サーバーは特定のテーブルが最後に更新された日時に関する情報を保持します。 ASP.NET ランタイムは定期的にデータベースをポーリングして、キャッシュに入力されてから変更されたテーブルをチェックします。 データが変更されたテーブルには、関連するキャッシュ項目が削除されています。
通知オプションは、ポーリングよりもセットアップが少なくて済み、テーブル レベルではなくクエリ レベルで変更を追跡するため、より詳細です。 残念ながら、通知は Microsoft SQL Server 2005 の完全版 (つまり、Express 以外のエディション) でのみ使用できます。 ただし、ポーリング オプションは、7.0 から 2005 までのすべてのバージョンの Microsoft SQL Serverで使用できます。 これらのチュートリアルでは、SQL Server 2005 の Express エディションを使用するため、ポーリング オプションの設定と使用に重点を置きます。 SQL Server 2005 の通知機能の詳細については、このチュートリアルの最後にある「さらに読む」セクションを参照してください。
ポーリングでは、、、および changeId
の 3 つの列notificationCreated
tableName
を持つ という名前AspNet_SqlCacheTablesForChangeNotification
のテーブルを含むようにデータベースを構成する必要があります。 このテーブルには、Web アプリケーションの SQL キャッシュ依存関係で使用する必要があるデータを含む各テーブルの行が含まれています。 列は tableName
テーブルの名前を指定し、 notificationCreated
行がテーブルに追加された日時を示します。 列の changeId
型 int
は で、初期値は 0 です。 その値は、テーブルを変更するたびにインクリメントされます。
データベースには、テーブルに AspNet_SqlCacheTablesForChangeNotification
加えて、SQL キャッシュの依存関係に含まれる可能性がある各テーブルにトリガーも含める必要があります。 これらのトリガーは、行が挿入、更新、または削除されるたびに実行され、 のAspNet_SqlCacheTablesForChangeNotification
テーブルのchangeId
値がインクリメントされます。
ASP.NET ランタイムは、 オブジェクトを使用してデータをキャッシュするときに、テーブルの現在 changeId
の SqlCacheDependency
を追跡します。 データベースは定期的にチェックされ、SqlCacheDependency
データがキャッシュされてからテーブルに変更が加えられたことを示す値が異なるため、データベース内の値と異なるchangeId
オブジェクトchangeId
はすべて削除されます。
手順 1: コマンド ライン プログラムのaspnet_regsql.exe
探索
ポーリング アプローチでは、前述のインフラストラクチャ (定義済みのテーブル (AspNet_SqlCacheTablesForChangeNotification
)、いくつかのストアド プロシージャ、および Web アプリケーションの SQL キャッシュ依存関係で使用できる各テーブルのトリガーを含むデータベースを設定する必要があります。 これらのテーブル、ストアド プロシージャ、およびトリガーは、 フォルダーにある$WINDOWS$\Microsoft.NET\Framework\version
コマンド ライン プログラム aspnet_regsql.exe
を使用して作成できます。 テーブルと関連するストアド プロシージャを 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_ddladmin
ロールにdb_securityadmin
存在する必要があります。
たとえば、Windows 認証を使用して という名前のデータベース サーバーScottsServer
上の という名前pubs
の Microsoft SQL Server データベースにポーリング用のインフラストラクチャを追加するには、適切なディレクトリに移動し、コマンド ラインから次のように入力します。
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
のデータベースの テーブルと titles
テーブルにauthors
トリガーを追加するには、次の値をpubs
ScottsServer
使用します。
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 Express Edition データベースを参照する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を開き、Windows 認証をlocalhost\SQLExpress
使用してサーバーに接続することを選択します。
図 1: サーバーにアタッチするlocalhost\SQLExpress
サーバーに接続すると、Management Studio によってサーバーが表示され、データベースやセキュリティなどのサブフォルダーが表示されます。 [データベース] フォルダーを右クリックし、[アタッチ] オプションを選択します。 [データベースのアタッチ] ダイアログ ボックスが表示されます (図 2 を参照)。 [追加] ボタンをクリックし、Web アプリケーションの NORTHWND.MDF
フォルダー内の App_Data
データベース フォルダーを選択します。
図 2: フォルダーからデータベースをNORTHWND.MDF
App_Data
アタッチする (フルサイズの画像を表示する場合はクリックします)
これにより、データベースが [データベース] フォルダーに追加されます。 データベース名は、データベース ファイルへの完全なパス、または GUID で先頭に付加された完全パスである可能性があります。 aspnet_regsql.exe コマンド ライン ツールを使用するときに、この長いデータベース名を入力する必要がないようにするには、アタッチしたデータベースを右クリックして [名前の変更] を選択して、データベースの名前をわかりやすい名前に変更します。 データベースの名前を DataTutorials に変更しました。
図 3: アタッチされたデータベースの名前を、さらに Human-Friendly 名に変更する
手順 3: Northwind データベースへのポーリング インフラストラクチャの追加
フォルダーからApp_Data
データベースをNORTHWND.MDF
アタッチしたので、ポーリング インフラストラクチャを追加する準備ができました。 データベースの名前を DataTutorials に変更した場合は、次の 4 つのコマンドを実行します。
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
これら 4 つのコマンドを実行した後、Management Studio でデータベース名を右クリックし、[タスク] サブメニューに移動し、[デタッチ] を選択します。 次に、Management Studio を閉じ、Visual Studio をもう一度開きます。
Visual Studio が再度開いたら、サーバー エクスプローラーを使用してデータベースにドリルインします。 新しいテーブル (AspNet_SqlCacheTablesForChangeNotification
)、新しいストアド プロシージャ、および 、Categories
、および Suppliers
テーブルのトリガーにProducts
注意してください。
図 4: データベースに必要なポーリング インフラストラクチャが含まれるようになりました
手順 4: ポーリング サービスの構成
必要なテーブル、トリガー、ストアド プロシージャをデータベースに作成した後、最後の手順はポーリング サービスを構成することです。これは、使用するデータベースとポーリング頻度をミリ秒単位で指定することで行われます Web.config
。 次のマークアップは、Northwind データベースを 1 秒に 1 回ポーリングします。
<?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>
要素 ( NorthwindDB ) の<add>
値はname
、人間が判読できる名前を特定のデータベースに関連付けます。 SQL キャッシュの依存関係を操作する場合は、ここで定義されているデータベース名と、キャッシュされたデータの基になるテーブルを参照する必要があります。 クラスを使用 SqlCacheDependency
して、SQL キャッシュの依存関係をキャッシュされたデータにプログラムで関連付ける方法については、手順 6 で説明します。
SQL キャッシュの依存関係が確立されると、ポーリング システムは要素で <databases>
定義されているデータベースにミリ秒ごとに pollTime
接続し、ストアド プロシージャを AspNet_SqlCachePollingStoredProcedure
実行します。 このストアド プロシージャは、コマンド ライン ツールを使用してaspnet_regsql.exe
手順 3 で再度追加されたもので、 の各レコードAspNet_SqlCacheTablesForChangeNotification
の と changeId
の値を返しますtableName
。 古い SQL キャッシュの依存関係は、キャッシュから削除されます。
この設定では pollTime
、パフォーマンスとデータの古さの間にトレードオフが生じます。 値を小さく pollTime
すると、データベースへの要求の数が増えますが、キャッシュから古いデータをより迅速に削除できます。 値を大きく pollTime
すると、データベース要求の数は減りますが、バックエンド データが変更されるまでと、関連するキャッシュ項目が削除されるまでの遅延が長くなります。 幸いなことに、データベース要求では単純なストアド プロシージャが実行され、単純で軽量なテーブルから数行しか返されなくなります。 ただし、さまざまな pollTime
値を試して、アプリケーションのデータベース アクセスとデータの古さの理想的なバランスを見つけてください。 使用できる最小値 pollTime
は 500 です。
注意
上記の例では、 要素に 1 つのpollTime
値が<sqlCacheDependency>
提供されていますが、必要に応じて 要素に値をpollTime
<add>
指定できます。 これは、複数のデータベースを指定し、データベースごとのポーリング頻度をカスタマイズする場合に便利です。
手順 5: SQL キャッシュの依存関係を宣言的に操作する
手順 1 から 4 では、必要なデータベース インフラストラクチャを設定し、ポーリング システムを構成する方法を確認しました。 このインフラストラクチャを用意することで、プログラムまたは宣言型の手法を使用して、関連する SQL キャッシュ依存関係を持つ項目をデータ キャッシュに追加できるようになりました。 この手順では、SQL キャッシュの依存関係を宣言的に操作する方法について説明します。 手順 6 では、プログラムによるアプローチについて説明します。
ObjectDataSource を使用したデータのキャッシュに関するチュートリアルでは、ObjectDataSource の宣言型キャッシュ機能について説明しました。 プロパティを EnableCaching
に true
設定し、 プロパティを CacheDuration
ある時間間隔に設定するだけで、ObjectDataSource は、指定した間隔の基になるオブジェクトから返されたデータを自動的にキャッシュします。 ObjectDataSource では、1 つ以上の SQL キャッシュ依存関係を使用することもできます。
SQL キャッシュの依存関係を宣言的に使用する方法を示すには、 フォルダー内のSqlCacheDependencies.aspx
ページをCaching
開き、ツールボックスから Designerに GridView をドラッグします。 GridView を ID
に ProductsDeclarative
設定し、そのスマート タグから、 という名前 ProductsDataSourceDeclarative
の新しい ObjectDataSource にバインドすることを選択します。
図 5: 名前付きの ProductsDataSourceDeclarative
新しい ObjectDataSource を作成する (フルサイズの画像を表示する場合はクリックします)
クラスを使用するように ObjectDataSource を ProductsBLL
構成し、[選択] タブのドロップダウン リストを に GetProducts()
設定します。 [更新] タブで、および の UpdateProduct
3 つの入力パラメーターproductName
unitPrice
を持つオーバーロードをproductID
選択します。 [挿入] タブと [削除] タブで、ドロップダウン リストを [(なし)] に設定します。
図 6: 3 つの入力パラメーターで UpdateProduct オーバーロードを使用する (クリックするとフルサイズの画像が表示されます)
図 7: INSERT タブと DELETE タブの Drop-Down リストを (なし) に設定します (フルサイズの画像を表示する をクリックします)
データ ソースの構成ウィザードが完了すると、Visual Studio によって、各データ フィールドに対して GridView に BoundFields と CheckBoxFields が作成されます。 、CategoryName
、、 以外のすべてのフィールドProductName
を削除しUnitPrice
、必要に応じてこれらのフィールドの書式を設定します。 GridView のスマート タグから、[ページングを有効にする]、[並べ替えを有効にする]、[編集を有効にする] チェック ボックスをチェックします。 Visual Studio では、ObjectDataSource の プロパティが OldValuesParameterFormatString
に original_{0}
設定されます。 GridView の編集機能が正常に機能するためには、宣言構文からこのプロパティを完全に削除するか、 {0}
既定値 に戻します。
最後に、GridView の上に Label Web コントロールを追加し、そのプロパティを ID
に ODSEvents
設定し、その EnableViewState
プロパティを に false
設定します。 これらの変更を行った後、ページの宣言型マークアップは次のようになります。 SQL キャッシュの依存関係機能を示すために必要ではない、GridView フィールドに対していくつかの美的なカスタマイズを行ったことに注意してください。
<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 が独自のキャッシュからデータにアクセスする場合、このイベントは発生しません。
次に、ブラウザーからこのページにアクセスします。 キャッシュはまだ実装していないため、グリッドをページ、並べ替え、または編集するたびに、"Selecting event fired, as figure 8 shows.
図 8: ObjectDataSource の Selecting
イベントは、GridView が Paged、Edited、または Sorted されるたびに発生します (フルサイズの画像を表示する場合はクリックします)
ObjectDataSource を使用したデータのキャッシュに関するチュートリアルで説明したように、 プロパティを EnableCaching
にtrue
設定すると、ObjectDataSource はそのプロパティでCacheDuration
指定された期間データをキャッシュします。 ObjectDataSource には プロパティもあります。これにより、 パターンをSqlCacheDependency
使用して、キャッシュされたデータに 1 つ以上の SQL キャッシュ依存関係が追加されます。
databaseName1:tableName1;databaseName2:tableName2;...
ここで 、databaseName は の 要素の 属性で name
指定されたデータベースの <add>
名前で Web.config
、 tableName はデータベース テーブルの名前です。 たとえば、Northwind テーブルに対する SQL キャッシュの依存関係に基づいてデータを無期限にキャッシュする ObjectDataSource を作成するには、ObjectDataSource の Products
EnableCaching
プロパティを に true
設定し、その SqlCacheDependency
プロパティを NorthwindDB:Products に設定します。
注意
SQL キャッシュの依存関係と時間ベースの有効期限を使用するには、 を にtrue
CacheDuration
設定EnableCaching
し、時間間隔に、データベースとSqlCacheDependency
テーブル名に設定します。 ObjectDataSource は、時間ベースの有効期限に達したとき、またはポーリング システムが基になるデータベース データが変更されたことを確認したときに、データを削除します。どちらか早い方が発生します。
の SqlCacheDependencies.aspx
GridView には、 と の 2 つのテーブルCategories
Products
のデータが表示されます (製品の CategoryName
フィールドは をCategories
介してJOIN
取得されます)。 したがって、次の 2 つの SQL キャッシュ依存関係を指定します。NorthwindDB:Products;NorthwindDB:Categories .
図 9: と に対する SQL キャッシュ依存関係 Products
Categories
を使用したキャッシュをサポートするように ObjectDataSource を構成する (フルサイズの画像を表示するには、ここをクリックします)
キャッシュをサポートするように ObjectDataSource を構成した後、ブラウザーを使用してページを見直します。 ここでも、"発生したイベントの選択" というテキストは最初のページに表示されますが、ページング、並べ替え、または [編集] または [キャンセル] ボタンをクリックすると削除されます。 これは、ObjectDataSource のキャッシュにデータが読み込まれた後、テーブルまたは Categories
テーブルが変更されるか、GridView を介してデータが更新されるまでProducts
、データはそこに残るためです。
グリッドをページングし、[Selecting event fired text]\(イベントが発生したテキストを選択する\) の欠如に気が付いた後、新しいブラウザー ウィンドウを開き、[編集]、[挿入]、[削除] セクションの [基本] チュートリアル (~/EditInsertDelete/Basics.aspx
) に移動します。 製品の名前または価格を更新します。 次に、最初のブラウザー ウィンドウから別のページのデータを表示するか、グリッドを並べ替えるか、行の [編集] ボタンをクリックします。 今回は、基になるデータベース データが変更されたため、"発生したイベントの選択" が再び表示されます (図 10 を参照)。 テキストが表示されない場合は、しばらく待ってからやり直してください。 ポーリング サービスでは、テーブルの Products
変更がミリ秒ごとに pollTime
チェックされるため、基になるデータが更新されるまでと、キャッシュされたデータが削除されるまでに遅延が発生します。
図 10: 製品テーブルを変更すると、キャッシュされた製品データが削除されます (クリックするとフルサイズの画像が表示されます)
手順 6: プログラムによるクラスのSqlCacheDependency
操作
アーキテクチャでのデータのキャッシュに関するチュートリアルでは、キャッシュを ObjectDataSource と緊密に結合するのではなく、アーキテクチャで別のキャッシュ レイヤーを使用する利点について説明しました。 このチュートリアルでは、データ キャッシュを ProductsCL
プログラムで操作する方法を示すクラスを作成しました。 キャッシュ層で SQL キャッシュの依存関係を利用するには、 クラスを使用します SqlCacheDependency
。
ポーリング システムでは、オブジェクトを特定の SqlCacheDependency
データベースとテーブルのペアに関連付ける必要があります。 たとえば、次のコードでは、Northwind データベースの テーブルに基づいて オブジェクトをProducts
作成SqlCacheDependency
します。
Caching.SqlCacheDependency productsTableDependency =
new Caching.SqlCacheDependency("NorthwindDB", "Products");
コンストラクターに対する SqlCacheDependency
2 つの入力パラメーターは、それぞれデータベース名とテーブル名です。 ObjectDataSource の SqlCacheDependency
プロパティと同様に、使用されるデータベース名は、 の 要素Web.config
の <add>
属性でname
指定された値と同じです。 テーブル名は、データベース テーブルの実際の名前です。
をデータ キャッシュに追加された項目に関連付けるには SqlCacheDependency
、依存関係を Insert
受け入れるメソッド オーバーロードのいずれかを使用します。 次のコードでは、データ キャッシュに無期限の値を追加しますが、テーブルの Products
と関連付けますSqlCacheDependency
。 つまり、 メモリ 制約が原因で削除されるまで、またはテーブルがキャッシュされてからテーブルが変更されたことがポーリング システムによって検出 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
クラスは、時間ベースの有効期限 60 秒を使用してテーブルの Products
データをキャッシュします。 代わりに SQL キャッシュの依存関係を使用するように、このクラスを更新しましょう。 ProductsCL
キャッシュにデータを追加するクラス s 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);
}
この機能をテストするには、既存 ProductsDeclarative
の GridView の下のページに GridView を追加します。 この新しい GridView を ID
に ProductsProgrammatic
設定し、スマート タグを使用して、 という名前 ProductsDataSourceProgrammatic
の新しい ObjectDataSource にバインドします。 クラスを使用ProductsCL
するように ObjectDataSource を構成し、SELECT タブと UPDATE タブのドロップダウン リストをそれぞれ と UpdateProduct
にGetProducts
設定します。
図 11: クラスを使用するように ObjectDataSource を構成する ProductsCL
(フルサイズの画像を表示するにはクリックします)
図 12: SELECT GetProducts
タブの Drop-Down リストからメソッドを選択します (フルサイズの画像を表示する をクリックします)
図 13: Update タブの Drop-Down リストから UpdateProduct メソッドを選択します (フルサイズの画像を表示する をクリックします)
データ ソースの構成ウィザードが完了すると、Visual Studio によって、各データ フィールドに対して GridView に BoundFields と CheckBoxFields が作成されます。 このページに追加された最初の GridView と同様に、、CategoryName
、、 以外のすべてのフィールドProductName
を削除しUnitPrice
、必要に応じてこれらのフィールドの書式を設定します。 GridView のスマート タグから、[ページングを有効にする]、[並べ替えを有効にする]、[編集を有効にする] チェック ボックスをチェックします。 ObjectDataSource と同様にProductsDataSourceDeclarative
、Visual Studio は ObjectDataSource の OldValuesParameterFormatString
プロパティを ProductsDataSourceProgrammatic
にoriginal_{0}
設定します。 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 キャッシュの依存関係をテストするには、 クラスの AddCacheItem
メソッドにブレークポイントをProductCL
設定し、デバッグを開始します。 に初めてアクセス SqlCacheDependencies.aspx
すると、データが初めて要求され、キャッシュに配置されるため、ブレークポイントにヒットする必要があります。 次に、GridView 内の別のページに移動するか、列の 1 つを並べ替えます。 これにより、GridView はデータの再クエリを実行しますが、データベース テーブルが変更されていないため Products
、キャッシュにデータが見つかる必要があります。 キャッシュにデータが繰り返し見つからない場合は、コンピューターに十分なメモリがあることを確認してから、もう一度やり直してください。
GridView のいくつかのページをページングした後、2 番目のブラウザー ウィンドウを開き、[編集]、[挿入]、[削除] セクション (~/EditInsertDelete/Basics.aspx
) の [基本] チュートリアルに移動します。 Products テーブルからレコードを更新し、最初のブラウザー ウィンドウで新しいページを表示するか、並べ替えヘッダーのいずれかをクリックします。
このシナリオでは、次の 2 つのいずれかが表示されます。いずれかのブレークポイントがヒットし、データベースの変更によりキャッシュされたデータが削除されたことを示します。または、ブレークポイントがヒットしません。つまり SqlCacheDependencies.aspx
、古いデータが表示されます。 ブレークポイントにヒットしない場合は、データが変更されてからポーリング サービスがまだ起動していない可能性があります。 ポーリング サービスでは、テーブルに対する Products
変更がミリ秒ごとに pollTime
チェックされるため、基になるデータが更新されるまでと、キャッシュされたデータが削除されるまでに遅延が発生します。
注意
この遅延は、 で GridView SqlCacheDependencies.aspx
を使用していずれかの製品を編集するときに表示される可能性が高くなります。 アーキテクチャのチュートリアルのキャッシュ データでは、クラスの UpdateProduct
メソッドを使用してProductsCL
編集されているデータがキャッシュから削除されたことを確認するために、キャッシュの依存関係を追加MasterCacheKeyArray
しました。 ただし、この手順で前にメソッドを変更するときに、このキャッシュ依存関係を AddCacheItem
置き換えたため ProductsCL
、クラスは、ポーリング システムがテーブルへの変更をメモするまで、キャッシュされたデータを表示し Products
続けます。 手順 7 でキャッシュの依存関係を再導入する MasterCacheKeyArray
方法について説明します。
手順 7: キャッシュされたアイテムに複数の依存関係を関連付ける
キャッシュの依存関係は MasterCacheKeyArray
、その中に関連付けられている 1 つの項目が更新されたときに 、すべての 製品関連データがキャッシュから削除されるようにするために使用されることを思い出してください。 たとえば、 メソッドは GetProductsByCategoryID(categoryID)
、一意の ProductsDataTables
categoryID 値ごとにインスタンスをキャッシュします。 これらのオブジェクトのいずれかが削除された場合、キャッシュの MasterCacheKeyArray
依存関係により、他のオブジェクトも確実に削除されます。 このキャッシュ依存関係がないと、キャッシュされたデータが変更されると、他のキャッシュされた製品データが古くなる可能性があります。 そのため、SQL キャッシュの依存関係を使用する場合は、キャッシュの依存関係を MasterCacheKeyArray
維持することが重要です。 ただし、データ キャッシュの メソッド Insert
では、1 つの依存関係オブジェクトのみが許可されます。
さらに、SQL キャッシュの依存関係を操作する場合は、複数のデータベース テーブルを依存関係として関連付ける必要がある場合があります。 たとえば、 クラスにProductsDataTable
ProductsCL
キャッシュされた には各製品のカテゴリ名と仕入先名が含まれますがAddCacheItem
、 メソッドでは に対Products
する依存関係のみが使用されます。 このような状況では、ユーザーがカテゴリまたはサプライヤーの名前を更新した場合、キャッシュされた製品データはキャッシュに残り、古くなります。 そのため、キャッシュされた製品データをテーブルだけでなく Products
、 Categories
テーブルと Suppliers
テーブルにも依存させる必要があります。
クラスはAggregateCacheDependency
、複数の依存関係をキャッシュ項目に関連付ける手段を提供します。 まず、インスタンスを AggregateCacheDependency
作成します。 次に、 メソッドを使用して依存関係のセットをAggregateCacheDependency
Add
追加します。 その後、データ キャッシュに項目を挿入する場合は、 インスタンスを AggregateCacheDependency
渡します。 インスタンスの依存関係のいずれかがAggregateCacheDependency
変更されると、キャッシュされた項目が削除されます。
クラス s AddCacheItem
メソッドの更新されたコードを次にProductsCL
示します。 メソッドは、、、MasterCacheKeyArray
および テーブルのオブジェクトとSqlCacheDependency
共にCategories
Products
キャッシュ依存関係をSuppliers
作成します。 これらはすべて という名前aggregateDependencies
の 1 つのAggregateCacheDependency
オブジェクトに結合され、 メソッドに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);
}
この新しいコードをテストします。これで、Categories
または Suppliers
テーブルがProducts
変更されると、キャッシュされたデータが削除されます。 さらに、GridView を ProductsCL
使用して製品を編集するときに呼び出されるクラス s UpdateProduct
メソッドは、キャッシュの依存関係を削除 MasterCacheKeyArray
します。これにより、キャッシュ ProductsDataTable
が削除され、次の要求でデータが再取得されます。
注意
SQL キャッシュの依存関係は、 出力キャッシュでも使用できます。 この機能のデモについては、「ASP.NET 出力キャッシュとSQL Serverの使用」を参照してください。
まとめ
データベース データをキャッシュする場合、データはデータベース内で変更されるまでキャッシュに残るのが理想的です。 ASP.NET 2.0 では、SQL キャッシュの依存関係を作成し、宣言型とプログラム型の両方のシナリオで使用できます。 このアプローチの課題の 1 つは、データがいつ変更されたかを検出することです。 Microsoft SQL Server 2005 のフル バージョンでは、クエリ結果が変更されたときにアプリケーションに警告できる通知機能が提供されます。 SQL Server 2005 以前のバージョンの SQL Server の Express Edition では、代わりにポーリング システムを使用する必要があります。 幸いなことに、必要なポーリング インフラストラクチャの設定は非常に簡単です。
幸せなプログラミング!
もっと読む
このチュートリアルで説明するトピックの詳細については、次のリソースを参照してください。
- Microsoft SQL Server 2005 でのクエリ通知の使用
- クエリ通知の作成
- クラスを使用した ASP.NET での
SqlCacheDependency
キャッシュ - ASP.NET SQL Server登録ツール (
aspnet_regsql.exe
) - の概要
SqlCacheDependency
著者について
7 冊の ASP/ASP.NET 書籍の著者であり、 4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジと協力しています。 Scott は独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズ・ティーチ・自分自身 ASP.NET 24時間で2.0です。 にアクセスmitchell@4GuysFromRolla.comすることも、ブログを介して アクセスすることもできます。これは でhttp://ScottOnWriting.NET確認できます。
特別な感謝
このチュートリアル シリーズは、多くの役立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者は、マルコ・レンジル、テレサ・マーフィー、ヒルトン・ギーゼナウでした。 今後の MSDN 記事の確認に関心がありますか? その場合は、 に行mitchell@4GuysFromRolla.comをドロップしてください。
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示