ASP.NET 网页简介 - 删除数据库数据
作者: Tom FitzMacken
本教程介绍如何删除单个数据库条目。 它假定你已完成通过更新 ASP.NET 网页中的数据库数据系列。
学习内容:
- 如何从记录列表中选择单个记录。
- 如何从数据库中删除单个记录。
- 如何检查窗体中是否单击了特定按钮。
讨论的功能/技术:
- 帮助
WebGrid
程序。- SQL
Delete
命令。- 运行
Database.Execute
SQLDelete
命令的方法。
所需操作
在上一教程中,你学习了如何更新现有数据库记录。 本教程类似,但不会更新记录,而是将其删除。 这些过程大致相同,但删除操作更简单,因此本教程将简短。
在 “电影” 页中 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>
元素),其文本显示“Delete”。 链接的目标(其 href
属性)是最终解析为类似于此 URL 的代码, id
每个电影的值不同:
http://localhost:43097/DeleteMovie?id=7
此链接将调用名为 DeleteMovie 的页面,并向其传递所选电影的 ID。
本教程不会详细介绍如何构造此链接,因为它与上一教程中的“编辑”链接几乎完全相同(更新 ASP.NET 网页中的数据库数据)。
创建“删除”页
现在,可以创建将成为网格中“删除”链接的目标页面。
注意
重要: 首先选择要删除的记录,然后使用单独的页面和按钮确认该过程对于安全性非常重要。 如前一教程中所述,应始终使用窗体(即使用 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 页面,但标记包含<span>
元素(而不是使用文本框)。<input type="text">
此处没有可编辑的内容。 你只需显示电影详细信息,以便用户可以确保他们正在删除正确的电影。
标记已包含一个链接,允许用户返回到电影列表页面。
与 EditMovie 页面一样,所选电影的 ID 存储在隐藏的字段中。 (它作为查询字符串值首先传递到页面。有一个 Html.ValidationSummary
调用将显示验证错误。 在这种情况下,错误可能是没有将电影 ID 传递给页面,或者电影 ID 无效。 如果有人在没有首先选择电影页中的电影的情况下运行此页面,则可能会出现这种情况。
按钮标题为 Delete Movie,其名称属性设置为 buttonDelete
。 该 name
属性将在代码中用于标识提交表单的按钮。
在首次显示页面时,您必须将代码写入 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 页面中的相应代码相同。 它从查询字符串中获取电影 ID,并使用 ID 从数据库读取记录。 代码包括验证测试(IsInt()
和 row != null
),以确保传递到页面的电影 ID 有效。
请记住,此代码应仅在页面首次运行时运行。 当用户单击“ 删除电影”按钮时,不希望从数据库重新读取电影 记录。 因此,阅读电影的代码位于一个测试if(!IsPost)
中,也就是说,如果请求不是操作后操作(表单提交)。
添加代码以删除所选电影
若要在用户单击按钮时删除影片,请在块的 @
右大括号内添加以下代码:
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”(逻辑 AND)。 因此,整个 if
条件为 ...
此请求是一个帖子(不是第一次请求)
AND
按钮buttonDelete
是提交表单的按钮。
此窗体(事实上,此页面)仅包含一个按钮,因此在技术上不需要额外 buttonDelete
测试。 不过,你将执行永久删除数据的操作。 因此,你希望确保仅在用户显式请求操作时才执行该操作。 例如,假设稍后扩展了此页面,并向其中添加了其他按钮。 即便如此,仅当单击按钮时 buttonDelete
,删除电影的代码才会运行。
与在 EditMovie 页中一样,从隐藏字段获取 ID,然后运行 SQL 命令。 语句的 Delete
语法为:
DELETE FROM table WHERE ID = value
包含 WHERE
子句和 ID 至关重要。 如果省略 WHERE 子句, 将删除表中的所有记录。 如前所述,使用占位符将 ID 值传递给 SQL 命令。
测试电影删除过程
现在可以测试了。 运行“电影”页,然后单击电影旁边的“删除”。 出现 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>