BOOK Preview

Microsoft Visual Studio 2005による
Webアプリケーション構築技法

第10章 3階層型自動データバインド

マイクロソフトプレスの書籍紹介ページ
書籍情報(書籍目次)のページ
2006/05/23

Page1 Page2 Page3

10.3 ObjectDataSourceオブジェクトを用いた大量データのページング制御

 最後に、ObjectDataSourceオブジェクトを利用した大量データのページング制御方法について解説する。

 第2部「9.3.2 ページング」の項で解説したように、2階層型自動データバインドを用いたページング制御方式では、大量データのページング制御ができない。これは、ページ切り替えのつどデータベースから全件のデータを取り寄せてしまうため、性能に優れたアプリケーションとならないからである(図10-13の上側)。

 しかし、本章で解説したObjectDataSourceオブジェクトとGridViewコントロールを組み合わせた場合には、データアクセスコンポーネントがObjectDataSourceオブジェクトを介してインデックス情報を受け取れるようになっている。このため、データコンポーネントからSELECTクエリを発行する際に、現在表示するページ分だけのデータを取り寄せるようにすると、効率的なページングアプリケーションを作成することができる(図10-13の下側)。

図10-13 大量データのページング制御の問題点

 以下に実装方法を解説する。なお、ここでは830行のデータが含まれている、Northwindサンプルデータベース上のOrdersテーブルのデータをページング制御するケースを例にとって解説する。

10.3.1 データアクセスコンポーネント側の準備

 この機能を利用するためには、背後のデータアクセスコンポーネントが以下の2つのメソッドを持っている必要がある※3

※3 なお、これらのメソッドのメソッド名は自由に決めてよいが、引数は固定であり、変更できない。
  • データの総件数をint 値として返すメソッド
    • 例) public int GetNumberOfOrders( )
  • 特定ページ部分だけのデータを取得するデータ検索メソッド
    • 例)public OrdersDataSet.OrdersDataTable GetDataByIndex(int startRowIndex, intmaximumRows)

 これらのメソッドはテーブルアダプタ上に直接実装できないため、いずれもpartialクラス上に定義する。実装例を図10-14およびリスト10-3に示す※4

※4 このうち、全件の件数を数えるクエリについては単一集計値クエリであるため、テーブルアダプタの標準機能を用いて定義できそうに見える。しかし現在のVisual Web Developerの場合には、残念ながらこのように定義したメソッドをObjectDataSourceオブジェクトに接続することができない。このため、partialクラス上に明示的に定義する必要がある。
 
図10-14 データコンポーネント機能とpartialクラスによる拡張
 
C#の場合

using System;
using System.Data;
using System.Data.SqlClient;

namespace OrdersDataSetTableAdapters
{
  public partial class OrdersTableAdapter
  {
    public OrdersDataSet.OrdersDataTable GetDataByIndex(int startRowIndex,int maximumRows)
    {
      string query;
      if (startRowIndex == 0)
      {
        query = string.Format("SELECT TOP {0} * FROM Orders ORDER BY OrderID", maximumRows);
      }
      else
      {
        // 手前のstartRowIndex - 1 件を避けて、最大maximumRows 件を取り出す
        query = string.Format("SELECT TOP {0} * FROM Orders WHERE OrderID NOT IN (SELECT TOP {1} OrderID FROM Orders ORDER BY OrderID) ORDER BY OrderID",maximumRows, startRowIndex - 1);
      }
      SqlDataAdapter sqlda = new SqlDataAdapter(query, this.Connection);
      OrdersDataSet ods = new OrdersDataSet();
      sqlda.Fill(ods.Orders);
      return ods.Orders;
    }

    public int GetNumberOfOrders()
    {
      SqlCommand sqlcmd = new SqlCommand("SELECT COUNT(*) FROM Orders",this.Connection);
      this.Connection.Open();
      int rows = (int)sqlcmd.ExecuteScalar();
      this.Connection.Close();
      return rows;
    }
  }
}
VBの場合

Imports System.Data
Imports System.Data.SqlClient

