ASP.NET Web ページの概要 - データベース データの更新

Tom FitzMacken

このチュートリアルでは、ASP.NET Web ページ (Razor) を使用するときに、既存のデータベース エントリを更新 (変更) する方法について説明します。 ここでは、ASP.NET Web ページを使用したフォームの使用によるデータ入力までのシリーズを完了していることを前提としています。

ここでは、次の内容について学習します。

  • WebGrid ヘルパーで個々のレコードを選択する方法。
  • データベースから 1 つのレコードを読み取る方法。
  • データベース レコードの値を使用してフォームを事前に読み込む方法。
  • データベース内の既存のレコードを更新する方法。
  • ページの情報を表示せずに格納する方法。
  • 非表示フィールドを使用して情報を格納する方法。

対象機能またはテクノロジ:

  • WebGrid ヘルパー。
  • SQL Update コマンド。
  • Database.Execute メソッド。
  • 非表示フィールド (<input type="hidden">)。

作成するアプリケーション:

前のチュートリアルでは、データベースにレコードを追加する方法を学習しました。 ここでは、編集用にレコードを表示する方法について説明します。 [ムービー] ページで、各ムービーの横に [編集] リンクが表示されるように、WebGrid ヘルパーを更新します。

WebGrid display including an 'Edit' link for each movie

[編集] リンクをクリックすると、ムービー情報が既にフォームに入力されている別のページに移動します。

Edit Movie page showing movie to be edited

任意の値を変更できます。 変更内容を送信すると、ページ内のコードによってデータベースが更新され、ムービーの一覧に戻ります。

このプロセスのこの部分は、前のチュートリアルで作成した AddMovie.cshtml ページとほぼ同じように動作するため、このチュートリアルの内容の大半は見慣れているでしょう。

個々のムービーを編集する方法を実装するには、いくつかの方法があります。 ここに示されている手法は、実装が簡単でわかりやすいことが理由で選ばれています。

まず、[ムービー] ページを更新して、各ムービーの一覧に [編集] リンクも含まれるようにします。

Movies.cshtml ファイルを開きます。

ページの本文で、列を追加して WebGrid マークアップを変更します。 変更されたマークアップを次に示します。

@grid.GetHtml(
    tableStyle: "grid",
    headerStyle: "head",
    alternatingRowStyle: "alt",
    columns: grid.Columns(
        grid.Column(format: @<a href="~/EditMovie?id=@item.ID">Edit</a>),
        grid.Column("Title"),
        grid.Column("Genre"),
        grid.Column("Year")
    )
)

新しい列は次のとおりです。

grid.Column(format: @<a href="~/EditMovie?id=@item.ID)">Edit</a>)

この列のポイントは、テキストに "編集" と表示されるリンク (<a> 要素) を表示することです。 次の目標は、ページの実行時に、ムービーごとに id 値が異なる次のようなリンクを作成することです。

http://localhost:43097/EditMovie?id=7

このリンクは EditMovie という名前のページを呼び出し、そのページに ?id=7 クエリ文字列を渡します。

新しい列の構文は少し複雑に見えるかもしれませんが、複数の要素をまとめているためにそう見えるだけです。 個々の要素は簡単です。 <a> 要素だけに注目すると、次のマークアップがあることがわかります。

<a href="~/EditMovie?id=@item.ID)">Edit</a>

グリッドの動作に関する背景情報: グリッドには、データベース レコードごとに 1 行が表示され、データベース レコード内の各フィールドの列が表示されます。 各グリッド行が構築される間に、item オブジェクトにその行のデータベース レコード (項目) が格納されます。 この配置により、コードでその行のデータを取得する方法が提供されます。 これが、ここに示されているものです。式 item.ID は、現在のデータベース項目の ID 値を取得します。 item.Titleitem.Genre、または item.Year を使用して、任意のデータベース値 (タイトル、ジャンル、または年) を同じ方法で取得できます。

