共用方式為


ASP.NET Web Pages 簡介 - 更新資料庫資料

Tom FitzMacken

本教學課程說明當您使用 ASP.NET Web Pages (Razor) 時,如何更新 (變更) 現有的資料庫條目。 它假設您已透過利用使用 ASP.NET Web Pages 的表單輸入資料來完成一系列。

您將學到什麼:

  • 如何在WebGrid協助程式中選取個別記錄。
  • 如何從資料庫讀取單一記錄。
  • 如何使用資料庫記錄中的值預先載入表單。
  • 如何更新資料庫中的現有記錄。
  • 如何在頁面中儲存資訊而不顯示資訊。
  • 如何使用隱藏欄位來儲存資訊。

討論的功能/技術:

  • WebGrid協助程式。
  • SQL Update 命令。
  • Database.Execute 方法。
  • 隱藏欄位 (<input type="hidden">)。

您將建置的內容

在上一個教學課程中,您已學到如何將記錄新增至資料庫。 在這裡,您將瞭解如何顯示要編輯的記錄。 在電影頁面中,您將更新WebGrid協助程式,使其在每個電影旁邊顯示編輯連結:

WebGrid 顯示包括每個電影的「編輯」連結

當您點集編輯連結時,它會帶您到不同的頁面,其中電影資訊已位於表單中:

編輯電影頁面,其中顯示要編輯的電影

您可以隨時變更任何值。 當您提交變更時,頁面中的程式碼會更新資料庫,並帶您回到電影清單。

過程中這個部分的運作方式幾乎與您在上一個教學課程中建立的 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>

網格如何運作的一些背景:網格會顯示資料列、每個資料庫記錄各顯示一個資料列,並顯示資料庫記錄中每個欄位的資料行。 建構每個網格資料列時,item物件會包含該資料列的資料庫記錄 (項目)。 這種安排可讓您以程式碼取得該資料列的資料。 這就是您在這裡看到的:運算式item.ID正在取得目前資料庫項目的識別碼值。 您可以使用item.Titleitem.Genre,或item.Year,以相同的方式取得任何資料庫值 (標題、內容類型或年份)。

運算式"~/EditMovie?id=@item.ID會將目標 URL (~/EditMovie?id=) 的硬編碼部分與這個動態衍生的識別碼結合。 (您在上一個教學課程中看到~運算子;它是代表目前網站根目錄的 ASP.NET 運算子。)

結果是資料行中這個部分的標記只會在執行階段產生類似下列標記的內容:

href="/EditMovie?id=2"

每個資料列的id實際值本來就會有所不同。

建立網格資料行的自訂顯示

現在回到網格資料行。 您原本在網格中擁有的三個資料行只會顯示資料值 (標題、內容類型,和年份)。 透過傳遞資料庫資料行的名稱,例如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>),

資料行包含呈現連結的標記,加上從列資料庫記錄擷取的一些資訊 (識別碼)。

提示

方法的具名參數和位置參數

多次呼叫方法並傳遞參數給它時,您只要列出以逗號分隔的參數值即可。 以下提供幾個範例:

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

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

當您第一次看到此程式碼時,我們並未提及這個問題,但在每個案例中,您會以特定順序將參數傳遞至方法,也就是參數在該方法中定義的順序。 針對db.ExecuteValidation.RequireFields,如果您弄亂您傳遞的值順序,則當頁面執行時,您會收到錯誤訊息,或至少會出現一些奇怪的結果。 您顯然必須知道傳入參數的順序。 (在 WebMatrix 中,IntelliSense 可協助您了解參數的名稱、類型和順序。)

除了依序傳遞值外,您可以使用具名參數。 (依序傳遞參數稱為使用位置參數。) 對於具名參數,您會在傳遞參數值時明確包含參數的名稱。 您已在這些教學課程中多次使用具名參數。 例如:

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

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

具名參數適用於數種情況,特別是當方法採用許多參數時。 其中一個是當您只想要傳遞一或兩個參數時,但您想要傳遞的值不在參數清單中的第一個位置。 另一種情況是,您想要將參數傳遞為您覺得最有意義的順序,讓您的程式碼更容易閱讀。

很明顯地,若要使用具名參數,您必須知道參數的名稱。 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作業。 (如需了解 GETPOST作業之間的差異,請參閱 HTML 表單上,上一個教學課程中的 GET、POST 和 HTTP 動詞切換側邊列。)

如您在先前的教學課程中所見,value文字方塊的屬性是以 Razor 程式碼設定,以便預先載入它們。 不過,這次,您會使用該工作的變數如titlegenre,而不是Request.Form["title"]

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

和之前一樣,此標記會使用電影值預先載入文字方塊值。 您會在某個時間看到為什麼這次使用變數,而不是使用Request物件是很方便的。

此頁面上也有<input type="hidden">元素。 此元素會儲存電影識別碼,而不會在頁面上顯示。 識別碼一開始會被傳遞到頁面,方法是使用查詢字串值 (?id=7 或 URL 中的類似值) 。 透過將識別碼碼值放入隱藏欄位,您可以確定在提交表單時可以使用它,即使您無法再存取頁面叫用的原始 URL 也一樣。

