在 ASP.NET 网页 (Razor) 站点中使用数据库简介

作者 Tom FitzMacken

本文介绍如何使用 Microsoft WebMatrix 工具在 ASP.NET 网页 (Razor) 网站中创建数据库,以及如何创建允许显示、添加、编辑和删除数据的页面。

你将了解的内容:

  • 如何创建数据库。
  • 如何连接到数据库。
  • 如何在网页中显示数据。
  • 如何插入、更新和删除数据库记录。

以下是本文中介绍的功能:

  • 使用 Microsoft SQL Server Compact Edition 数据库。
  • 使用 SQL 查询。
  • Database 类。

本教程中使用的软件版本

  • ASP.NET 网页 (Razor) 2
  • WebMatrix 2

本教程还适用于 WebMatrix 3。 可以将 ASP.NET 网页 3 和 Visual Studio 2013 (或 Visual Studio Express 2013 用于 Web) ;但是,用户界面将有所不同。

数据库简介

假设有一个典型的通讯簿。 对于通讯簿 (中的每个条目,即,对于每个人) ,你有多个信息,例如名字、姓氏、地址、电子邮件地址和电话号码。

像这样描绘数据的典型方式是作为包含行和列的表。 在数据库术语中,每一行通常称为记录。 每列 (有时称为字段) 包含每种类型的数据的值:名字、姓氏等。

ID 名字 姓氏 Address 电子邮件 电话
1 Jim 阿布鲁斯 210 100th St SE Orcas WA 98031 jim@contoso.com 555 0100
2 Terry Adams 1234 主街西雅图 WA 99011 terry@cohowinery.com 555 0101

对于大多数数据库表,表必须具有一个包含唯一标识符的列,例如客户编号、帐户号等。这称为表 的主键,使用它来标识表中的每一行。 在示例中,ID 列是通讯簿的主键。

通过对数据库的基本了解,你可以了解如何创建简单的数据库并执行添加、修改和删除数据等操作。

提示

关系数据库

可以通过多种方式存储数据,包括文本文件和电子表格。 不过,对于大多数业务用途,数据存储在关系数据库中。

