共用方式為


ASP.NET Web Pages 簡介 - 刪除資料庫資料

作者:Tom FitzMacken

本教學課程說明如何刪除個別資料庫項目。 其假設您已完成在 ASP.NET Web Pages 中更新資料庫資料系列。

您將學會:

  • 如何從記錄清單中選取個別記錄。
  • 如何從資料庫刪除單一記錄。
  • 如何檢查表單中是否已按下特定按鈕。

討論的功能/技術:

  • WebGrid協助程式。
  • SQL Delete 命令。
  • 用以執行 SQL Delete 命令的 Database.Execute 方法。

建置內容

在上一個教學課程中,您已了解如何更新現有的資料庫記錄。 本教學課程很類似,不同之處在於您不會更新記錄,而是將它刪除。 程序大致相同,差別在於刪除比較簡單,因此本教學課程也很簡短。

在 [電影] 頁面中,您將更新 WebGrid 協助程式,使其在每部電影旁顯示 [刪除] 連結,以伴隨您稍早新增的 [編輯] 連結。

為每部電影顯示 [刪除] 連結的電影頁面

就跟編輯一樣,當您按一下 [編輯] 連結時,它會帶您到不同的頁面,其中電影資訊已位於表單中:

顯示電影的 [刪除電影] 頁面

然後,您可以按一下按鈕以永久刪除記錄。

首先,您將新增 [刪除] 連結至 WebGrid 協助程式。 此連結類似於您在上一個教學課程中新增的 [編輯] 連結。

開啟 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="~/DeleteMovie?id=@item.ID">Delete</a>)
    )
)

新的資料行是這個資料行:

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

設定格線的方式,[編輯] 資料行在格線中最左邊,而 [刪除] 資料行在最右邊。 (萬一您沒注意到,現在 Year 資料行後面有逗號)。這些連結資料行的位置並無特殊之處,而且您可以輕鬆地將它們放在彼此旁邊。 在本例中,將它們分開,比較不容易混淆。

標示 [編輯] 和 [詳細資料] 連結以顯示彼此不相鄰的的電影頁面

新的資料行會顯示一個連結 (<a> 元素),其文字顯示「刪除」。 連結的目標 (其 href 屬性) 是最終解析為類似此 URL 的程式碼,每部電影的 id 值不同:

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

此連結會叫用名為 DeleteMovie 的頁面,並傳遞您所選取電影的識別碼。

本教學課程不會詳細說明此連結建構方式,因為它與上一個教學課程中的 [編輯] 連結幾乎完全相同 (在 ASP.NET Web Pages 中更新資料庫資料)。

建立刪除頁面

現在,您可以建立頁面,在格線中成為 [刪除] 連結的目標。

注意

重要事項:先選取要刪除的記錄,然後使用個別頁面和按鈕來確認程序,對於安全性而言極為重要。 如您在先前的教學課程中所讀,對您的網站進行「任何」類型的變更應該「一律」使用表單來完成,也就是使用 HTTP POST 作業。 如果只要按下連結即可變更網站 (也就是使用 GET 作業),人們就可以對您的網站提出簡單的要求,並刪除您的資料。 即使是編製網站索引的搜尋引擎編目程式,也可能不小心遵循下列連結來刪除資料。

當您的應用程式讓使用者變更記錄時,無論如何都必須將記錄呈現給使用者以進行編輯。 但您可能會想要針對刪除記錄略過此步驟。 不過,請不要略過此步驟。 (讓使用者查看記錄,並確認他們正在刪除他們預期的記錄也很有幫助。)

在後續的教學課程集中,您將了解如何新增登入功能,讓使用者必須先登入才能刪除記錄。

建立名為 DeleteMovie.cshtml 的頁面,並以下列標記取代檔案中的內容:

<html>
<head>
  <title>Delete a Movie</title>
</head>
<body>
      <h1>Delete a Movie</h1>
        @Html.ValidationSummary()
      <p><a href="~/Movies">Return to movie listing</a></p>

      <form method="post">
        <fieldset>
        <legend>Movie Information</legend>

        <p><span>Title:</span>
         <span>@title</span></p>

        <p><span>Genre:</span>
         <span>@genre</span></p>

        <p><span>Year:</span>
          <span>@year</span></p>

        <input type="hidden" name="movieid" value="@movieId" />
        <p><input type="submit" name="buttonDelete" value="Delete Movie" /></p>
        </fieldset>
      </form>
    </body>
</html>

此標記與 EditMovie 頁面類似,不同之處在於與其文字方塊 (<input type="text">),標記會包含 <span> 元素。 這裡沒有可編輯的內容。 您只需要顯示電影詳細資料,讓使用者可以確定他們正在刪除正確的電影。

標記已經包含可讓使用者返回電影清單頁面的連結。

如同 EditMovie 頁面,所選電影的識別碼會儲存在隱藏的欄位中。 (它會先以查詢字串值的形式傳遞至頁面)。有一個 Html.ValidationSummary 呼叫會顯示驗證錯誤。 在本例中,錯誤可能是沒有將電影識別碼傳遞至頁面,或電影識別碼無效。 如果有人執行此頁面但沒有先在 [電影] 頁面中選取電影 ,就可能發生這種情況。

按鈕標題為 [刪除電影],且其名稱屬性設定為 buttonDeletename 屬性將用於程式碼中,以識別提交表單的按鈕。

