DB のレコード一覧を表示する場合、レコード数が多い場合はページングが必要になってきます。
SqlDataSource を使って、ウィザードベースでクエリなどを設定していけば、コードを一行も書くことなく簡単にページング機能を実装できます。
しかしながら、ウィザードベースで実装した場合は、ページを切り替えるたびに全レコードを取得し、そのページの当該部分のみを表示するという動作になります。
レコード数が多い場合、ページングの都度全レコードを取得するのは負荷が大きく、できれば避けたい操作です。
ちなみに、先の記事 カスタムページャー で紹介した Repeater とカスタムページャーを使用したページングではそのあたりは考慮してあります。
今回は、先の記事と同等な内容を、ObjectDataSource と ListView を使って実現する例を書いてみます。実行結果は以下のようになります。
ポイントは、先の記事のようなストアドプロシージャを使うのではなくて、必要なレコードのみ DB から取得するクラス/メソッドを実装して、それらを ObjectDataSource で定義されているプロパティに設定するというところです。
加えて、出来るだけ ObjectDataSource と ListView が持つページングの機能を利用し、自力でコードは書かない(上記のクラス/メソッドを除く)ということもあります。
まず、型付 DataSet + TableAdapter(xsd ファイル)を Visual Studio のウィザードを利用して作成します。
Microsoft が提供しているサンプルデータベース Northwind の Products テーブルを利用します。ウィザードに従って進めていくと xsd ファイルが作られ、これをベースに 型付 DataSet + TableAdapter のコードが自動生成されます。
xsd ファイルを開くと、以下のように表示されるはずです。
自動生成されたコードは、Web アプリケーションプロジェクトの場合は xsd ファイルの直下に、Web サイトプロジェクトの場合は Temporary ASP.NET Files フォルダ内にあります。
この TableAdapter コードを partial class を使って拡張して、必要なレコードのみ DB から取得するためのクラス/メソッドを実装します。
以下のようになります。GetDataByIndex メソッドの引数名 startRowIndex, maximumRowsは、ObjectDataSource がデフォルトでその名前を参照していますので、そのまま使うのが面倒がないです(変更する場合は MaximumRowsParameterName プロパティと StartRowIndexParameterName プロパティに変更後の引数名を設定してください)。名前空間名、クラス名は、自動生成されたコードを参照してください。
using System;
using System.Data;
using System.Configuration;
using System.Data.SqlClient;
using System.ComponentModel;
namespace ProductsDataSetTableAdapters
{
public partial class ProductsTableAdapter
{
[DataObjectMethod(DataObjectMethodType.Select, true)]
public ProductsDataSet.ProductsDataTable GetDataByIndex(int startRowIndex, int maximumRows)
{
SqlDataAdapter adapter;
string query = String.Format(
"SELECT * " +
"FROM (" +
"SELECT *, ROW_NUMBER() OVER (ORDER BY [ProductID] ASC) AS rownum " +
"FROM [Products]) AS DerivedTable " +
"WHERE rownum BETWEEN {0} AND {1} " +
"ORDER BY [ProductID] ASC",
startRowIndex + 1, maximumRows + startRowIndex);
adapter = new SqlDataAdapter(query, this.Connection);
ProductsDataSet dataset = new ProductsDataSet();
adapter.Fill(dataset.Products);
return dataset.Products;
}
public int GetNumberOfMessages()
{
SqlCommand command;
command =
new SqlCommand("SELECT COUNT(*) FROM [Products]", this.Connection);
this.Connection.Open();
int rows = (int)command.ExecuteScalar();
this.Connection.Close();
return rows;
}
}
}
最後に、ObjectDataSource と ListView を実装した aspx ページを作成します。コードは以下のようになります。
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<style type="text/css">
table.style1
{
border-style: solid;
border-width: 2px;
border-color: Black;
text-align: center;
border-collapse: collapse;
}
table.style1 th
{
border-style: solid;
border-width: 2px 1px 2px 1px;
border-color: Black;
background-color: #6699FF;
color: #FFFFFF;
}
table.style1 td
{
border-style: solid;
border-width: 1px;
border-color: Black;
}
.alternate
{
background-color: #CCFFFF;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ObjectDataSource ID="ObjectDataSource1"
runat="server"
SelectMethod="GetDataByIndex"
SelectCountMethod="GetNumberOfMessages"
EnablePaging="True"
TypeName="ProductsDataSetTableAdapters.ProductsTableAdapter">
</asp:ObjectDataSource>
<asp:ListView ID="ListView1"
runat="server"
DataKeyNames="ProductID"
DataSourceID="ObjectDataSource1"
EnableModelValidation="True">
<LayoutTemplate>
<table id="Table1" runat="server" class="style1">
<tr id="Tr1" runat="server" style="">
<th id="Th1" rowspan="2" runat="server">ProductID</th>
<th id="Th2" colspan="7" runat="server">ProductName</th>
<th id="Th3" rowspan="2" runat="server">Discontinued</th>
</tr>
<tr>
<th id="Th4" runat="server">SupplierID</th>
<th id="Th5" runat="server">CategoryID</th>
<th id="Th6" runat="server">QuantityPerUnit</th>
<th id="Th7" runat="server">UnitPrice</th>
<th id="Th8" runat="server">UnitsInStock</th>
<th id="Th9" runat="server">UnitsOnOrder</th>
<th id="Th10" runat="server">ReorderLevel</th>
</tr>
<tr ID="itemPlaceholder" runat="server">
</tr>
</table>
</LayoutTemplate>
<AlternatingItemTemplate>
<tr class="alternate">
<td rowspan="2">
<asp:Label ID="ProductIDLabel"
runat="server"
Text='<%# Eval("ProductID") %>' />
</td>
<td colspan="7">
<asp:Label ID="ProductNameLabel"
runat="server"
Text='<%# Eval("ProductName") %>' />
</td>
<td rowspan="2">
<asp:CheckBox ID="DiscontinuedCheckBox"
runat="server"
Checked='<%# Eval("Discontinued") %>'
Enabled="false" />
</td>
</tr>
<tr class="alternate">
<td>
<asp:Label ID="SupplierIDLabel"
runat="server"
Text='<%# Eval("SupplierID") %>' />
</td>
<td>
<asp:Label ID="CategoryIDLabel"
runat="server"
Text='<%# Eval("CategoryID") %>' />
</td>
<td>
<asp:Label ID="QuantityPerUnitLabel"
runat="server"
Text='<%# Eval("QuantityPerUnit") %>' />
</td>
<td>
<asp:Label ID="UnitPriceLabel"
runat="server"
Text='<%# Eval("UnitPrice") %>' />
</td>
<td>
<asp:Label ID="UnitsInStockLabel"
runat="server"
Text='<%# Eval("UnitsInStock") %>' />
</td>
<td>
<asp:Label ID="UnitsOnOrderLabel"
runat="server"
Text='<%# Eval("UnitsOnOrder") %>' />
</td>
<td>
<asp:Label ID="ReorderLevelLabel"
runat="server"
Text='<%# Eval("ReorderLevel") %>' />
</td>
</tr>
</AlternatingItemTemplate>
<ItemTemplate>
<tr>
<td rowspan="2">
<asp:Label ID="ProductIDLabel"
runat="server"
Text='<%# Eval("ProductID") %>' />
</td>
<td colspan="7">
<asp:Label ID="ProductNameLabel"
runat="server"
Text='<%# Eval("ProductName") %>' />
</td>
<td rowspan="2">
<asp:CheckBox ID="DiscontinuedCheckBox"
runat="server"
Checked='<%# Eval("Discontinued") %>'
Enabled="false" />
</td>
</tr>
<tr>
<td>
<asp:Label ID="Label1"
runat="server"
Text='<%# Eval("SupplierID") %>' />
</td>
<td>
<asp:Label ID="Label2"
runat="server"
Text='<%# Eval("CategoryID") %>' />
</td>
<td>
<asp:Label ID="Label3"
runat="server"
Text='<%# Eval("QuantityPerUnit") %>' />
</td>
<td>
<asp:Label ID="Label4"
runat="server"
Text='<%# Eval("UnitPrice") %>' />
</td>
<td>
<asp:Label ID="Label5"
runat="server"
Text='<%# Eval("UnitsInStock") %>' />
</td>
<td>
<asp:Label ID="Label6"
runat="server"
Text='<%# Eval("UnitsOnOrder") %>' />
</td>
<td>
<asp:Label ID="Label7" runat="server"
Text='<%# Eval("ReorderLevel") %>' />
</td>
<tr>
</ItemTemplate>
</asp:ListView>
<asp:DataPager ID="DataPager1"
runat="server"
PageSize="7"
PagedControlID="ListView1">
<Fields>
<asp:NextPreviousPagerField
ButtonType="Link"
ShowFirstPageButton="True"
ShowNextPageButton="False"
ShowPreviousPageButton="False"
FirstPageText="<<最初" />
<asp:NumericPagerField
ButtonCount="5"
PreviousPageText="<前の 5 ページ"
NextPageText="次の 5 ページ>"/>
<asp:NextPreviousPagerField
ButtonType="Link"
ShowLastPageButton="True"
ShowNextPageButton="False"
ShowPreviousPageButton="False"
LastPageText="最後>>" />
</Fields>
</asp:DataPager>
</div>
</form>
</body>
</html>
先の記事の方法と今回の記事の方法とで、どちらが簡単かと言えば、正直言ってどっちもどっちって感じです。