連載:VS 2005でいってみようDBプログラミング

第10回 実践アプリケーションで一歩踏み込むASP.NET 2.0の世界

山田 祥寛(http://www.wings.msn.to/
2006/11/29
Page1 Page2 Page3 Page4

[3]SqlDataSourceコントロールのプロパティ情報を設定する

 次に、FormViewコントロールの各テンプレートから利用するSqlDataSourceコントロールのプロパティ情報を設定します。

プロパティ 設定値
ConnectionString myDb(第2回を参照)
SelectQuery SELECT id, nam, subject, REPLACE(body, CHAR(13) + CHAR(10), '<br />') AS body, passwd, deleted, parent, last_modified FROM Bbs WHERE (id = @id) AND (deleted = 0)
UpdateQuery INSERT INTO Bbs(nam, subject, body, passwd, deleted, parent, last_modified) VALUES (@nam, @subject, @body, @passwd, 0, @id, CURRENT_TIMESTAMP)
InsertQuery INSERT INTO [Bbs] ([nam], [subject], [body], [passwd], [deleted], [parent], [last_modified]) VALUES (@nam, @subject, @body, @passwd, 0, 0, CURRENT_TIMESTAMP)
DeleteQuery UPDATE Bbs SET deleted=1 WHERE id=@id AND passwd=@passwd
表8 SqlDataSourceコントロール上に設定されたSQL命令
XxxxxQueryプロパティはクエリビルダから設定できる。クエリビルダの設定方法については、第5回の内容を参照すること。

 XxxxxQueryプロパティには、それぞれ個別記事表示時(SelectQueryプロパティ)、返信記事の登録時(UpdateQueryプロパティ)、新規記事の登録時(InsertQueryプロパティ)、既存記事の削除時(DeleteQueryプロパティ)に使用するSQL命令を指定します。

 ここで注目していただきたいのは、UpdateQuery/DeleteQueryプロパティに必ずしもSQLのUPDATE/DELETE命令を指定しているわけではないという点です。

 UpdateQuery/DeleteQueryプロパティはそれぞれEditItemTemplate/ItemTemplateで更新/削除ボタン(CommandNameプロパティがUpdate/Deleteに設定されているボタン)がクリックされたタイミングで実行されるSQLを指定しているにすぎませんので、この例のように、UpdateQueryプロパティにINSERT命令を、DeleteQueryプロパティにUPDATE命令を記述しても構いません。

 ここでは、更新ボタン([投稿]ボタン)をクリック時に、元の参照記事を親記事とする子記事を新規作成し、削除ボタンをクリックするときに、(Bbsテーブルからデータを削除するのではなく)該当データのdeleted列(削除済み)に1をセットしているわけです。

 SelectQueryプロパティの指定にも注目です。body列のように改行文字が含まれているような列を表示したい場合には、このようにREPLACE関数で改行文字(CHAR(13) + CHAR(10))を<br>タグに置き換えるような処理をあらかじめ行っておく必要があります。

 また、SelectQueryプロパティの@idパラメータには、図9の要領でクエリ情報「id」から値を受け取れるようにパラメータ・ソースの登録を行っておきましょう。


図9 [コマンドおよびパラメータのエディタ]ダイアログ

 クエリ情報とは、ページのURLの末尾「?〜」以降に付加された「キー名=値」のペアのことをいいます*1。もともとクエリ(Query)とは「問い合わせ」という意味を持っていますが、クエリ情報もデータベースなどに対する「問い合わせのための短いキー情報」などをページ間で受け渡しするために利用されるのが一般的です。

*1 「キー名=値」のペアを「&」で連結することで、複数の値を受け渡しすることが可能です。

 例えば、本稿の例では、Bbs.aspxで動的に生成された「~/BbsShow.aspx?id=1」のようなURLを介して、BbsShow.aspxにアクセスしています。ここでクエリ情報を表すクエリ文字列は「id=1」であり、キー名が「id」、値が「1」ということになります。

[コラム]クエリ文字列

 クエリ文字列には以下のような制約がありますので、注意が必要です。
  • データのサイズに一定の制約がある
  • 「?」「&」「%」、空白、マルチバイト文字などは使用できない
  • データがアドレス欄に露出する
 使用しているサーバによって制限は異なりますが、その性質上、おおよそ数百バイト程度のサイズと思っておけばよいでしょう。また、制約文字を受け渡す必要がある場合には、Server.UrlEncodeメソッドで文字列をエンコード(変換)処理しておく必要があります。

 以上でSqlDataSourceコントロールの設定は完了です。あとは、FormViewコントロールのプロパティ値を表9のように設定することで、FormViewコントロールとSqlDataSourceコントロールとが関連付けられます。

プロパティ 概要 設定値
DataKeyNames データソースのキー・フィールド id
DataSourceID データソース・コントロールのID sds
EmptyDataText データが取得できない場合の表示テキスト 該当するデータが存在しません
表9 FormViewコントロールのプロパティ設定

 EmptyDataTextプロパティを設定しておくことで、(例えば)エンドユーザーが直接にid値を変更してBbsShow.aspxにアクセスし、かつ、該当のデータが存在しなかった場合などに、データが存在しないことを明示的にテキスト表示することができます。ちなみに、単純なテキストではなく、画像やリンクなどを含んだコンテンツを定義したい場合には、表5でも示したEmptyDataTemplateテンプレートを定義してください。

[4]データ操作の各タイミングでの処理を定義する

 以上でフォーム・デザイナ上の作業は完了です。次に、ページ上で発生する各イベントに応じた処理を記述します。

' フォームのLoadイベント・ハンドラ
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)

  ' クエリ情報idが空の場合、FormViewの表示モードを「新規登録」に変更
  If Request.QueryString("id") Is Nothing Or Request.QueryString("id") ="" Then
    fv.ChangeMode(FormViewMode.Insert)
  End If