AddMovie 頁面不同,EditMovie 頁面的程式碼有兩個不同的函式。 第一個函式是,當頁面第一次顯示時 (且也只有那個時候),程式碼會從查詢字串取得電影識別碼。 然後,程式碼會使用識別碼讀取資料庫中對應的電影,並在文本方塊中顯示 (預先載入)。

第二個函式是當使用者點擊提交變更按鈕時,程式碼必須讀取文字方塊的值並加以驗證。 程式碼也必須使用新的值來更新資料庫項目。 這項技術類似於新增記錄,如您在 AddMovie 中所見。

新增程式碼以讀取單一電影

若要執行第一個函式,請將此程式碼新增至頁面頂端:

@{
    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)的區塊內。 !運算子表示「不是」,因此運算式代表如果此要求不是張貼提交,這是指出此要求是否為此頁面第一次執行的間接方式。 如先前所述,此程式碼應該在第一次執行頁面時執行。 如果您未將程式碼包括在if(!IsPost)中,則每次叫用頁面時它都會執行,無論是第一次或回應按鈕點擊。

請注意,程式碼這次包含一個else區塊。 如我們介紹if區塊時所說,如果測試條件不是真的,有時您會想要執行替代程式碼。 這就是這裡的情況。 如果條件通過 (也就是說,傳遞至頁面的識別碼沒問題),您就會從資料庫讀取資料列。 不過,如果條件未通過,else區塊就會執行,而程式碼會設定錯誤訊息。

驗證傳遞至頁面的值

程式碼會使用Request.QueryString["id"]來取得傳遞至頁面的識別碼。 程式碼可確保已針對識別碼實際傳遞值。 如果未傳遞任何值,程式碼會設定驗證錯誤。

此程式碼會顯示驗證資訊的不同方式。 在上一個教學課程中,您已使用Validation協助程式。 您已註冊要驗證的欄位,ASP.NET 使用Html.ValidationMessageHtml.ValidationSummary自動執行驗證並顯示錯誤。 不過,在此情況下,您並沒有真正驗證使用者輸入。 相反地,您正在驗證從其他地方傳遞至頁面的值。 Validation協助程式不會為您執行此動作。