當頁面第一次顯示時,您必須寫入程式碼以 1) 讀取電影詳細資料,並且 2) 當使用者按下按鈕時,實際刪除電影。

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

DeleteMovie.cshtml 頁面頂端,新增下列程式碼區塊:

@{
    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 found for that ID.");
            }
        }
        else{
            Validation.AddFormError("No movie was found for that ID.");
        }
    }
}

此標記與 EditMovie 頁面中相對應的程式碼相同。 它會從查詢字串取得電影識別碼,並使用該識別碼從資料庫讀取記錄。 程式碼包含驗證測試 (IsInt()row != null),以確保傳遞至頁面的是有效的電影識別碼。

請記住,此程式碼應該僅在第一次執行頁面時執行。 當使用者按下 [刪除電影] 按鈕時,您不應該從資料庫重新讀取電影記錄。 因此,讀取電影的程式碼位在測試中並指出 if(!IsPost),也就是說,如果要求不是 Post 作業 (表單提交)

新增程式碼以刪除選取的電影

若要在使用者按下按鈕時刪除電影,請在 @ 區塊的右大括弧內新增下列程式碼:

if(IsPost && !Request["buttonDelete"].IsEmpty()){
    movieId = Request.Form["movieId"];
    var db = Database.Open("WebPagesMovies");
    var deleteCommand = "DELETE FROM Movies WHERE ID = @0";
    db.Execute(deleteCommand, movieId);
    Response.Redirect("~/Movies");
}

此程式碼與更新現有記錄的程式碼類似,但更簡單。 程式碼基本上會執行 SQL Delete 陳述式。

如同 EditMovie 頁面,程式碼位於if(IsPost) 區塊中。 這一次,if() 條件稍微複雜一點:

if(IsPost && !Request["buttonDelete"].IsEmpty())

這裡有兩個條件。 第一個是要提交的頁面,如您先前所見 — if(IsPost)

第二個條件是 !Request["buttonDelete"].IsEmpty(),這表示要求具有名為 buttonDelete 的物件。 無可否認,這是測試哪一個按鈕提交表單的間接方式。 如果表單包含多個提交按鈕,則只會在要求中顯示已按下的按鈕名稱。 因此,在邏輯上,如果特定按鈕的名稱出現在要求中,或如程式碼所述,若該按鈕不是空的,就是提交表單的按鈕。

&& 運算子表示「並且」 (邏輯 AND)。 因此,整個 if 條件為 ...

此要求是 Post (不是第一次要求)

buttonDelete按鈕是提交表單的按鈕。

此表單 (事實上,此頁面) 只包含一個按鈕,因此嚴格說來對 buttonDelete 不需要額外的測試。 不過,您即將執行將永久移除資料的作業。 因此,您應該盡可能確定只有在使用者明確要求時,才執行作業。 例如,假設您稍後已展開此頁面,並將其他按鈕新增至此頁面。 即便如此,刪除電影的程式碼只有在按下 buttonDelete 按鈕時才會執行。

如同 EditMovie 頁面,您會從隱藏欄位取得識別碼,然後執行 SQL 命令。 Delete 陳述式的語法為:

DELETE FROM table WHERE ID = value

包含 WHERE 子句和識別碼非常重要。 如果您省略 WHERE 子句,將刪除資料表中的所有記錄。 如您所見,您使用預留位置將識別碼值傳遞至 SQL 命令。

測試電影刪除程序

您現在可以測試。 執行 Movies 頁面,然後按一下電影旁的 [刪除]。 當 DeleteMovie 頁面出現時,按一下 [刪除電影]

已醒目提示 [刪除電影] 按鈕的 [刪除電影] 頁面

當您按下按鈕時,程式碼會刪除電影並返回電影清單。 您可以在該處搜尋已刪除的電影,並確認它已刪除。

接續內容

下一個教學課程會說明如何為網站中的所有頁面提供一般的外觀和版面配置。

@{
    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"),
                grid.Column(format: @<a href="~/DeleteMovie?id=@item.ID">Delete</a>)
            )
        )
      </div>
      <p>
        <a href="~/AddMovie">Add a movie</a>
      </p>
    </body>
</html>

DeleteMovie 頁面的完整清單

@{
    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 found for that ID.");
            }
        }
        else{
            Validation.AddFormError("No movie was found for that ID.");
        }
    }

    if(IsPost && !Request["buttonDelete"].IsEmpty()){
        movieId = Request.Form["movieId"];
        var db = Database.Open("WebPagesMovies");
        var deleteCommand = "DELETE FROM Movies WHERE ID = @0";
        db.Execute(deleteCommand, movieId);
        Response.Redirect("~/Movies");
    }
}
<html>
<head>
  <title>Delete a Movie</title>
</head>
<body>
      <h1>Delete a Movie</h1>
        @Html.ValidationSummary()
      <p><a href="~/Movies">Return to movie listing</a></p>

      <form method="post">
        <fieldset>
        <legend>Movie Information</legend>

        <p><span>Title:</span>
         <span>@title</span></p>

        <p><span>Genre:</span>
         <span>@genre</span></p>

        <p><span>Year:</span>
          <span>@year</span></p>

        <input type="hidden" name="movieid" value="@movieId" />
        <p><input type="submit" name="buttonDelete" value="Delete Movie" /></p>
        </fieldset>
        <p><a href="~/Movies">Return to movie listing</a></p>
      </form>
    </body>
</html>

其他資源