"~/EditMovie?id=@item.ID は、ターゲット URL (~/EditMovie?id=) のハードコーディングされた部分と、この動的に派生した ID を結合します。 (前のチュートリアルで ~ 演算子を確認しました。これは、現在の Web サイトのルートを表す ASP.NET 演算子です)。

その結果、列のマークアップのこの部分では、実行時に次のようなマークアップが生成されます。

href="/EditMovie?id=2"

当然ながら、id の実際の値は、行ごとに異なります。

グリッド列のカスタム表示の作成

次は、グリッド列に戻ります。 最初にグリッドに表示されていた 3 列には、データ値 (タイトル、ジャンル、年) のみが表示されていました。 この表示は、データベース列の名前 (grid.Column("Title") など) を渡すことで指定します。

この新しい [編集] リンク列はこれとは異なります。 列名を指定する代わりに、format パラメータを渡します。 このパラメータを使用すると、WebGrid ヘルパーが item 値と共にレンダリングするマークアップを定義して、列データを太字、緑色などお好みの書式で表示できます。 たとえば、タイトルを太字にしたい場合は、次の例のような列を作成できます。

grid.Column(format:@<strong>@item.Title</strong>)

(format プロパティに示されるさまざまな @ 文字は、マークアップとコード値の間の遷移をマークします)。

format プロパティについて理解したら、新しい [編集] リンク列のまとめ方を理解しやすくなります。

grid.Column(format: @<a href="~/EditMovie?id=@item.ID">Edit</a>),

この列は、リンクをレンダリングするマークアップのみで構成され、これに加えて、行のデータベース レコードから抽出された情報 (ID) が含まれます。

ヒント

メソッドの名前付きパラメータと位置指定パラメータ

メソッドを呼び出して複数のパラメータを渡す多くの場合、それらのパラメータ値は単にコンマで区切って列挙します。 いくつかの例を次に示します。

db.Execute(insertCommand, title, genre, year)

Validation.RequireField("title", "You must enter a title")

このコードを初めて挙げたときは、この問題に言及しませんでしたが、いずれの場合も、パラメータを特定の順序 (つまり、そのメソッドでパラメータが定義される順序) でメソッドに渡します。 Validation.RequireFieldsdb.Execute に対して渡す値の順序が混乱すると、ページの実行時にエラー メッセージが表示されるか、少なくともやや奇妙な結果が返されます。 パラメータを渡す順序を知っている必要があるのは明らかです。 (WebMatrix では、IntelliSense がパラメータの名前、型、順序を把握するのに役立ちます)。

値を順番に渡す代わりに、名前付きパラメータを使用できます。 (パラメーターを順番に渡すことは、位置指定パラメータの使用と呼ばれます)。名前付きパラメータの場合、値を渡すときにパラメータの名前を明示的に含めます。 これらのチュートリアルでは、既に何度も名前付きパラメータを使用しています。 次に例を示します。

var grid = new WebGrid(source: selectedData, defaultSort: "Genre", rowsPerPage:3)

and

@grid.GetHtml(
    tableStyle: "grid",
    headerStyle: "head",
    alternatingRowStyle: "alt",
    columns: grid.Columns(
       grid.Column("Title"),
       grid.Column("Genre"),
       grid.Column("Year")
    )
)

名前付きパラメータは、特にメソッドが多くのパラメータを受け取る場合、いくつかの状況で便利です。 その 1 つは、1 つまたは 2 つのパラメータのみを渡すものの、渡す値がパラメータ リストの最初の位置に含まれているわけではない場合です。 もう 1 つの状況は、最も意味のある順序でパラメータを渡すことで、コードをより読みやすくしたい場合です。

名前付きパラメータを使用するには、パラメータの名前を知っている必要があるのは明らかです。 現在 WebMatrix IntelliSense で名前を表示できますが、あらかじめ入力しておくことはできません。

編集ページの作成