Namespace OrdersDataSetTableAdapters

  Partial Public Class OrdersTableAdapter

    Public Function GetDataByIndex(ByVal startRowIndex As Integer, ByValmaximumRows As Integer) As OrdersDataSet.OrdersDataTable
      Dim query As String
      If startRowIndex = 0 Then
        query = String.Format("SELECT TOP {0} * FROM Orders ORDER BYOrderID", maximumRows)
      Else
        ' 手前のstartRowIndex - 1 件を避けて、最大maximumRows 件を取り出す
        query = String.Format("SELECT TOP {0} * FROM Orders WHERE OrderID NOT IN (SELECT TOP {1} OrderID FROM Orders ORDER BY OrderID) ORDER BY OrderID",maximumRows, startRowIndex - 1)
      End If
      Dim sqlda As SqlDataAdapter = New SqlDataAdapter(query,Me.Connection)
      Dim ods As New OrdersDataSet()
      sqlda.Fill(ods.Orders)
      Return ods.Orders
    End Function

    Public Function GetNumberOfOrders() As Integer
      Dim sqlcmd As SqlCommand = New SqlCommand("SELECT COUNT(*) FROM Orders", Me.Connection)
      Me.Connection.Open()
      Dim rows As Integer = CType(sqlcmd.ExecuteScalar(), Integer)
      Me.Connection.Close()
      Return rows
    End Function

  End Class

End Namespace
リスト10-3 partialクラスによるテーブルアダプタの拡張

10.3.2 ObjectDataSourceオブジェクトとの連結

 上記の実装が済んだら、これをObjectDataSourceオブジェクトに連結し、プロパティ類を設定する。なお、このプロパティ設定はウィザードベースでの作業ができないため、すべて手作業で行う必要がある。

  • EnablePaging = true (ページ情報をSELECT メソッドに引き渡す)
  • TypeName = テーブルアダプタのクラス名
  • SelectMethod = 当該ページ部分のみのデータを返すメソッド名
  • SelectCountMethod = データ総件数をint 値として取得するメソッド

 以上の作業により、大量データに対しても効率的なページング制御を行うことができる(図10-15)。

図10-15 ObjectDataSourceコントロールを利用した効率的なページング制御

10.3.3 より効率的な実装方法

 なお、前述のリスト10-3ではn〜m件目のデータを取り寄せる際に、NOT INクエリを利用している(図10-16)。この方法はSQL Server 2000でも利用できる汎用的なものだが、SQL Server 2005をデータベースとして利用する場合には、新規に搭載されたROW_NUMBER( )関数を利用するとより効率的な実装ができる。

図10-16 特定ページのデータを検索するクエリの記述方法

 このROW_NUMBER( )関数は、クエリの実行結果行セットに整数の連番を自動付与させる機能である※5。これによって連番を振っておき、これをWHERE句で絞り込むようにクエリを実装すると、効率的なデータ取得が可能になる(リスト10-4)。

※5 Oracleのrownum列に相当する機能である。

クエリ記述方法

// startRowIndex 〜 startRowIndex + maximumRows - 1 番目のレコードを取り出す
query = string.Format("SELECT TOP {0} * FROM Orders WHERE OrderID NOT IN (SELECT TOP {1} OrderID FROM Orders ORDER BY OrderID) ORDER BY OrderID", maximumRows,startRowIndex - 1);



query = string.Format("SELECT * FROM (SELECT *, OW_NUMBER() OVER (ORDER BY OrderID) rownum FROM [Order Details]) AS [Order Details] WHERE rownum BETWEEN {0} AND {1} ORDER BY OrderID", startRowIndex, startRowIndex + maximumRows - 1);
リスト10-4 n〜m件目のデータを取得するためのクエリの記述方法

10.3.4 3階層型自動データバインドのまとめ

 本章のキーポイントを整理すると、以下の通りとなる。

  • ObjectDataSourceオブジェクトとデータコンポーネント機能のテーブルアダプタクラスにより、高い開発生産性と高い柔軟性を両立させることができる。
    • これにより、2階層型自動データバインドでは記述することのできない可変型クエリなども利用することができるようになる。
  • ObjectDataSource コントロールを利用すれば、大量データのページング制御も可能になる。
 

 INDEX
  Microsoft Visual Studio 2005によるWebアプリケーション構築技法
  第10章 3階層型自動データバインド
    1. 10.1 2階層型自動データバインドの限界
    2. 10.2.3 特殊クエリの実装方法
  3. 10.3 ObjectDataSourceオブジェクトを用いた大量データのページング制御
 
インデックス・ページヘ  「BOOK Preview」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間