因此,您會使用if(!Request.QueryString["ID"].IsEmpty()測試該值來自行檢查該值。 如果發生問題,您可以使用Html.ValidationSummary來顯示錯誤,就像您使用Validation協助程式一樣。 若要這樣做,您可以呼叫Validation.AddFormError並傳遞要顯示的訊息給它。 Validation.AddFormError是內建方法,可讓您定義與您已熟悉之驗證系統一致的自訂訊息。 (稍後在本教學課程中,我們將討論如何讓此驗證過程更健全。)

確定電影有識別碼後,程式碼會讀取資料庫,只尋找單一資料庫項目。 (您可能已經注意到資料庫作業的一般模式:開啟資料庫、定義 SQL 陳述式,以及執行陳述式。) 這次,SQLSelect 陳述式包含WHERE ID = @0。 因為識別碼是唯一的,因此只能傳回一筆記錄。

查詢是使用db.QuerySingle來執行的 (而非db.Query,如您用於電影清單的),而程式碼會將結果放入row變數中。 此名稱row為任意名稱;您可以命名任何您想要的變數。 然後,在頂端初始化的變數會填入電影詳細資料,以便在文字方塊中顯示這些值。

測試編輯頁面 (到目前為止)

如果您想要測試頁面,請立即執行電影頁面,然後點擊任何電影旁的編輯連結。 您會看到 EditMovie 頁面,其中包含已填入您所選取之電影的詳細資料:

顯示編輯電影頁面的螢幕截圖,其中顯示要編輯的電影。

請注意,頁面的 URL 包含類似?id=10的內容 (或其他數字)。 到目前為止,您已測試電影頁面中的編輯連結正常運作,您的頁面會從查詢字串讀取識別碼,以及要取得單一電影記錄的資料庫查詢正常運作。

您可以變更電影資訊,但點擊提交變更時,不會發生任何動作。

新增程式碼來更新具有使用者變更的電影

EditMovie.cshtml 檔案中,若要實作第二個函式 (儲存變更),請在@區塊的右大括弧內新增下列程式碼。 (如果您不確定要放置程式碼的確切位置,您可以查看本教學課程結尾所顯示的編輯電影頁面的完整程式碼清單

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">) 取得電影識別碼。 第一次執行頁面時,程式碼會從查詢字串中取得識別碼。 您會從隱藏欄位取得值,以確保您取得原先顯示的電影識別碼,以免查詢字串自那以後已有所改變。

AddMovie 程式碼和此程式碼之間的真正重要差異在於,在此程式碼中,您會使用 SQL Update 陳述式,而不是Insert Into陳述式。 下列範例會顯示 SQL Update 陳述式的語法:

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

您可以依任何順序指定任何資料行,而且不需要在Update作業期間更新每個資料行。 (您無法更新識別碼本身,因為這實際上會將記錄儲存為新記錄,且不允許Update作業這麼做。)

注意

重要具有識別碼的Where子句非常重要,因為這是資料庫知道您要更新哪個資料庫記錄的方式。 如果您不包括Where子句,資料庫會更新資料庫中的每一 筆記錄。 在大多數情況下,這將是一場災難。

在程式碼中,要更新的值會使用佔位符傳遞至 SQL 陳述句。 若要重複我們先前說過的內容:基於安全性考慮,使用佔位符將值傳遞至 SQL 陳述句。

程式碼使用db.Execute來執行Update陳述句後,它會重新導向回清單頁面,您可以在其中看到變更。

提示

不同的 SQL 陳述句、不同的方法

您可能已經注意到您使用稍微不同的方法來執行不同的 SQL 陳述句。 若要執行Select可能會傳回多個記錄的查詢,您可以使用Query方法。 若要執行Select您知道只會傳回一個資料庫項目的查詢,請使用QuerySingle方法。 若要執行進行變更但不會傳回資料庫項目的命令,請使用Execute方法。

您必須有不同的方法,因為每個方法都會傳回不同的結果,如您已經看到QueryQuerySingle之間的差異。 (Execute方法實際上也會傳回一個值,也就是受命令影響的資料庫列數目,但到目前為止,您一直忽略這個資料列。)

當然,Query方法可能只傳回一個資料庫列。 不過,ASP.NET 一律會將Query方法的結果視為集合。 即使方法只傳回一個資料列,您仍必須從集合中擷取該單一資料列。 因此,在知道您將只得到一個資料列的情況下,使用QuerySingle會更方便一點。

有一些其他方法可執行特定類型的資料庫作業。 您可以在 ASP.NET Web Pages API 快速參考中找到資料庫方法的清單。

讓識別碼的驗證更健全

第一次執行頁面時,您會從查詢字串取得電影識別碼,以便從資料庫取得該電影。 您確定事實上要尋找一個值,且您用了下列程式碼執行此動作:

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

您已使用此程式碼來確認如果使用者在未先選取電影頁面中電影的情況下,進入 EditMovies 頁面,該頁面會顯示使用者易懂的錯誤訊息。 (否則,使用者會看到只會讓他們感到困惑的錯誤。)

不過,此驗證並不十分健全。 您也可以使用這些錯誤調用頁面:

  • 識別碼不是數字。 例如,可以使用類似http://localhost:nnnnn/EditMovie?id=abc的 URL 來調用頁面。
  • 識別碼是一個數字,但它參考不存在的電影 (例如,http://localhost:nnnnn/EditMovie?id=100934)。

如果您想知道這些 URL 產生的錯誤,請執行電影頁面。 選取要編輯的電影,然後將 EditMovie 頁面的 URL 變更為包含字母識別碼或不存在電影識別碼的 URL。

因此您該怎麼做? 第一個修正是確定傳遞至頁面的不僅是識別碼,且標識碼還要是整數。 變更!IsPost測試的程式碼,如下所示:

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

您已將第二個條件新增至IsEmpty測試,並連結至 &&(邏輯 AND):

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

您可能會記得從ASP.NET Web Pages 程式設計的簡介教學課程中記下的方法,例如AsBool一個AsInt將字元字串轉換成一些其他資料類型。 IsInt方法 (和其他 ,例如IsBoolIsDateTime) 很類似。 不過,它們只會測試您是否可以轉換字串,而不會實際執行轉換。 因此,您基本上是在討論查詢字串值是否可以轉換成整數 ...

另一個潛在的問題是尋找不存在的電影。 取得電影的程式碼看起來像下列程式碼:

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

如果您將movieId值傳遞至未對應至實際電影的QuerySingle方法,則不會傳回任何值,且後續的陳述句 (例如,title=row.Title) 會導致錯誤。

這裡一樣有個簡易修正。 如果db.QuerySingle方法未傳回任何結果,row變數會是 Null。 因此,在嘗試從row變數取得值之前,您可以先檢查變數是否為 null。 下列程式碼會在陳述句周圍新增if區塊,以從row物件取得值:

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

透過這兩個額外的驗證測試,頁面會變得更加萬無一失。 !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 包含~表示「網站的根目錄」。

測試電影更新過程

現在您可以測試 執行電影頁面,然後點擊電影旁的編輯。 當 EditMovie] 頁面出現時,請變更影片,然後點擊提交變更。 當影片清單出現時,請確認已顯示您的變更。

若要確認驗證正常運作,請點擊編輯來取得另一部電影。 當您進入 EditMovie 頁面時,請清除 風格類型欄位 (或年份欄位,或兩者) 並試著提交您的變更。 您將會看到錯誤,如預期所示:

顯示驗證錯誤的編輯電影頁面

點擊返回到電影清單連結以放棄您的變更,並返回到電影頁面。

下一段內容

在下一個教學課程中,您將瞭解如何刪除電影記錄。

@{
    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>

其他資源