これで、EditMovie ページを作成できるようになりました。 ユーザーが [編集] リンクをクリックすると、このページが表示される結果になります。

EditMovie.cshtml という名前のページを作成し、ファイル内の内容を次のマークアップに置き換えます。

<!DOCTYPE html>
<html>
  <head>
   <meta charset="utf-8" />
   <title>Edit a Movie</title>
    <style>
      .validation-summary-errors{
        border:2px dashed red;
        color:red;
        font-weight:bold;
        margin:12px;
      }
    </style>
  </head>
  <body>
    <h1>Edit a Movie</h1>
    @Html.ValidationSummary()
    <form method="post">
      <fieldset>
        <legend>Movie Information</legend>

        <p><label for="title">Title:</label>
           <input type="text" name="title" value="@title" /></p>

        <p><label for="genre">Genre:</label>
           <input type="text" name="genre" value="@genre" /></p>

        <p><label for="year">Year:</label>
           <input type="text" name="year" value="@year" /></p>

        <input type="hidden" name="movieid" value="@movieId" />

        <p><input type="submit" name="buttonSubmit" value="Submit Changes" /></p>
      </fieldset>
    </form>
  </body>
</html>

このマークアップとコードは、AddMovie ページにあるものに似ています。 送信ボタンのテキストには小さな違いがあります。 AddMovie ページと同様に、検証エラーがある場合に表示される Html.ValidationSummary 呼び出しがあります。 ここでは、エラーは検証の概要に表示されるため、Validation.Message への呼び出しは省略します。 前のチュートリアルで説明したように、検証の概要と個々のエラー メッセージをさまざまな組み合わせで使用できます。

もう一度、<form>method 要素の属性が、post に設定されていることに注目してください。 AddMovie.cshtml ページと同様に、このページはデータベースに変更を加えます。 したがって、このフォームは POST 操作を実行するはずです。 (GET 操作と POST 操作の違いの詳細については、HTML フォームに関するチュートリアルの GET、POST、HTTP 動詞の安全性サイドバーを参照してください)。

前のチュートリアルで説明したように、テキスト ボックスの value 属性は、事前に読み込むために Razor コードで設定されます。 ただし、今回はそのタスクに対し、Request.Form["title"] の代わりに、titlegenre などの変数を使用します。

<input type="text" name="title" value="@title" />

以前と同様に、このマークアップでは、テキスト ボックスの値にムービー値が事前に読み込まれます。 今回 Request オブジェクトを使用する代わりに変数を使用するのが便利な理由が、すぐにわかります。

このページには、<input type="hidden"> 要素もあります。 この要素は、ムービー ID をページに表示せずに格納します。 ID は、最初はクエリ文字列値 (?id=7 または URL 内の同様の値) を使用してページに渡されます。 ID 値を非表示フィールドに配置することで、ページが呼び出された元の URL にアクセスできなくなっても、フォームが送信されたときに使用できることを確認できます。

AddMovie ページとは異なり、EditMovie ページのコードには、2 つの異なる関数があります。 1 つ目の関数は、ページが初めて表示されるとき (およびそれ以降のみ) に、コードがクエリ文字列からムービー ID を取得するものです。 その後、コードは ID を使用してデータベースから対応するムービーを読み取り、テキスト ボックスに表示 (事前読み込み) します。

2 つ目の関数は、ユーザーが [変更の送信] ボタンをクリックすると、コードがテキスト ボックスの値を読み取ってそれらを検証する必要があるものです。 このコードで、データベース項目を新しい値で更新する必要もあります。 この手法は、AddMovie で見たレコードの追加に似ています。

1 つのムービーを読み取るコードの追加

この最初の機能を実行するには、次のコードをページの上部に追加します。

