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.Genreitem.Year ,取得任何資料庫值 (標題、內容類型或年份) 相同。 item.Title

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

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

href="/EditMovie?id=2"

自然地,每個資料列的實際值 id 都會不同。

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

現在回到方格資料行。 您原本在方格中擁有的三個數據行只會顯示標題、內容類型和年份) (資料值。 您藉由傳遞資料庫資料行的名稱來指定此顯示,例如 。 grid.Column("Title")

這個新的 [編輯 連結] 資料行不同。 您不需要指定資料行名稱,而是要傳遞 format 參數。 此參數可讓您定義協助程式會隨著 item 值一起轉譯的標記 WebGrid ,以粗體或綠色或您想要的任何格式顯示資料行資料。 例如,如果您想要標題顯示為粗體,您可以建立類似下列範例的資料行:

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 呼叫,因為錯誤會顯示在驗證摘要中。 如上一個教學課程所述,您可以使用驗證摘要和各種組合中的個別錯誤訊息。

再次請注意, method 元素 <form> 的 屬性會設定為 post 。 如同 AddMovie.cshtml 頁面,此頁面會對資料庫進行變更。 因此,此表單應該執行 POST 作業。 (如需 和 POST 作業之間的差異 GET 的詳細資訊,請參閱 HTML forms.) 教學課程中的GET、POST 和 HTTP 動詞安全提要欄

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

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

如同先前一樣,此標記會預先載入具有電影值的文字方塊值。 您會在一段時間看到為什麼這次使用變數,而不是使用 Request 物件。

此頁面也有元素 <input type="hidden"> 。 此元素會儲存電影識別碼,而不會在頁面上顯示。 識別碼一開始會使用 URL 中的查詢字串值 (或類似的 URL) ?id=7 傳遞至頁面。 藉由將識別碼值放入隱藏欄位,您就可以確定表單提交時可以使用,即使您無法再存取頁面叫用的原始 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 語句,然後執行 語句。) 這次,SQL Select 語句包含 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 頁面中稍有不同,但效果相同。

您可以使用 和其他元素的類似程式碼 <input> 來取得文字方塊 Request.Form["title"] 的值。 請注意,這次程式碼會從隱藏欄位取得電影識別碼, <input type="hidden"> () 。 第一次執行頁面時,程式碼會從查詢字串取得識別碼。 您會從隱藏欄位取得值,以確定您取得原本顯示之電影的識別碼,以防查詢字串自之後有所改變。

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

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

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

注意

重要Where識別碼為 的 子句非常重要,因為這是資料庫知道您要更新之資料庫記錄的方式。 如果您離開 Where 子句,資料庫會更新資料庫中 的每個 記錄。 在大部分情況下,這會是災害。

在程式碼中,要更新的值會使用預留位置傳遞至 SQL 語句。 若要重複先前所說的內容:基於安全性考慮, 請只 使用預留位置將值傳遞至 SQL 語句。

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

提示

不同的 SQL 語句、不同的方法

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

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

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

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

讓識別碼的驗證更健全

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

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

您已使用此程式碼來確保如果使用者未先選取Movies頁面中的電影,頁面會顯示使用者易記的錯誤訊息。 (否則,使用者會看到可能只是混淆的錯誤。)

不過,此驗證不是非常強固的。 您也可以使用下列錯誤來叫用頁面:

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

如果您想要查看這些 URL 所產生的錯誤,請執行 Movies 頁面。 選取要編輯的電影,然後將 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程式設計教學課程的簡介中,將字元字串轉換成一些其他資料類型的方法 AsBoolAsInt 。 方法 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 頁面時,請清除 [ 內容類型 ] 欄位 (或 Year 欄位,或同時) 並嘗試提交您的變更。 您會看到錯誤,如預期所示:

編輯影片頁面,其中顯示驗證錯誤

按一下 [ 返回電影清單 ] 連結以放棄您的變更,並返回 [電影] 頁面。

即將推出下一個

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

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

其他資源