本文不会深入探讨数据库。 但是,你可能会发现稍微了解一下它们很有用。 在关系数据库中,信息在逻辑上划分为单独的表。 例如,学校的数据库可能包含学生和课堂课程的单独表。 SQL Server) 等数据库软件 (支持强大的命令,使你能够动态建立表之间的关系。 例如,可以使用关系数据库在学生和班级之间建立逻辑关系,以便创建计划。 将数据存储在单独的表中可降低表结构的复杂性,并减少在表中保留冗余数据的需求。

创建数据库

此过程演示如何使用 WebMatrix 中包含的 SQL Server Compact 数据库设计工具创建名为 SmallBakery 的数据库。 虽然可以使用代码创建数据库,但更典型的做法是使用 WebMatrix 等设计工具创建数据库和数据库表。

  1. 启动 WebMatrix,然后在“快速启动”页上,单击“ 从模板站点”。

  2. 选择“ 空网站”,在“ 网站名称 ”框中输入“SmallBakery”,然后单击“ 确定”。 网站创建并显示在 WebMatrix 中。

  3. 在左窗格中,单击“ 数据库” 工作区。

  4. 在功能区中,单击“ 新建数据库”。 创建一个与站点同名的空数据库。

  5. 在左窗格中,展开 SmallBakery.sdf 节点,然后单击“ ”。

  6. 在功能区中,单击“ 新建表”。 WebMatrix 将打开表设计器。

    [屏幕截图显示 Web 矩阵打开表设计器。]

  7. 单击“ 名称” 列并输入“Id”。

  8. 在“ 数据类型” 列中,选择“ int”。

  9. “是主键吗?” 和“ 是否标识?” 选项设置为 “是”。

    顾名思义, 是主键 会告知数据库这是表的主键。 标识 指示数据库自动为每条新记录创建 ID 号,并为其分配下一个序号, (从 1) 开始。

  10. 单击下一行。 编辑器将启动新的列定义。

  11. 对于“名称”值,请输入“Name”。

  12. 对于 “数据类型”,选择“nvarchar”并将长度设置为 50。 的 nvarcharvar 部分告知数据库,此列的数据将是一个字符串,其大小可能因记录而异。 (n 个前缀表示 国家/地区,表示字段可以保存表示任何字母或书写系统的字符数据,即字段保存 Unicode data.)

  13. “允许 Null” 选项设置为 “否”。 这将强制“ 名称” 列不留空。

  14. 使用此相同过程,创建名为 Description 的列。 将 “数据类型 ”设置为“nvarchar”,将长度设置为 50,并将 “允许 Null” 设置为 false。

  15. 创建名为 Price 的列。 将 “数据类型”设置为“money” ,并将 “允许 Null” 设置为 false。

  16. 在顶部的框中,将表命名为“Product”。

    完成后,定义将如下所示:

    [屏幕截图显示定义完成后的外观。]

  17. 按 Ctrl+S 保存表。

将数据添加到数据库

现在,你可以向数据库添加一些示例数据,稍后将在本文中使用这些数据。

  1. 在左窗格中,展开 SmallBakery.sdf 节点,然后单击“ ”。

  2. 右键单击“产品”表,然后单击“ 数据”。

  3. 在编辑窗格中,输入以下记录:

    名称 说明 价格
    面包 每天新鲜烘焙。 2.99
    草莓蛋糕 用我们花园的有机草莓制成。 9.99
    Apple Pie 仅次于你妈妈的馅饼。 12.99
    山核桃馅饼 如果你喜欢山核桃,这是适合你的。 10.99
    柠檬派 用世界上最好的柠檬制成。 11.99
    纸托蛋糕 你的孩子和你中的孩子会喜欢这些。 7.99

    请记住,无需为 Id 列输入任何内容。 创建 Id 列时,将其 Is Identity 属性设置为 true,这会导致自动填充该列。

    输入完数据后,表设计器将如下所示:

    [屏幕截图显示输入完数据后表设计器的外观。]

  4. 关闭包含数据库数据的选项卡。

显示数据库中的数据

获得包含数据的数据库后,可以在 ASP.NET 网页中显示数据。 若要选择要显示的表行,请使用 SQL 语句,该语句是传递给数据库的命令。

  1. 在左窗格中,单击“ 文件” 工作区。

  2. 在网站的根目录中,创建名为 ListProducts.cshtml 的新 CSHTML 页面。

  3. 将现有标记替换为以下内容:

    @{
        var db = Database.Open("SmallBakery");
        var selectQueryString = "SELECT * FROM Product ORDER BY Name";
     }
    <!DOCTYPE html>
    <html>
     <head>
       <title>Small Bakery Products</title>
       <style>
           table, th, td {
             border: solid 1px #bbbbbb;
             border-collapse: collapse;
             padding: 2px;
           }
        </style>
     </head>
     <body>
       <h1>Small Bakery Products</h1>
       <table>
           <thead>
               <tr>
                   <th>Id</th>
                   <th>Product</th>
                   <th>Description</th>
           <th>Price</th>
               </tr>
           </thead>
           <tbody>
               @foreach(var row in db.Query(selectQueryString)){
                <tr>
                   <td>@row.Id</td>
                       <td>@row.Name</td>
                       <td>@row.Description</td>
                       <td>@row.Price</td>
                </tr>
               }
           </tbody>
       </table>
     </body>
    </html>
    

    在第一个代码块中,打开前面创建的 SmallBakery.sdf 文件 (数据库) 。 方法 Database.Open 假定 .sdf 文件位于网站的 App_Data 文件夹中。 (请注意,无需指定 .sdf 扩展名 ,事实上,如果指定, Open 方法将不起作用。)

    注意

    App_Data文件夹是 ASP.NET 中用于存储数据文件的特殊文件夹。 有关详细信息,请参阅本文后面的 连接到数据库

    然后,使用以下 SQL Select 语句发出查询数据库的请求:

    SELECT * FROM Product ORDER BY Name
    

    在 语句中, Product 标识要查询的表。 字符 * 指定查询应返回表中的所有列。 (如果只想查看某些列,还可以单独列出列,用逗号分隔。) The Order By 子句指示应如何对数据进行排序-在本例中,按 Name 列排序。 这意味着数据根据每行的 “名称” 列的值按字母顺序排序。

    在页面正文中,标记将创建一个用于显示数据的 HTML 表。 在 元素内 <tbody> ,使用 foreach 循环单独获取查询返回的每个数据行。 对于每个数据行, (元素) <tr> 创建一个 HTML 表行。 然后,为每个列创建 HTML 表单元格 (<td> 元素) 。 每次遍历 循环时,数据库中的下一个可用行都位于变量中 row , (你在 语句) 中设置 foreach 该行。 若要从行中获取单个列,可以使用 row.Namerow.Description 或所需的列的名称。

  4. 在浏览器中运行页面。 (请确保在“ 文件” 工作区中选中该页,然后再运行它。) 该页显示如下所示的列表:

    [屏幕截图显示页面将在浏览器中显示的列表。]

提示

结构化查询语言 (SQL)

SQL 是大多数关系数据库中用于管理数据库中数据的语言。 它包含用于检索和更新数据的命令,以及用于创建、修改和管理数据库表的命令。 SQL 不同于在 WebMatrix) 中所使用的编程语言 (,因为使用 SQL,其理念是告诉数据库所需内容,而数据库的工作是弄清楚如何获取数据或执行任务。 下面是一些 SQL 命令及其用途的示例:

SELECT Id, Name, Price FROM Product WHERE Price > 10.00 ORDER BY Name

如果 Price 的值超过 10,则会从 Product 表中的记录中提取 IdNamePrice 列,并根据 Name 列的值按字母顺序返回结果。 此命令将返回一个结果集,其中包含符合条件的记录;如果没有记录匹配,则返回空集。

INSERT INTO Product (Name, Description, Price) VALUES ("Croissant", "A flaky delight", 1.99)

这会在 “产品 ”表中插入一条新记录,将 “名称 ”列设置为“单色”,将 “说明 ”列设置为“片状的喜悦”,并将价格设置为 1.99。

DELETE FROM Product WHERE ExpirationDate < "01/01/2008"

此命令删除 Product 表中过期日期列早于 2008 年 1 月 1 日的记录。 (这假定 Product 表具有此类列。当然,) 此处的日期以 MM/DD/YYYY 格式输入,但应以用于区域设置的格式输入日期。

Insert IntoDelete 命令不返回结果集。 相反,它们返回一个数字,告知有多少记录受 命令影响。

对于其中一些操作 ((例如插入和删除记录) ),请求操作的进程在数据库中必须具有相应的权限。 这就是为什么在连接到数据库时,对于生产数据库,通常需要提供用户名和密码。

有几十个 SQL 命令,但它们都遵循这样的模式。 可以使用 SQL 命令创建数据库表、计算表中的记录数、计算价格以及执行更多操作。

在数据库中插入数据

本部分介绍如何创建允许用户将新产品添加到 Product 数据库表的页面。 插入新的产品记录后,该页面将使用在上一部分创建的 ListProducts.cshtml 页显示更新的表。

该页包含验证,以确保用户输入的数据对数据库有效。 例如,页面中的代码可确保已为所有必需列输入值。

  1. 在网站中,创建名为 InsertProducts.cshtml 的新 CSHTML 文件。

  2. 将现有标记替换为以下内容:

    @{
        Validation.RequireField("Name", "Product name is required.");
        Validation.RequireField("Description", "Product description is required.");
        Validation.RequireField("Price", "Product price is required.");
    
        var db = Database.Open("SmallBakery");
        var Name = Request.Form["Name"];
        var Description = Request.Form["Description"];
        var Price = Request.Form["Price"];
    
        if (IsPost && Validation.IsValid()) {
            // Define the insert query. The values to assign to the
            // columns in the Product table are defined as parameters
            // with the VALUES keyword.
            if(ModelState.IsValid) {
                var insertQuery = "INSERT INTO Product (Name, Description, Price) " +
                    "VALUES (@0, @1, @2)";
                db.Execute(insertQuery, Name, Description, Price);
                // Display the page that lists products.
                Response.Redirect("~/ListProducts");
            }
        }
    }
    
    <!DOCTYPE html>
    <html>
    <head>
     <title>Add Products</title>
     <style type="text/css">
        label {float:left; width: 8em; text-align: right;
               margin-right: 0.5em;}
        fieldset {padding: 1em; border: 1px solid; width: 50em;}
        legend {padding: 2px 4px; border: 1px solid; font-weight:bold;}
        .validation-summary-errors {font-weight:bold; color:red;
               font-size: 11pt;}
     </style>
    </head>
    <body>
     <h1>Add New Product</h1>
    
     @Html.ValidationSummary("Errors with your submission:")
    
     <form method="post" action="">
       <fieldset>
         <legend>Add Product</legend>
         <div>
           <label>Name:</label>
           <input name="Name" type="text" size="50" value="@Name" />
         </div>
         <div>
           <label>Description:</label>
           <input name="Description" type="text" size="50"
               value="@Description" />
         </div>
         <div>
           <label>Price:</label>
           <input name="Price" type="text" size="50" value="@Price" />
         </div>
         <div>
           <label>&nbsp;</label>
           <input type="submit" value="Insert" class="submit" />
         </div>
       </fieldset>
     </form>
    </body>
    </html>
    

    页面正文包含一个 HTML 窗体,其中包含三个文本框,允许用户输入名称、说明和价格。 当用户单击“ 插入 ”按钮时,页面顶部的代码会打开与 SmallBakery.sdf 数据库的连接。 然后,可以使用 对象获取用户已提交的值, Request 并将这些值分配给局部变量。

    若要验证用户是否为每个必需列输入了值,请注册要验证的每个 <input> 元素:

    Validation.RequireField("Name", "Product name is required.");
    Validation.RequireField("Description", "Product description is required.");
    Validation.RequireField("Price", "Product price is required.");
    

    帮助 Validation 程序检查你已注册的每个字段中是否都有一个值。 可以通过检查 Validation.IsValid()来测试是否所有字段都通过了验证,通常在处理从用户获取的信息之前执行此操作:

    if (IsPost && Validation.IsValid()) {
        // Process information here
    }
    

    (运算符 && 表示 AND - 此测试是 如果这是表单提交且所有字段都通过了 validation.)

    如果验证 (所有列均为空) ,请继续创建 SQL 语句以插入数据,然后执行,如下所示:

    var insertQuery =
        "INSERT INTO Product (Name, Description, Price) VALUES (@0, @1, @2)";
    

    对于要插入的值,请包括参数占位符 (@0@1@2) 。

    注意

    作为安全预防措施,始终使用参数将值传递给 SQL 语句,如前面的示例中所示。 这使你有机会验证用户的数据,此外,它还有助于防止尝试向数据库发送恶意命令, (有时称为 SQL 注入攻击) 。

    若要执行查询,请使用此语句,将包含要替换占位符的值的变量传递给它:

    db.Execute(insertQuery, Name, Description, Price);
    

    Insert Into执行 语句后,可使用以下行将用户发送到列出产品的页面:

    Response.Redirect("~/ListProducts");
    

    如果验证未成功,则跳过插入。 相反,页面中有一个帮助程序,可以在 (显示累积的错误消息(如果有任何) ):

    @Html.ValidationSummary("Errors with your submission:")
    

    请注意,标记中的样式块包括名为 的 .validation-summary-errorsCSS 类定义。 这是默认情况下用于包含任何验证错误的元素的 <div> CSS 类的名称。 在这种情况下,CSS 类指定验证摘要错误以红色和粗体显示,但你可以定义 .validation-summary-errors 类以显示所需的任何格式。

测试插入页

  1. 在浏览器中查看页面。 该页面显示类似于下图所示的窗体。

    [屏幕截图显示将在浏览器中的页面上显示的窗体。]

  2. 输入所有列的值,但请确保将 “价格 ”列留空。

  3. 单击“插入” 。 该页显示错误消息,如下图所示。 (未创建新记录。)

    [屏幕截图显示错误消息。]

  4. 完全填写表单,然后单击“ 插入”。 这一次, 将显示 ListProducts.cshtml 页面并显示新记录。

更新数据库中的数据

将数据输入表后,可能需要对其进行更新。 此过程演示如何创建两个页面,这两个页面与之前为数据插入而创建的页面类似。 第一页显示产品,并允许用户选择要更改的产品。 第二页允许用户实际进行编辑并保存它们。

注意

重要 在生产网站中,通常限制允许对数据进行更改的人员。 有关如何设置成员身份以及如何授权用户在网站上执行任务的信息,请参阅向 ASP.NET 网页网站添加安全性和成员身份

  1. 在网站中,创建名为 EditProducts.cshtml 的新 CSHTML 文件。

  2. 将 文件中的现有标记替换为以下内容:

    @{
        var db = Database.Open("SmallBakery");
        var selectQueryString = "SELECT * FROM Product ORDER BY Name";
    
    }
    <!DOCTYPE html>
    <html>
    <head>
        <title>Edit Products</title>
        <style type="text/css">
            table, th, td {
              border: solid 1px #bbbbbb;
              border-collapse: collapse;
              padding: 2px;
            }
        </style>
    </head>
    <body>
        <h1>Edit Small Bakery Products</h1>
        <table>
          <thead>
            <tr>
              <th>&nbsp;</th>
              <th>Name</th>
              <th>Description</th>
              <th>Price</th>
            </tr>
          </thead>
          <tbody>
            @foreach (var row in db.Query(selectQueryString)) {
              <tr>
                <td><a href="@Href("~/UpdateProducts", row.Id)">Edit</a></td>
                <td>@row.Name</td>
                <td>@row.Description</td>
                <td>@row.Price</td>
              </tr>
            }
          </tbody>
        </table>
    </body>
    </html>
    

    此页面与之前列出的 ListProducts.cshtml 页面之间的唯一区别在于,此页面中的 HTML 表包含一个显示 编辑 链接的额外列。 单击此链接时,将转到 UpdateProducts.cshtml 页面 (接下来将创建) 可在其中编辑所选记录。

    查看创建 “编辑” 链接的代码:

    <a href="@Href("~/UpdateProducts", row.Id)">Edit</a></td>
    

    这会创建一个 HTML <a> 元素,其 href 属性是动态设置的。 属性 href 指定要在用户单击链接时显示的页面。 它还将 Id 当前行的值传递给链接。 当页面运行时,页面源可能包含如下链接:

    <a href="UpdateProducts/1">Edit</a></td>
    <a href="UpdateProducts/2">Edit</a></td>
    <a href="UpdateProducts/3">Edit</a></td>
    

    请注意, href 属性设置为 UpdateProducts/n,其中 n 是一个产品编号。 当用户单击其中一个链接时,生成的 URL 将如下所示:

    http://localhost:18816/UpdateProducts/6

    换句话说,要编辑的版本号将在 URL 中传递。

  3. 在浏览器中查看页面。 页面以如下所示的格式显示数据:

    [屏幕截图显示浏览器中页面上显示的数据。]

    接下来,你将创建允许用户实际更新数据的页面。 更新页包括验证用户输入的数据的验证。 例如,页面中的代码可确保已为所有必需列输入值。

  4. 在网站中,创建名为 UpdateProducts.cshtml 的新 CSHTML 文件。

  5. 将 文件中的现有标记替换为以下内容。

    @{
        Validation.RequireField("Name", "Product name is required.");
        Validation.RequireField("Description", "Product description is required.");
        Validation.RequireField("Price", "Product price is required.");
    
        var Name = "";
        var Description = "";
        var Price = Decimal.Zero;
    
        var ProductId  = UrlData[0];
        if (ProductId.IsEmpty()) {
             Response.Redirect("~/EditProducts");
        }
    
        var db = Database.Open("SmallBakery");
    
        if (IsPost && Validation.IsValid()) {
            var updateQueryString =
                "UPDATE Product SET Name=@0, Description=@1, Price=@2 WHERE Id=@3" ;
            Name = Request["Name"];
            Description = Request["Description"];
            Price = Request["Price"].AsDecimal();
            db.Execute(updateQueryString, Name, Description, Price, ProductId);
            Response.Redirect(@Href("~/EditProducts"));
        }
        else {
            var selectQueryString = "SELECT * FROM Product WHERE Id=@0";
    
            var row = db.QuerySingle(selectQueryString, ProductId);
            Name = row.Name;
            Description = row.Description;
            Price = row.Price;
        }
    
    }
    
    <!DOCTYPE html>
    <html>
    <head>
      <title>Add Products</title>
      <style type="text/css">
         label { float: left; width: 8em; text-align: right;
                 margin-right: 0.5em;}
         fieldset { padding: 1em; border: 1px solid; width: 35em;}
         legend { padding: 2px 4px;  border: 1px solid; font-weight: bold;}
         .validation-summary-errors {font-weight:bold; color:red; font-size:11pt;}
      </style>
    </head>
    <body>
      <h1>Update Product</h1>
       @Html.ValidationSummary("Errors with your submission:")
       <form method="post" action="">
         <fieldset>
           <legend>Update Product</legend>
           <div>
             <label>Name:</label>
             <input name="Name" type="text" size="50" value="@Name" />
           </div>
           <div>
             <label>Description:</label>
             <input name="Description" type="text" size="50"
                value="@Description" />
           </div>
           <div>
              <label>Price:</label>
              <input name="Price" type="text" size="50" value="@Price" />
           </div>
           <div>
              <label>&nbsp;</label>
              <input type="submit" value="Update" class="submit" />
           </div>
        </fieldset>
      </form>
    </body>
    </html>
    

    页面正文包含一个 HTML 窗体,其中显示产品,用户可以在其中对其进行编辑。 若要获取要显示的产品,请使用以下 SQL 语句:

    SELECT * FROM Product WHERE Id=@0
    

    这将选择其 ID 与参数中 @0 传递的值匹配的产品。 (由于 ID 是主键,因此必须是唯一的,因此只能这样选择一个产品记录。) 若要获取要传递给此 Select 语句的 ID 值,可以使用以下语法读取作为 URL 的一部分传递到页面的值:

    var ProductId  = UrlData[0];
    

    若要实际提取产品记录,请使用 QuerySingle 方法,该方法仅返回一条记录:

    var row = db.QuerySingle(selectQueryString, ProductId);
    

    单个行将返回到 变量中 row 。 可以从每列获取数据并将其分配给局部变量,如下所示:

    var Name = row.Name;
    var Description = row.Description;
    var Price = row.Price;
    

    在窗体的标记中,这些值通过使用嵌入的代码在各个文本框中自动显示,如下所示:

    <input name="Name" type="text" size="50" value="@Name" />
    

    代码的这一部分显示要更新的产品记录。 显示记录后,用户可以编辑单个列。

    当用户通过单击“ 更新 ”按钮提交表单时,块中的代码将 if(IsPost) 运行。 这会从 Request 对象中获取用户的值,将值存储在变量中,并验证是否已填充每列。 如果验证通过,代码将创建以下 SQL Update 语句:

    UPDATE Product SET Name=@0, Description=@1, Price=@2, WHERE ID=@3
    

    在 SQL Update 语句中,指定要更新的每个列以及要将其设置为的值。 在此代码中,使用参数占位符 @0@1@2等指定值。 (如前所述,为了安全起想,应始终使用 parameters 将值传递给 SQL 语句。)

    调用 db.Execute 方法时,按与 SQL 语句中的参数相对应的顺序传递包含值的变量:

    db.Execute(updateQueryString, Name, Description, Price, ProductId);
    

    Update执行 语句后,调用以下方法,以便将用户重定向回编辑页:

    Response.Redirect(@Href("~/EditProducts"));
    

    其效果是,用户会看到数据库中数据的更新列表,并且可以编辑另一个产品。

  6. 保存页。

  7. (更新页) 运行 EditProducts.cshtml 页,然后单击“ 编辑 ”选择要编辑的产品。 将显示 UpdateProducts.cshtml 页面,其中显示了所选记录。

    [屏幕截图显示“更新产品”页以及所选记录。]

  8. 进行更改,然后单击“ 更新”。 产品列表将再次显示更新的数据。

删除数据库中的数据

本部分演示如何允许用户从 Product 数据库表中删除 产品 。 该示例由两个页面组成。 在第一页中,用户选择要删除的记录。 然后,要删除的记录将显示在第二页中,以便他们确认要删除该记录。

注意

重要 在生产网站中,通常限制允许对数据进行更改的人员。 有关如何设置成员身份以及授权用户在网站上执行任务的方法的信息,请参阅向 ASP.NET 网页网站添加安全性和成员身份

  1. 在网站中,创建名为 ListProductsForDelete.cshtml 的新 CSHTML 文件。

  2. 将现有标记替换为以下内容:

    @{
      var db = Database.Open("SmallBakery");
      var selectQueryString = "SELECT * FROM Product ORDER BY Name";
    }
    <!DOCTYPE html>
    <html>
    <head>
        <title>Delete a Product</title>
        <style>
            table, th, td {
              border: solid 1px #bbbbbb;
              border-collapse: collapse;
              padding: 2px;
            }
         </style>
    </head>
    <body>
      <h1>Delete a Product</h1>
      <form method="post" action="" name="form">
        <table border="1">
          <thead>
            <tr>
              <th>&nbsp;</th>
              <th>Name</th>
              <th>Description</th>
              <th>Price</th>
            </tr>
          </thead>
          <tbody>
            @foreach (var row in db.Query(selectQueryString)) {
              <tr>
                <td><a href="@Href("~/DeleteProduct", row.Id)">Delete</a></td>
                <td>@row.Name</td>
                <td>@row.Description</td>
                <td>@row.Price</td>
              </tr>
            }
          </tbody>
        </table>
      </form>
    </body>
    </html>
    

    此页面类似于之前的 EditProducts.cshtml 页面。 但是,它不显示每个产品的 “编辑” 链接,而是显示 “删除” 链接。 使用标记中的以下嵌入代码创建 “删除” 链接:

    <a href="@Href("~/DeleteProduct", row.Id)">Delete</a>
    

    这会在用户单击链接时创建如下所示的 URL:

    http://<server>/DeleteProduct/4

    URL 调用名为 DeleteProduct.cshtml 的页面 (你将创建) ,并向其传递产品 ID 以在此处删除 (4) 。

  3. 保存文件,但保持打开状态。

  4. 创建另一个名为 DeleteProduct.cshtml 的 CHTML 文件。 将现有内容替换为以下内容:

    @{
      var db = Database.Open("SmallBakery");
      var ProductId = UrlData[0];
      if (ProductId.IsEmpty()) {
        Response.Redirect("~/ListProductsForDelete");
      }
      var prod = db.QuerySingle("SELECT * FROM PRODUCT WHERE ID = @0", ProductId);
      if( IsPost && !ProductId.IsEmpty()) {
        var deleteQueryString = "DELETE FROM Product WHERE Id=@0";
        db.Execute(deleteQueryString, ProductId);
        Response.Redirect("~/ListProductsForDelete");
      }
    }
    
    <!DOCTYPE html>
    <html>
    <head>
        <title>Delete Product</title>
    </head>
    <body>
      <h1>Delete Product - Confirmation</h1>
      <form method="post" action="" name="form">
        <p>Are you sure you want to delete the following product?</p>
    
        <p>Name: @prod.Name <br />
           Description: @prod.Description <br />
           Price: @prod.Price</p>
        <p><input type="submit" value="Delete" /></p>
      </form>
    </body>
    </html>
    

    此页由 ListProductsForDelete.cshtml 调用,允许用户确认要删除产品。 若要列出要删除的产品,请使用以下代码从 URL 获取要删除的产品的 ID:

    var ProductId = UrlData[0];
    

    然后,该页面会要求用户单击按钮以实际删除记录。 这是一个重要的安全措施:在网站中执行敏感操作(如更新或删除数据)时,应始终使用 POST 操作(而不是 GET 操作)完成这些操作。 如果站点已设置为可以使用 GET 操作执行删除操作,则任何人都可以传递类似 URL http://<server>/DeleteProduct/4 ,并从数据库中删除所需的任何内容。 通过添加确认和对页面进行编码,以便只能使用 POST 执行删除,可以向网站添加安全措施。

    实际删除操作使用以下代码执行,该代码首先确认这是一个后操作,并且 ID 不为空:

    if( IsPost && !ProductId.IsEmpty()) {
        var deleteQueryString = "DELETE FROM Product WHERE Id=@0";
        db.Execute(deleteQueryString, ProductId);
        Response.Redirect("~/ListProductsForDelete");
    }
    

    该代码运行一个 SQL 语句,该语句删除指定的记录,然后将用户重定向回列表页。

  5. 在浏览器中运行 ListProductsForDelete.cshtml

    [屏幕截图显示了在浏览器中运行用于 delete dot CSHTML 的列表产品。]

  6. 单击其中一个产品的 “删除” 链接。 将显示 DeleteProduct.cshtml 页以确认要删除该记录。

  7. 单击“删除” 按钮。 删除产品记录,并使用更新的产品列表刷新页面。

提示

连接到数据库

可以通过两种方式连接到数据库。 第一种方法是使用 Database.Open 方法,并指定数据库文件的名称, (少 .sdf 扩展名) :

var db = Database.Open("SmallBakery");

方法 Open 假定 为 。sdf 文件位于网站的 App_Data 文件夹中。 此文件夹专为保存数据而设计。 例如,它具有允许网站读取和写入数据的相应权限,作为安全措施,WebMatrix 不允许访问此文件夹中的文件。

第二种方法是使用连接字符串。 连接字符串包含数据库连接方式的相关信息。 这可以包括文件路径,也可以包括本地或远程服务器上的SQL Server数据库的名称,以及用于连接到该服务器的用户名和密码。 (如果将数据保存在集中管理的SQL Server版本(例如托管提供程序的站点上),则始终使用连接字符串来指定数据库连接信息。)

在 WebMatrix 中,连接字符串通常存储在名为 Web.config的 XML 文件中。顾名思义,可以使用网站根目录中的 Web.config 文件来存储站点的配置信息,包括站点可能需要的任何连接字符串。 Web.config 文件中的连接字符串示例可能如下所示。 注意 $CREDENTIAL_PLACEHOLDER$ 是密码键/值对的占位符:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <connectionStrings>
   <add
     name="SQLServerConnectionString"
     connectionString= "server=myServer;database=myDatabase;uid=username;$CREDENTIAL_PLACEHOLDER$"
     providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

在示例中,连接字符串指向SQL Server实例中的数据库,该实例在 (某处的服务器上运行,而不是本地 .sdf 文件) 。 需要替换 和 myDatabase的相应名称myServer,并为 和 password指定SQL Server登录值username。 (用户名和密码值不一定与你的 Windows 凭据相同,也不一定与托管提供商提供给你用于登录其服务器的值相同。请与管理员核实所需的确切值。)

方法 Database.Open 非常灵活,因为它允许传递数据库 .sdf 文件的名称或存储在 Web.config 文件中的连接字符串的名称。 以下示例演示如何使用上一示例中所示的连接字符串连接到数据库:

@{
    var db = Database.Open("SQLServerConnectionString");
}

如前所述, Database.Open 方法允许传递数据库名称或连接字符串,并找出要使用的名称。 在部署 (发布) 网站时,这非常有用。 开发和测试站点时,可以使用 App_Data 文件夹中的 .sdf 文件。 然后,将站点移动到生产服务器时,可以在 Web.config 文件中使用与 .sdf 文件同名但指向托管提供程序的数据库的连接字符串,而无需更改代码。

最后,如果要直接使用连接字符串,可以调用 Database.OpenConnectionString 方法,并将实际连接字符串传递给它,而不只是 Web.config 文件中一个连接字符串的名称。 如果出于某种原因无法访问连接字符串 (或其中的值,例如在页面运行之前) .sdf 文件名,这可能很有用。 但是,对于大多数方案,可以使用 Database.Open 本文中所述。

其他资源