【プログラミング】ASP.NETのObjectDataSource活用(1)―ADO.NETで作る(1)

「新館」の開発は試行錯誤の連続であります。そのため、よくわからないままにASP.NETの機能を使い、コードを書いている部分もあるのですが(危ない、危ない)、もっとよい機能が別にあるのに、知っている機能の範囲内だけで済ませてしまうこともあります。

私の場合、これがSqlDataSourceでした。SqlDataSourceはデータベースへの接続に便利なコントロールで、GridViewなどのデータコントロールと組み合わせると非常に便利なのですが、柔軟性に欠けるところがあります。検索条件を任意に変えるなど複雑なことを無理にさせようとすると、それなりにトリッキーなプログラミングが要求されます。

トリッキーなので、コードにも無理矢理感が出てきますし、動作も安定していないような気がします。そこで、ObjectDataSourceという汎用のあるコントロールの存在を今さら知ったということで、それを使って置き換えてみようというのが、これからの連載になります。

最初に、概要を書いておきましょう。ObjectDataSourceとはデータソースコントロールのひとつですが、データソースをほぼ自由にできるのが特徴です。SqlDataSourceの場合、データソースはSQL Serverなどのデータベースに限定されますが、ObjectDataSourceでは適当なテキストファイル、ファイルシステム、要はデータアクセスのためのコードを書いてやれば何でもデータソースになります。もちろん、データベースをデータソースにしてもよいわけで、これが今回の連載の主眼です。

「新館」内のアルバム機能は、データベースへ発行するSELECT命令の内容(WHERE句による絞り込み、ORDER BY句による並び替えなど)を動的に変化させているのですが、これをSqlDataSourceのSelectCommandを随時書き換えるという方法でやっているため、「いつ書き換えるか」ということが重要になってきます。とりあえず、「レンダリング直前」ということでPageオブジェクトのPrerenderイベント内で行っていました。

実際には、いつデータベースにSELECT命令が発行されるかわからなかったので、このタイミングでデータバインドをやり直す、という無茶をやっていたようです。案の定、うまく動かないところも出てきましたので、思い切ってObjectDataSourceに移行して、データベースアクセスをスッキリ切り離そう、と思った次第です。

さて、いろいろ調べてみましてみましたら、ObjectDataSourceを使ってデータアクセスする基本は、こんな感じになるようです。

  1. データアクセスコンポーネントを作る。
  2. データコントロールを配置する。
  3. ObjectDataSourceを作成して各種プロパティを設定する。
  4. データコントロールのDataSourceにObjectDataSourceを設定する。

ここは、ひとつずつ理解しながら進めたいものです。ということで最初は、もっともシンプルなものを作ってみることにしました。ADO.NETというデータベースアクセスのためのしくみを用いた基本的なものになります。

まず、データアクセスクラスは、こんな感じになりました。Selectメソッドしか作っていません。さらに、単純化するために絞り込み条件を1つ、並び替え条件を1つだけ受け取るようにしています。このメソッドは、絞り込み条件として写真カテゴリを表す整数値を受け取って、0であれば省略と見なして全件選択し、そうでなければWHERE句によって絞り込みを行います。また、並び替え条件として並び替え方向を表す整数値を受け取って、0であれば昇順、1であれば降順でORDER BY句によってtaken_datetimeフィールドでの並び換えを行います(もちろん、並び換えのフィールドを変えたり、引数を追加して複雑な条件指定もできます)。

結果は、DbDataReaderオブジェクトとして返されます。メソッドにDataObjectMethod属性を指定しておくと、ウィザードが認識してくれますのでObjectDataSourceの設定が楽になります。

usingは省略…。

public class flickrphoto
{
    コンストラクタは省略…。

    [DataObjectMethod(DataObjectMethodType.Select)]
    public DbDataReader getPhotoDataReader(int category, int direction)
    {
        ConnectionStringSettings setting =
          ConfigurationManager.ConnectionStrings["ConnectionString"];
        DbProviderFactory factory =
          DbProviderFactories.GetFactory(setting.ProviderName);
        DbConnection db = factory.CreateConnection();
        db.ConnectionString = setting.ConnectionString;
        DbCommand command = factory.CreateCommand();
        command.Connection = db;
        string where_str = "";
        if(category != 0)
        {
            where_str = " WHERE category=@category";
            DbParameter param = factory.CreateParameter();
            param.ParameterName = "@category";
            param.Value = category;
            command.Parameters.Add(param);
        }
        order_str = " ORDER BY taken_datetime ";
        if(direction == 0 )
            order_str += "ASC";
        }
        else
        {
            order_str += "DESC";
        }
        command.CommandText =
          "SELECT * FROM FlickrPhoto" + where_str + order_str;
        db.Open();
        return command.ExecuteReader(CommandBehavior.CloseConnection);
    }
}

さらに、ObjectDataSourceそのものは、こんな感じです。TypeName属性でクラスを指定し、SelectMethod属性にメソッド名を、SelectParametersコレクションにパラメータを指定する、という感じになっています。SelectParameter要素は、メソッドの引数の分だけ必要になりますので、メソッドの定義を行ったら、ウィザードで自動的に生成させるのが簡単です。

<asp:ObjectDataSource ID="ods" runat="server"
    SelectMethod="getPhotoDataReader" TypeName="flickrphoto">
    <SelectParameters>
        <asp:Parameter Name="category" Type="Int32" DefaultValue="0" />
        <asp:Parameter Name="direction" Type="Int32" DefaultValue="0" />
    </SelectParameters>
</asp:ObjectDataSource>

これで、たとえばGridViewのデータソースにこのObjectDataSourceを指定してやれば、テーブルの内容がグリッド表示されずはずです。絞り込みを行いたければ、ObjectDataSourceのSelectParameters要素に対して、値の書き換えを行います。

    int category = 4;   // たとえばの値
    ………
    ods.SelectParameters["category"].DefaultValue = category.ToString();

しかし、これでは十分な機能を提供しているとはいえません。たとえば、GridViewなどのデータコントロールにはページングの機能があります。しかし、この方法ではまだページングに対応できません。ObjectDataSourceのEnablePagingプロパティをTrueにした上で、SelectCountMethodプロパティにレコード数取得のためのメソッドを指定し、startRowIndexParameterName, maximumRowsParameterNameの両プロパティに設定されているパラメータを用意して、メソッドもそれに合わせて書き換えなければなりません。

一言で書くとこれだけなのですが、実際にやってみると大変です。次回は、ページングに対応するための機能を組み込むための考え方について書きましょう。

コメント