@{
    var title = "";
    var genre = "";
    var year = "";
    var movieId = "";

    if(!IsPost){
        if(!Request.QueryString["ID"].IsEmpty()){
            movieId = Request.QueryString["ID"];
            var db = Database.Open("WebPagesMovies");
            var dbCommand = "SELECT * FROM Movies WHERE ID = @0";
            var row = db.QuerySingle(dbCommand, movieId);
            title = row.Title;
            genre = row.Genre;
            year = row.Year;
        }
        else{
            Validation.AddFormError("No movie was selected.");
        }
    }
}

このコードのほとんどは、if(!IsPost) で開始するブロック内にあります。 ! 演算子は "not" を意味するため、この式は、この要求が送信の投稿でないかどうかを判定するためのものです。これは、この要求が、このページが実行されてから初めての要求でないかどうかを間接的に表現したものです。 前述のように、このコードは、ページの初回実行時にのみ実行する必要があります。 コードを if(!IsPost) で囲んでいない場合は、このコードは、ページが呼び出されるたびに実行されます。初回でもボタンのクリックに応答する場合でも同じです。

今回は、コードにこの else ブロックが含まれていることに注意してください。 if ブロックを紹介したときに言及したように、テスト中の条件に当てはまらないときに、代わりのコードを実行する必要がある場合があります。 これがその場合です。 条件が満たされた場合 (つまり、ページに渡された ID が問題なければ)、データベースから行を読み取ります。 ただし、条件が満たされない場合は、else ブロックが実行され、コードによってエラー メッセージが設定されます。

ページに渡される値の検証

このコードは、ページに渡される ID を取得するために Request.QueryString["id"] を使用します。 このコードでは、ID に対して値が実際に渡されたことを確認します。 値が渡されなかった場合、コードは検証エラーを設定します。

このコードは、情報を検証する別の方法を示しています。 前のチュートリアルでは、Validation ヘルパーを使用しました。 検証するフィールドを登録し、ASP.NET は、Html.ValidationMessageHtml.ValidationSummary を使用することで自動的に検証を行い、エラーを表示しました。 ただし、この場合、実際にはユーザー入力を検証していません。 代わりに、他の場所からページに渡された値を検証しています。 Validation ヘルパーが、開発者の代わりにこれを実行することはありません。

したがって、この値は、if(!Request.QueryString["ID"].IsEmpty()) を使用してテストすることで、自分で確認します。 問題が発生した場合は、Validation ヘルパーで行ったのと同様に、Html.ValidationSummary を使用してエラーを表示できます。 これを行うには、Validation.AddFormError を呼び出して、表示するメッセージをこれに渡します。 Validation.AddFormError は、既に使い慣れている検証システムと結び付くカスタム メッセージを定義できる組み込みメソッドです。 (このチュートリアルの後半では、この検証プロセスを少し堅牢にする方法について説明します)。

ムービーの ID があることを確認した後、コードはデータベースを読み取り、1 つのデータベース項目のみを検索します。 (データベースを開き、SQL ステートメントを定義し、ステートメントを実行する、データベース操作の一般的なパターンがあることにお気付きでしょう)。今回は、SQL Select ステートメントに WHERE ID = @0 を含めます。 ID は一意であるため、返せるレコードは 1 つだけです。

クエリは、ムービーの一覧で使用した db.Query でなく、db.QuerySingle を使用して実行され、コードによって結果がrow 変数に格納されます。 名前 row は任意です。この変数にはどのような名前も付けられます。 その後、上部で初期化された変数にムービーの詳細が入力され、これらの値がテキスト ボックスに表示されます。

ここまでの [編集] ページのテスト

ページをテストする場合は、[ムービー] ページを今すぐ実行し、ムービーの横にある [編集] リンクをクリックします。 選択したムービーの詳細が入力された EditMovie ページが表示されます。

Screenshot shows the Edit Movie page showing movie to be edited.

ページの URL に、?id=10 のような部分、または別の番号が含まれていることに注目してください。 ここまでで、[ムービー] ページの [編集] リンクが機能しており、ページがクエリ文字列から ID を読み取り、1 つのムービー レコードを取得するためのデータベース クエリが機能していることをテストしました。