End Sub

' SqlDataSourceコントロールのDeletingイベント・ハンドラ
Protected Sub sds_Deleting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.SqlDataSourceCommandEventArgs)

  ' 削除処理前に、削除用パスワードをパラメータ@passwdにセット
  Dim txtPasswd As TextBox = _
    DirectCast(fv.FindControl("txtPasswd"), TextBox)
  e.Command.Parameters("@passwd").Value = txtPasswd.Text

End Sub

' SqlDataSourceコントロールのDeletedイベント・ハンドラ
Protected Sub sds_Deleted(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.SqlDataSourceStatusEventArgs)

  ' 削除されたレコードがなかった場合、エラー・ダイアログを表示。
  ' 正常に削除処理が完了した場合、Bbs.aspxにリダイレクト
  If e.AffectedRows = 0 Then
    Page.ClientScript.RegisterStartupScript(Me.GetType(), _
      "err", "window.alert('パスワードが間違っています。')", True)
  Else
    Response.Redirect("Bbs.aspx")
  End If

End Sub


' FormViewコントロールのDataBoundイベント・ハンドラ
' FormViewコントロールへのデータバインド完了のタイミングで、
' テンプレート上のコントロールを初期化
Protected Sub fv_DataBound(ByVal sender As Object, ByVal e As System.EventArgs)

  Dim cok As HttpCookie = Request.Cookies("name")

  Select Case fv.CurrentMode

    ' 新規登録モードの場合、クッキー「name」の値を
    ' テキストボックスtxtNamにセット
    Case FormViewMode.Insert

      If cok IsNot Nothing Then
        Dim txtNam As TextBox = _
          DirectCast(fv.FindControl("txtNam"), TextBox)
        txtNam.Text = Request.Cookies("name").Value
      End If

    ' 編集モードの場合、クッキー「name」の値を
    ' テキストボックスtxtNamにセット
    ' また、件名(txtSubject)の先頭に「Re:」を付与、
    Case FormViewMode.Edit

      Dim txtSubject As TextBox = _
        DirectCast(fv.FindControl("txtSubject"), TextBox)
      Dim txtNam As TextBox = _
        DirectCast(fv.FindControl("txtNam"), TextBox)
      Dim txtBody As TextBox = _
        DirectCast(fv.FindControl("txtBody"), TextBox)
      Dim txtPasswd As TextBox = _
        DirectCast(fv.FindControl("txtPasswd"), TextBox)
      txtSubject.Text = "Re: " & txtSubject.Text
      txtBody.Text = ""
      txtPasswd.Text = ""

      If cok IsNot Nothing Then
        txtNam.Text = Request.Cookies("name").Value
      End If
  End Select

End Sub

' SqlDataSourceコントロールのUpdatedイベント・ハンドラ
' 更新([投稿])ボタンによる更新処理後にBbs.aspxにリダイレクト
Protected Sub sds_Updated(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.SqlDataSourceStatusEventArgs)
  Response.Redirect("Bbs.aspx")
End Sub


' SqlDataSourceコントロールのInsertedイベント・ハンドラ
' 挿入([投稿])ボタンによる挿入処理後にBbs.aspxにリダイレクト
Protected Sub sds_Inserted(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.SqlDataSourceStatusEventArgs)
  Response.Redirect("Bbs.aspx")
End Sub

