LinqDataSource コントロールを使用すると、データ コントロールをさまざまなデータ ソースに接続できます。この場合のデータ ソースとしては、データベース データ、データ ソースのクラス、メモリ内コレクションなどが挙げられます。LinqDataSource コントロールを使用すると、これらの種類のデータ ソースに対してデータベースのような取得タスク (選択、フィルタ処理、グループ化、および並べ替え) を指定できます。データベース テーブルに対する変更タスク (更新、削除、および挿入) を指定することもできます。
LinqDataSource は、パブリック フィールドまたはプロパティに格納されている各種のデータ コレクションに接続できます。データ操作を実行するための宣言型マークアップおよびコードは、すべてのデータ ソースに共通です。データベース テーブルのデータとやり取りするときも、配列などのデータ コレクションのデータとやり取りするときも、同じ構文を使用できます。
LinqDataSource コントロールの概要については、「チュートリアル : LinqDataSource コントロールと DetailsView コントロールを使用したデータの取得、更新、挿入、および削除」を参照してください。
データベースのデータへの接続
データベースのデータとやり取りする場合は、LinqDataSource コントロールをデータベースに直接接続しません。代わりに、データベースおよびそのテーブルを表すエンティティ クラスとやり取りします。エンティティ クラスを生成するには、オブジェクト リレーショナル デザイナ を使用するか、SqlMetal.exe ユーティリティを実行します。詳細については、「オブジェクト リレーショナル デザイナ (O/R デザイナ)」または「コード生成ツール (SqlMetal.exe)」を参照してください。作成したエンティティ クラスは、通常、Web アプリケーションの App_Code フォルダに格納されます。O/R デザイナ または SqlMetal.exe ユーティリティは、データベースを表すクラスを 1 つと、データベースのテーブルを表すクラスをテーブルごとに 1 つ生成します。
データベースを表すクラスは、データ ソースの値の取得と設定を行います。LinqDataSource コントロールは、データ テーブルを表すクラスのプロパティの読み込みと設定を行います。更新、挿入、および削除の各操作をサポートするには、データベース クラスが DataContext クラスから派生し、テーブル クラスが Table<(Of <(TEntity>)>) クラスを参照している必要があります。
LinqDataSource コントロールをデータベース クラスに接続するには、ContextTypeName プロパティを、データベースを表すクラスの名前に設定します。LinqDataSource コントロールを特定のテーブルに接続するには、TableName プロパティを、そのデータ テーブルを表すクラスの名前に設定します。たとえば、AdventureWorks データベースの Contacts テーブルに接続するには、ContextTypeName プロパティを AdventureWorksDataContext (または、このデータベース オブジェクトに対して指定した名前) に設定します。TableName プロパティは Contacts に設定します。AdventureWorks データベースに接続する LinqDataSource コントロールのマークアップの例を次に示します。
<asp:LinqDataSource
ContextTypeName="AdventureWorksDataContext"
TableName="Contacts"
ID="LinqDataSource1"
runat="server">
</asp:LinqDataSource>
この例では、O/R デザイナによって生成されたクラスは示していません。生成されたコードが、このトピックで扱うには長すぎるためです。ただし、この例が機能するには、この生成されたコードが必要です。詳細については、「LINQ to SQL でのコード生成」を参照してください。
メモリ内コレクションのデータへの接続
配列などのメモリ内データ コレクションに接続する場合は、ContextTypeName プロパティを、このコレクションを表すクラスの名前に設定します。TableName プロパティは、コレクション自体の名前に設定します。
文字列値の配列が格納されたクラスの例を次に示します。
Public Class MovieLibrary
Dim _availableGenres() As String = {"Comedy", "Drama", "Romance"}
Public ReadOnly Property AvailableGenres() As String()
Get
Return _availableGenres
End Get
End Property
End Class
public class MovieLibrary
{
string[] _availableGenres = { "Comedy", "Drama", "Romance" };
public MovieLibrary()
{
}
public string[] AvailableGenres
{
get
{
return _availableGenres;
}
}
}
上の例のクラスから動画ジャンルの一覧を読み込む LinqDataSource コントロールの例を次に示します。ジャンルの配列を取得するには、ContextTypeName プロパティを MovieLibrary に設定し、TableName プロパティを AvailableGenres に設定します。
<asp:LinqDataSource
ContextTypeName="MovieLibrary"
TableName="AvailableGenres"
ID="LinqDataSource1"
runat="server">
</asp:LinqDataSource>
LinqDataSource コントロールとデータ バインド コントロールの使用
LinqDataSource コントロールのデータを表示するために、データ バインド コントロールを LinqDataSource コントロールにバインドできます。たとえば、DetailsView コントロール、GridView コントロール、または ListView コントロールを LinqDataSource コントロールにバインドします。これを行うには、データ バインド コントロールの DataSourceID プロパティを、LinqDataSource コントロールの ID に設定します。LinqDataSource コントロールのすべてのデータを表示する GridView コントロールの例を次に示します。
<asp:LinqDataSource
runat="server"
ContextTypeName="AdventureWorksDataContext"
TableName="Contacts"
ID="LinqDataSource1">
</asp:LinqDataSource>
<asp:GridView
ID="GridView1"
runat="server"
DataSourceID="LinqDataSource1" >
</asp:GridView>
データ バインド コントロールによってユーザー インターフェイスが自動的に作成され、LinqDataSource コントロールのデータが表示されます。データの並べ替えとページングのためのインターフェイスを表示することもできます。データ変更が許可されている場合は、レコードの更新、挿入、および削除のためのインターフェイスが表示されます。
どのデータ (プロパティ) を表示するかを制限するには、データ コントロールのフィールドが自動生成されないようにデータ バインド コントロールを構成します。こうすると、これらのフィールドをデータ バインド コントロールで明示的に定義できます。LinqDataSource コントロールの場合はすべてのデータが取得されますが、データ バインド コントロールの場合は指定したプロパティのみが表示されます。AdventureWorks データベースの Products テーブルの Name プロパティと StandardCost プロパティのみを表示する GridView コントロールの例を次に示します。AutoGenerateColumns プロパティが false に設定されています。
<asp:LinqDataSource
ContextTypeName="AdventureWorksDataContext"
TableName="Products"
ID="LinqDataSource1"
runat="server">
</asp:LinqDataSource>
<asp:GridView
DataSourceID="LinqDataSource1"
AutoGenerateColumns="false"
ID="GridView1"
runat="server">
<Columns>
<asp:BoundField DataField="Name" />
<asp:BoundField DataField="StandardCost" />
</Columns>
</asp:GridView>
クエリで返されるプロパティの種類を制限する必要がある場合、これらのプロパティを定義するには、LinqDataSource コントロールの Select プロパティを設定します。
LinqDataSource コントロールと他のデータ ソース コントロールとの比較
データの選択
LinqDataSource コントロールの Select プロパティの値を指定しなかった場合、データ ソース クラスのすべてのプロパティが取得されます。たとえば、LinqDataSource コントロールは、データベース テーブルの各列の値を返します。
データ ソースから取得するプロパティの種類を制限するには、Select プロパティを、取得するプロパティの名前に設定します。1 つのプロパティのみを取得する場合は、Select プロパティをそのプロパティの名前に設定します。たとえば、データベース テーブルの City 列の値のみを取得するには、Select プロパティを City に設定します。LinqDataSource コントロールは、このプロパティから、適切に型指定された項目が格納された List<(Of <(T>)>) コレクションを返します。City プロパティがテキスト (文字列) として型指定されている場合、City プロパティを選択すると、文字列値の List<(Of <(T>)>) コレクションが返されます。
データ クラスの一部のプロパティのみを取得するには、Select プロパティで new 関数を使用し、取得する列を指定します。指定したプロパティのみを含むクラスを動的に作成することになるので、new 関数を使用する必要があります。たとえば、詳細な住所が格納されたデータ ソースから City プロパティと PostalCode プロパティのみを取得する場合は、Select プロパティを new(City, PostalCode) に設定します。LinqDataSource コントロールは、これらのプロパティを含むクラスのインスタンスが格納された List<(Of <(T>)>) コレクションを返します。
1 つのプロパティのみを選択する場合、返されるオブジェクトはそのプロパティの値の単純なコレクションであるため、new 関数を使用する必要はありません。一方、複数のプロパティを指定する場合、LinqDataSource コントロールで、それらのプロパティを含む新しいクラスを作成する必要があります。
Select 句による値の計算
Select 句で値を計算できます。たとえば、オーダー品目の合計を計算するには、Select プロパティを new(SalesOrderDetailID, OrderQty * UnitPrice As LineItemTotal) に設定します。As キーワードを使用すると、計算した値に名前 (別名) を割り当てることができます。詳細については、「チュートリアル : LinqDataSource コントロールと GridView コントロールを使用したデータのサブセットの選択およびフィルタ処理」を参照してください。
LinqDataSource コントロールを使用してデータのサブセットを取得する方法の例を次に示します。この例では、返された値に別名を割り当て、値を計算するように Select プロパティが設定されています。
<asp:LinqDataSource
ContextTypeName="ExampleDataContext"
TableName="OrderDetails"
Select="new(SalesOrderDetailID As DetailID,
OrderQty * UnitPrice As LineItemTotal,
DateCreated As SaleDate)"
ID="LinqDataSource1"
runat="server">
</asp:LinqDataSource>
Where 句によるデータのフィルタ処理
返されたデータをフィルタ処理して、特定の条件を満たすレコードのみを取得できます。これを行うには、Where プロパティを、返されるデータに含まれるためにレコードが満たす必要がある条件に設定します。Where プロパティの値を指定しなかった場合、データ ソースのすべてのレコードが取得されます。フィルタ処理するには、フィルタ式を作成します。フィルタ式では、比較を使用して、レコードを含めるかどうかを判定します。比較は、静的な値に対して行うことも、パラメータ プレースホルダで指定する変数値に対して行うこともできます。
静的な値を使用した Where 句の作成
プロパティの値を静的な値と比較する場合は、そのプロパティおよび静的な値を使用して、Where プロパティを定義します。たとえば、1000 より大きい ListPrice 値を持つレコードのみを取得するには、Where プロパティを ListPrice > 1000 に設定します。
論理 AND の && 演算子または and 演算子、および論理 OR の || 演算子または or 演算子を使用できます。たとえば、ListPrice の値が 1000 より大きいか、UnitCost の値が 500 より大きいか、DaysToManufacture の値が 3 より大きいレコードを取得するには、Where プロパティを ListPrice > 1000 || UnitCost > 500 || DaysToManufacture > 3 に設定します。すべての条件を満たすレコードのみを取得するには、Where プロパティを ListPrice > 1000 && UnitCost > 500 && DaysToManufacture > 3 に設定します。
文字列値を比較する場合は、条件を単一引用符で囲み、リテラル値を二重引用符で囲む必要があります。たとえば、Category 列が "Sports" であるレコードのみを取得するには、Where プロパティを 'Category = "Sports"' に設定します。
文字列値と数値の両方でフィルタ処理されたデータを取得する LinqDataSource コントロールの例を次に示します。
<asp:LinqDataSource
ContextTypeName="ExampleDataContext"
TableName="Product"
Where='Category = "Sports" && Weight < 10'
ID="LinqDataSource1"
runat="server"
</asp:LinqDataSource>
パラメータ化された Where 句の作成
プロパティ値を、実行時にのみ取得できる値と比較する場合は、WhereParameters プロパティ コレクションのパラメータを定義します。たとえば、ユーザーによって指定された値を使用してフィルタ処理する場合は、その値を表すパラメータを作成します。LinqDataSource コントロールは、このパラメータの現在の値を使用して Where 句を作成します。
DropDownList1 という名前のコントロールでユーザーが選択した項目に基づいてデータを取得する LinqDataSource コントロールの例を次に示します。
<asp:DropDownList AutoPostBack="true" ID="DropDownList1" runat="server">
<asp:ListItem Value="Sports">Sports</asp:ListItem>
<asp:ListItem Value="Garden">Garden</asp:ListItem>
<asp:ListItem Value="Auto">Auto</asp:ListItem>
</asp:DropDownList>
<asp:LinqDataSource
ContextTypeName="ExampleDataContext"
TableName="Products"
AutoGenerateWhereClause="true"
ID="LinqDataSource1"
runat="server">
<WhereParameters>
<asp:ControlParameter
Name="Category"
ControlID="DropDownList1"
Type="String" />
</WhereParameters>
</asp:LinqDataSource>
<asp:GridView
DataSourceID="LinqDataSource1"
ID="GridView1"
runat="server">
</asp:GridView>
AutoGenerateWhereClause プロパティを true に設定すると、LinqDataSource コントロールによって Where 句が自動的に作成されます。このオプションは、複数のパラメータがある場合に便利です。Where プロパティで各条件を指定する必要がなくなるからです。代わりに、WhereParameters プロパティ コレクションですべてのパラメータを追加すると、各パラメータを含む Where 句が LinqDataSource コントロールによって自動的に作成されます。
AutoGenerateWhereClause プロパティを true に設定した場合は、各パラメータの名前が、対応するプロパティの名前と一致している必要があります。たとえば、パラメータの値を Category プロパティと突き合わせて確認するには、パラメータの名前が Category である必要があります。すべての比較は、等値比較になります。値がパラメータ値より大きい (または小さい) かどうかはテストできません。WhereParameters コレクションで複数のパラメータを指定すると、論理 AND を使用してすべてのパラメータが結合されます。
非等値比較を行う場合、または論理 OR で条件を結合する場合は、AutoGenerateWhereClause プロパティを false に設定します。これにより、Where プロパティで条件を定義できるようになります。パラメータごとに、Where プロパティにプレースホルダを指定します。
データのフィルタ処理で非等値をテストする方法の例を次に示します。
<asp:DropDownList
AutoPostBack="true"
ID="DropDownList1"
runat="server">
<asp:ListItem Value="0">0</asp:ListItem>
<asp:ListItem Value="25">25</asp:ListItem>
<asp:ListItem Value="100">100</asp:ListItem>
<asp:ListItem Value="400">400</asp:ListItem>
</asp:DropDownList>
<asp:LinqDataSource
ContextTypeName="ExampleDataContext"
TableName="Products"
Where="Price > @UserPrice"
ID="LinqDataSource1"
runat="server">
<WhereParameters>
<asp:ControlParameter
Name="UserPrice"
DefaultValue="0"
ControlID="DropDownList1"
Type="Int32" />
</WhereParameters>
</asp:LinqDataSource>
<asp:GridView
DataSourceID="LinqDataSource1"
ID="GridView1"
runat="server">
</asp:GridView>
詳細については、AutoGenerateWhereClause のトピックを参照してください。
データのグループ化と集計
1 つ以上の列に共通の値を持つレコードのデータを統合するために、データをグループ化できます。これを行うには、GroupBy プロパティを、データの統合に使用するプロパティの名前に変更します。たとえば、住所情報が格納されたテーブルから同じ市区町村の値を持つレコードをグループ化するには、GroupBy を City に設定します。
GroupBy プロパティを集計関数と組み合わせて使用すると、グループ化されたデータの値を計算して、プロパティの平均や合計を取得できます。グループ化に使用された値を取得するには、Key オブジェクトを参照します。
ProductCategory という名前のプロパティでデータをグループ化する方法の例を次に示します。グループ化された値は、Select プロパティに Key を指定することによって取得します。Select プロパティには、Average 集計メソッドと Count 集計メソッドも指定しています。
<asp:LinqDataSource
ContextTypeName="ExampleDataContext"
TableName="Products"
GroupBy="ProductCategory"
Select="new(Key,
Average(ListPrice) As AverageListPrice,
Average(Cost) As AverageCost,
Count() As RecordCount)"
ID="LinqDataSource1"
runat="server">
</asp:LinqDataSource>
グループに含まれる個々のレコードを取得するには、It キーワードを使用します。詳細については、「方法 : LinqDataSource コントロールを使用してデータをグループ化および集計する」を参照してください。
集計メソッド
LinqDataSource コントロールを使用する場合に利用できる集計メソッドの一覧を次の表に示します。
集計関数 | 説明 |
|---|
Count() | 一連のデータにおけるレコードの総数を返します。 |
Average(column) | 返されたすべてのレコードについて、指定された列の平均値を返します。 |
Sum(column) | 返されたすべてのレコードについて、指定された列のすべての値を加算して得た値を返します。 |
Max(column) | 返されたすべてのレコードについて、指定された列の最大値を返します。 |
Min(column) | 返されたすべてのレコードについて、指定された列の最小値を返します。 |
Where(condition) | 指定された条件に基づいて、返されたレコードをフィルタ処理します。 |
Any() | コレクションにレコードが格納されているかどうかを確認します。 |
All(condition) | コレクション内のすべてのレコードが、指定された条件を満たしているかどうかを確認します。 |
データの更新、挿入、および削除
データの並べ替え
LinqDataSource オブジェクトでは、クエリから返されたデータを 2 とおりの方法で並べ替えることができます。Web ページを開発する場合は、静的な値でデータを並べ替えることができます。また、実行時にユーザーが動的にデータを並べ替えることができるようにすることもできます。
静的なデータに従ってデータを並べ替えるには、プロパティの名前を OrderBy プロパティに割り当てます。実行時にユーザーがデータを並べ替えることができるようにするには、AutoSort プロパティを true (既定値) に設定します。次に、並べ替え式を LinqDataSource コントロールに渡します。GridView コントロールなどのデータ バインド コントロールは、AllowSorting プロパティが true に設定されている場合のみ、並べ替え式を渡します。
OrderBy プロパティに複数の列名を指定するには、列名をコンマで区切ります。たとえば、"LastName, FirstName" と指定した場合、最初に LastName を基準にレコードが並べ替えられ、LastName フィールドに一致する値を持つレコードが FirstName を基準に並べ替えられます。
最初に特定の順序でデータを返し、次にユーザーがその順序を変更できるようにする場合は、両方の並べ替え方法を使用できます。その場合は、AutoSort プロパティを true に設定し、OrderBy プロパティをプロパティの名前に設定します。
最初に LastName を基準にレコード並べ替え、次に FirstName を基準に並べ替え、最後に MiddleName を基準に並べ替える LinqDataSource コントロールの例を次に示します。また、LinqDataSource コントロールは、ユーザーが動的に行を並べ替えることができるように構成されています。GridView コントロールなどのデータ コントロールを LinqDataSource コントロールにバインドすると、データを表示し、ユーザーが並べ替え順序を指定できるように構成できます。
<asp:LinqDataSource
ContextTypeName="ExampleDataContext"
TableName="Contact"
OrderBy="LastName, FirstName, MiddleName"
AutoSort="true"
ID="LinqDataSource1"
runat="server"
</asp:LinqDataSource>
値の動的評価のためのパラメータの使用
同時実行制御
ユーザーによるデータの更新または削除を許可する場合、別のプロセスによってデータ ソース内のデータが変更されていないことを確認したうえで、更新または削除の操作を続行する必要があります。値が変更されたかどうかを確認しないと、別のプロセスによって設定された値を誤って上書きして、データが矛盾した状態のままになる可能性があります。
LinqDataSource コントロールを使用すると、データが変更されたかどうかを判定できます。このコントロールは、元の値を Web ページのビューステートに格納します。Web ページがポストバックされると、元の値と更新後の値の両方がページに格納されます。LinqDataSource コントロールでは、LINQ to SQL を使用して、元の値とデータ ソース内の現在の値が比較されます。これらの値が同じ場合はデータが変更されていないことを意味し、LINQ to SQL によってデータが更新または削除されます。データが変更されていた場合、LINQ to SQL は例外を発生させます。
どの列の値を確認するかを手動で指定するには、エンティティ クラスで列の UpdateCheck プロパティを設定します。O/R デザイナ によってデータベース テーブルのコードが生成されるときに、データベースで管理されている列について UpdateCheck プロパティが Never に設定されます。その他の列の値は、常に同時実行チェックに含まれることを意味する Always に設定されます。列が同時実行チェックに含まれないようにするには、UpdateCheck プロパティを Never に設定します。このプロパティを Never に設定すると、その列の値がビューステートに格納されることもなくなります。ユーザーが値を変更した場合のみ、データ ソースと照合して値をチェックするには、UpdateCheck プロパティを WhenChanged に設定します。
重要情報をビューステートに格納する必要がある場合は、ビューステートを暗号化することをお勧めします。詳細については、「Encrypt ViewState in ASP.NET 2.0」を参照してください。
メモ : |
|---|
ビューステートを暗号化すると、Web ページのパフォーマンスに影響を及ぼす可能性があります。 |
SQL Server データの同時実行チェックの最適化
多くの値をビューステートに格納すると、Web ページのサイズが拡大し、重要情報がユーザーに公開される可能性があります。SQL Server データベースのデータを操作している場合は、タイムスタンプ値を格納する列をデータベース内に作成することにより、Web ページのパフォーマンスを向上し、セキュリティを強化できます。SQL Server では、レコードが変更されるたびにタイムスタンプ列が自動更新されます。この場合、LinqDataSource コントロールは、レコードが変更されたかどうかを確認するためにレコードの各列を比較する必要がありません。代わりに、ビューステートのタイムスタンプと、データベースのタイムスタンプを比較するだけで済みます。
SQL Server データベースにタイムスタンプ列を追加した場合、タイムスタンプのみがビューステートに格納されるように、O/R デザイナ によってエンティティ クラスが自動的に作成されます。詳細については、「チュートリアル : LinqDataSource コントロールでのタイムスタンプを使用したデータの整合性のチェック」を参照してください。
ストアド プロシージャの使用
LinqDataSource コントロールを使用してストアド プロシージャからデータを取得するには、Selecting イベントのハンドラを作成します。このイベント ハンドラでは、ストアド プロシージャを表すデータコンテキスト クラスのメソッドを呼び出します。次に、ストアド プロシージャの結果を LinqDataSourceSelectEventArgs オブジェクトの Result プロパティに設定します。自動的な更新、挿入、および削除の操作を有効にするには、メソッドから返される型が、TableName プロパティで指定される型と一致する必要があります。
Result プロパティを、ストアド プロシージャを表すメソッドから返されるオブジェクトに割り当てる方法を次の例に示します。
Protected Sub LinqDataSource_Selecting(ByVal sender As Object, _
ByVal e As LinqDataSourceSelectEventArgs)
Dim exampleContext As ExampleDataContext = New ExampleDataContext()
e.Result = exampleContext.GetRegisteredCustomers()
End Sub
protected void LinqDataSource_Selecting(object sender,
LinqDataSourceSelectEventArgs e)
{
ExampleDataContext exampleContext = new ExampleDataContext();
e.Result = exampleContext.GetRegisteredCustomers();
}
データ コンテキスト メソッドの作成の詳細については、「方法 : ストアド プロシージャや関数にマップされる DataContext メソッドを作成する (O/R デザイナ)」を参照してください。
データの修正時の値の検証
LinqDataSource コントロールのイベント