ムービーの情報は変更できますが、[変更の送信] をクリックしても何も起こりません。

ユーザーの変更内容でムービーを更新するコードの追加

EditMovie.cshtml ファイルで、2 番目の関数を実装する (変更を保存する) には、@ ブロックの閉じかっこの内側に、次のコードを追加します。 (コードを配置する場所がわからない場合は、このチュートリアルの最後に表示される EditMovie ページの全コードを確認できます)。

if(IsPost){
    Validation.RequireField("title", "You must enter a title");
    Validation.RequireField("genre", "Genre is required");
    Validation.RequireField("year", "You haven't entered a year");
    Validation.RequireField("movieid", "No movie ID was submitted!");

    title = Request.Form["title"];
    genre = Request.Form["genre"];
    year = Request.Form["year"];
    movieId = Request.Form["movieId"];

    if(Validation.IsValid()){
        var db = Database.Open("WebPagesMovies");
        var updateCommand = "UPDATE Movies SET Title=@0, Genre=@1, Year=@2 WHERE Id=@3";
        db.Execute(updateCommand, title, genre, year, movieId);
        Response.Redirect("~/Movies");
   }
}

ここでも、このマークアップとコードは AddMovie のコードに似ています。 このコードは if(IsPost) ブロック内にあるため、ユーザーが [変更の送信] ボタンをクリックしたときにのみ実行されます。つまり、フォームが投稿されるときが、コードの唯一の実行機会です。 ここでは、if(IsPost && Validation.IsValid()) のようなテストを使用しません。これは AND を使用して両方のテストを組み合わせたものでしたが、そうしません。 このページでは、まず、フォームの送信 (if(IsPost)) があるかどうかを判定し、その後にのみ、検証のためにフィールドを登録します。 その後、検証結果 (if(Validation.IsValid()) をテストできます。 フローは AddMovie.cshtml ページとは若干異なりますが、効果は同じです。

Request.Form["title"] と他の <input> 要素の同様のコードを使用して、テキスト ボックスの値を取得します。 今回は、このコードは、隠しフィールド (<input type="hidden">) からムービー ID を取得します。 このコードは、ページの初回実行時にクエリ文字列から ID を取得しました。 非表示フィールドから値を取得して、表示された元のムービーの ID を取得していることを確認します。これは、クエリ文字列がそれ以降何らかの形で変更されている場合に備えます。

AddMovie コードとこのコードとの本当に重要な違いは、このコードでは、Insert Into ステートメントでなく、SQL Update ステートメントを使用する点にあります。 次の例は、SQL Update ステートメントの構文を示しています。

UPDATE table SET col1="value", col2="value", col3="value" ... WHERE ID = value

任意の列を任意の順序で指定でき、Update 操作中にすべての列を更新する必要はありません。 (ID 自体を更新することはできません。これは、レコードを新しいレコードとして保存する結果になり、これは Update 操作に対して許可されないためです)。

Note

重要 ID を持つ Where 句は非常に重要です。これは、データベースが、更新対象のデータベース レコードを認識する方法であるためです。 Where 句を省略すると、データベースはデータベース内のすべてのレコードを更新します。 ほとんどの場合、これは悲惨な結果になります。

このコードでは、更新する値は、プレースホルダーを使用して SQL ステートメントに渡されます。 前の説明の繰り返しになりますが、セキュリティ上の理由から、プレースホルダーは、SQL ステートメントに値を渡すのみの目的で使用します。

コードが db.Execute を使用して Update ステートメントを実行すると、リスト ページにリダイレクトされ、そこで変更内容を確認できます。

ヒント

異なる SQL ステートメント、異なるメソッド

ここでは、異なる SQL ステートメントを実行するために、少し異なる方法を使用しています。 複数のレコードを返す可能性がある Select クエリを実行するには、Query メソッドを使用します。 データベース項目が 1 つだけ返されることがわかっている Select クエリを実行するには、QuerySingle メソッドを使用します。 変更を加えたがデータベース項目を返さないコマンドを実行するには、Execute メソッドを使用します。

QueryQuerySingle との違いで既に見たように、それぞれが異なる結果を返すので、それぞれに異なるメソッドを設ける必要があります。 (Execute メソッドは、実際には、コマンドの影響を受けたデータベース行数の値も返します。この値はここまで無視してきたものです)。

もちろん、Query メソッドは、データベース行を 1 つだけ返す場合があります。 ただし、ASP.NET は常に Query メソッドの結果をコレクションとして扱います。 メソッドから 1 行しか返されない場合でも、コレクションからその 1 行を抽出する必要があります。 したがって、1 行しか返されないことがわかっている状況では、QuerySingle を使用する方が少し便利です。

他にも、特定の種類のデータベース操作を実行する方法がいくつかあります。 データベース メソッドの一覧については、ASP.NET Web ページ API クイック リファレンスを参照してください。

ID 検証の堅牢性の向上

ページの初回実行時に、データベースからそのムービーを取得できるように、クエリ文字列からムービー ID を取得します。 ここまでに、実際に検索する値があることを確認し、これは次のコードを使用して行いました。

if(!IsPost){
    if(!Request.QueryString["ID"].IsEmpty()){
        // Etc.
    }
}

このコードを使用して、ユーザーが [ムービー] ページで最初にムービーを選択せずに EditMovies ページにアクセスすると、ユーザーにわかりやすいエラー メッセージがページに表示されることを確認しました。 (そうしない場合、ユーザーには、意味がわからず混乱させるだけのエラーが表示されます)。

ただし、この検証はあまり堅牢ではありません。 このページは、次のエラーで呼び出される場合もあります。

  • ID が数値ではありません。 たとえば、http://localhost:nnnnn/EditMovie?id=abc などの URL を使用してページが呼び出される可能性があります。
  • ID は数値ですが、存在しないムービー (たとえば http://localhost:nnnnn/EditMovie?id=100934) を参照します。

このような URL から発生するエラーを確認するには、[ムービー] ページを実行します。 編集するムービーを選択し、EditMovie ページの URL を、アルファベットの ID または存在しないムービーの ID を含む URL に変更します。

それでは、どうすればよいでしょうか。 最初の修正は、ID がページに渡されることを確認するだけでなく、ID が整数であるのを確認することです。 !IsPost テストのコードを次の例のように変更します。

if(!IsPost){
    if(!Request.QueryString["ID"].IsEmpty() && Request.QueryString["ID"].IsInt()) {
       // Etc.

&& (論理 AND) を使用してリンクされた IsEmpty テストに、2 つ目の条件を追加しました。

Request.QueryString["ID"].IsInt()

ASP.NET Web ページ プログラミングの概要」チュートリアルの内容で、AsBoolAsInt などのメソッドは、文字列を他のデータ型に変換することをご記憶でしょう。 IsInt メソッド (および IsBoolIsDateTime などの他のメソッド) も同様です。 ただし、これらは実際には変換を実行せずに、文字列が変換可能かどうかをテストするだけです。 したがって、ここでは基本的に、クエリ文字列の値を整数に変換できるかどうかを意味しています。

もう 1 つの潜在的な問題として、存在しないムービーを探すことがあります。 ムービーを取得するコードは、次のコードのようになります。

var row = db.QuerySingle(dbCommand, movieId);

実際のムービーに対応しない movieId 値を QuerySingle メソッドに渡すと、何も返されず、後続のステートメント (title=row.Title など) はエラーになります。

ここでも、簡単な修正方法があります。 db.QuerySingle メソッドが結果を返さない場合、row 変数は null になります。 したがって、row 変数から値を取得する前に、変数が null かどうかを確認できます。 次のコードは、row オブジェクトから値を取得するステートメントの周囲に if ブロックを追加します。

if(row != null) {
    title = row.Title;
    genre = row.Genre;
    year = row.Year;
}
else{
    Validation.AddFormError("No movie was found for that ID.");
}

これら 2 つの検証テストを追加することで、このページはより堅牢になります。 !IsPost 分岐のコード全体は、次の例のようになります。

if(!IsPost){
    if(!Request.QueryString["ID"].IsEmpty() && Request.QueryString["ID"].IsInt()) {
        movieId = Request.QueryString["ID"];
        var db = Database.Open("WebPagesMovies");
        var dbCommand = "SELECT * FROM Movies WHERE ID = @0";
        var row = db.QuerySingle(dbCommand, movieId);

        if(row != null) {
            title = row.Title;
            genre = row.Genre;
            year = row.Year;
        }
        else {
            Validation.AddFormError("No movie was found for that ID.");
        }
    }
    else {
        Validation.AddFormError("No movie was selected.");
    }
}

このタスクは、else ブロックが役立つよい使用例であることをもう一度言及しておきます。 テストに合格しない場合、else ブロックはエラー メッセージを設定します。

最後の役立つ詳細は、リンクを追加して [ムービー] ページに戻る方法です。 通常のイベント フローでは、ユーザーは [ムービー] ページから開始し、[編集] リンクをクリックします。 これにより、ムービーを編集してボタンをクリックできる EditMovie ページに移動します。 コードが変更内容を処理すると、[ムービー] ページにリダイレクトされます。

ただし、

  • ユーザーは、結果的に何も変更しないと決める場合があります。
  • ユーザーは、最初に [ムービー] ページの [編集] リンクをクリックせずに、このページに至る場合があります。

いずれの場合も、メインの一覧に簡単に戻れるようにするのが適しています。 これは簡単な修正で実行できます。マークアップの終了 </form> タグの直後に、次のマークアップを追加します。

<p><a href="~/Movies">Return to movie listing</a></p>

このマークアップでは、これまで各所で扱った <a> 要素と同じ構文が使用されます。 URL には、"web サイトのルート" を意味する ~ が含まれます。

ムービー更新プロセスのテスト

これでテストできるようになりました。 [ムービー] ページを実行し、ムービーの横にある [編集] をクリックします。 EditMovie ページが表示されたら、ムービーに変更を加え、[変更の送信] をクリックします。 ムービーの一覧が表示されたら、変更が表示されていることを確認します。

検証が機能していることを確認するには、別のムービーの [編集] をクリックします。 EditMovie ページに移動したら、[ジャンル] フィールド (または [年] フィールド、またはその両方) を消去して、変更内容を送信しようとしてみます。 予想したとおり、次のようなエラーが表示されます。

Edit Movie page showing validation errors

[ムービーの一覧に戻る] リンクをクリックして変更を破棄し、[ムービー] ページに戻ります。

次の予定

次のチュートリアルでは、ムービー レコードを削除する方法について説明します。

@{
    var db = Database.Open("WebPagesMovies") ;
    var selectCommand = "SELECT * FROM Movies";
    var searchTerm = "";

    if(!Request.QueryString["searchGenre"].IsEmpty() ) {
        selectCommand = "SELECT * FROM Movies WHERE Genre = @0";
        searchTerm = Request.QueryString["searchGenre"];
    }

    if(!Request.QueryString["searchTitle"].IsEmpty() ) {
        selectCommand = "SELECT * FROM Movies WHERE Title LIKE @0";
        searchTerm = "%" + Request.QueryString["searchTitle"] + "%";
    }

    var selectedData = db.Query(selectCommand, searchTerm);
    var grid = new WebGrid(source: selectedData, defaultSort: "Genre", rowsPerPage:3);
}

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>Movies</title>
        <style type="text/css">
          .grid { margin: 4px; border-collapse: collapse; width: 600px; }
          .grid th, .grid td { border: 1px solid #C0C0C0; padding: 5px; }
          .head { background-color: #E8E8E8; font-weight: bold; color: #FFF; }
          .alt { background-color: #E8E8E8; color: #000; }
        </style>
    </head>
    <body>
        <h1>Movies</h1>
          <form method="get">
              <div>
                <label for="searchGenre">Genre to look for:</label>
                <input type="text" name="searchGenre" value="@Request.QueryString["searchGenre"]" />
                <input type="Submit" value="Search Genre" /><br/>
                (Leave blank to list all movies.)<br/>
                </div>

              <div>
                  <label for="SearchTitle">Movie title contains the following:</label>
                  <input type="text" name="searchTitle" value="@Request.QueryString["searchTitle"]" />
                  <input type="Submit" value="Search Title" /><br/>
                </div>
            </form>

        <div>
             @grid.GetHtml(
                tableStyle: "grid",
                headerStyle: "head",
                alternatingRowStyle: "alt",
                columns: grid.Columns(
                    grid.Column(format: @<a href="~/EditMovie?id=@item.ID">Edit</a>),
                    grid.Column("Title"),
                    grid.Column("Genre"),
                    grid.Column("Year")
                )
            )
        </div>
    <p>
        <a href="~/AddMovie">Add a movie</a>
    </p>
    </body>
</html>

ムービーの編集ページの完全なページ一覧

@{
    var title = "";
    var genre = "";
    var year = "";
    var movieId = "";

    if(!IsPost){
        if(!Request.QueryString["ID"].IsEmpty() && Request.QueryString["ID"].IsInt()) {
            movieId = Request.QueryString["ID"];
            var db = Database.Open("WebPagesMovies");
            var dbCommand = "SELECT * FROM Movies WHERE ID = @0";
            var row = db.QuerySingle(dbCommand, movieId);

            if(row != null) {
                title = row.Title;
                genre = row.Genre;
                year = row.Year;
            }
            else{
                Validation.AddFormError("No movie was selected.");
            }
        }
        else{
            Validation.AddFormError("No movie was selected.");
        }
    }

    if(IsPost){
        Validation.RequireField("title", "You must enter a title");
        Validation.RequireField("genre", "Genre is required");
        Validation.RequireField("year", "You haven't entered a year");
        Validation.RequireField("movieid", "No movie ID was submitted!");

        title = Request.Form["title"];
        genre = Request.Form["genre"];
        year = Request.Form["year"];
        movieId = Request.Form["movieId"];

        if(Validation.IsValid()){
            var db = Database.Open("WebPagesMovies");
            var updateCommand = "UPDATE Movies SET Title=@0, Genre=@1, Year=@2 WHERE Id=@3";
            db.Execute(updateCommand, title, genre, year, movieId);
            Response.Redirect("~/Movies");
        }
    }
}

<!DOCTYPE html>
<html>
  <head>
   <meta charset="utf-8" />
   <title>Edit a Movie</title>
    <style>
      .validation-summary-errors{
        border:2px dashed red;
        color:red;
        font-weight:bold;
        margin:12px;
      }
    </style>
  </head>
  <body>
    <h1>Edit a Movie</h1>
      @Html.ValidationSummary()
      <form method="post">
      <fieldset>
        <legend>Movie Information</legend>

        <p><label for="title">Title:</label>
           <input type="text" name="title" value="@title" /></p>

        <p><label for="genre">Genre:</label>
           <input type="text" name="genre" value="@genre" /></p>

        <p><label for="year">Year:</label>
           <input type="text" name="year" value="@year" /></p>

        <input type="hidden" name="movieid" value="@movieId" />

        <p><input type="submit" name="buttonSubmit" value="Submit Changes" /></p>
      </fieldset>
    </form>
    <p><a href="~/Movies">Return to movie listing</a></p>
  </body>
</html>

その他のリソース