' SqlDataSourceコントロールのInsertingイベント・ハンドラ
' 挿入([投稿])ボタンによる挿入処理前に入力された投稿者名を
' クッキーに保存
Protected Sub sds_Inserting(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.SqlDataSourceCommandEventArgs)
  Me.AddCookie(e.Command.Parameters("@nam").Value)
End Sub

' SqlDataSourceコントロールのUpdatingイベント・ハンドラ
' 更新([投稿])ボタンによる更新処理前に入力された投稿者名を
' クッキーに保存
Protected Sub sds_Updating(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.SqlDataSourceCommandEventArgs)
  Me.AddCookie(e.Command.Parameters("@nam").Value)
End Sub

' 指定された値(引数name)の値をクッキーnameにセット
Protected Sub AddCookie(ByVal name As String)
  Dim cok As New HttpCookie("name", name)
  cok.Expires = DateTime.Now.AddMonths(3)
  Response.AppendCookie(cok)
End Sub
リスト2 各テンプレートでの処理を記述したコード(BbsShow.aspx)

 やや複雑にも思われるかもしれませんが、1つ1つの処理自体はこれまでに紹介したデータベース処理の延長線にすぎません。本稿冒頭のアプリケーションの画面遷移図などを参考に、動作を1つ1つたどってみるとよいでしょう。

 ここで1つだけ注目していただきたいのは、クッキーによる情報維持の部分です。

 クッキーとは、クライアント側に保存される小さなテキスト・ファイルのことをいいます。セキュリティ的な理由から、通常、サーバはクライアント上のデータの読み込み/書き込みを行うことはできませんが、このクッキーだけは例外です。サーバがクライアントに対して、任意のテキストをファイルに保存しておくことができます。また、自分が保存したテキスト・ファイルは好きなときに参照することができますから、ページ間で情報を保持したいという場合、あるいは、本サンプルのように、後日のアクセスでかつて入力した情報を復帰したいというような場合には、このクッキーを利用すればよいというわけです。

 AddCookieメソッドを見ても分かるように、クッキーは比較的簡単なコードで利用できます。クッキーに関する情報を管理するのは、HttpCookieクラスの役割です。HttpCookieクラスのコンストラクタには、第1パラメータからクッキー名、クッキー値の順で指定します。HttpCookieクラスで利用可能な主なプロパティは以下のとおりです。

プロパティ 概要 設定値(例)
Name クッキー名 nam
Value クッキーの値 hoge
Expires 有効期限 DateTime.Now.AddMonths(2)
Domain クッキーの有効なドメイン wings.msn.to
Path クッキーの有効なパス /DbMagazine
HttpOnly HTTPクッキーを有効にするか*2 True
Secure クッキーを送信するのにSSL(Secure Sockets Layer)を必要とするか False
表10 HttpCookieクラスの主なプロパティ
*2 HTTPクッキーとはHTTP経由でのみアクセスが可能なクッキーのことをいいます。HTTPクッキーを利用することで、クロスサイト・スクリプティング脆弱性によるクッキー漏えいの危険性を軽減できます。ただし、Internet Explorer 6.0以降でのみ利用可能です。

 このうち、Expiresプロパティは(事実上)必須です。有効期限が設定されなかった場合、クッキーはブラウザを閉じたタイミングで削除されます。ここでは、DateTimeクラスのAddMonthsメソッドを使って、3カ月後の日付を指定していますが、そのほかにもAddDaysやAddHoursなどのメソッドを使って、日単位/時間単位の有効期限を設定することもできます。

 クライアント側に保存したクッキーを取得するのは、Request.Cookiesプロパティの役割です。Cookiesプロパティは戻り値として(クッキー値そのものではなく)HttpCookieオブジェクトを返します。クッキー値にアクセスするには、そのValueプロパティにアクセスする必要がある点に注意してください。

 以上、今回は掲示板アプリケーションの基本的な機能を組み立ててみました。次回は引き続き、このアプリケーションに対して、メール通知機能やキャッシュ機能、RSSフィードの出力など、付随的な機能を追加してみます。End of Article


 INDEX
  Visual Studio 2005でいってみようDBプログラミング
  第10回 実践アプリケーションで一歩踏み込むASP.NET 2.0の世界
    1.スレッド一覧画面を作成する(1)
    2.スレッド一覧画面を作成する(2)
    3.個別記事表示/返信/投稿画面を作成する(1)
  4.個別記事表示/返信/投稿画面を作成する(2)
 
インデックス・ページヘ  「Visual Studio 2005でいってみようDBプログラミング」


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 記事ランキング

本日 月間