在 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 for Web):但是,用户界面将有所不同。

数据库简介

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

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

ID 名字 姓氏 地址 电子邮件 电话
1 吉姆 Abrus 210 100th St SE Orcas WA 98031 jim@contoso.com 555 0100
2 泰 瑞 Adams 1234 Main St. Seattle 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 Matrix 打开了表设计器。]

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

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

  9. “主键”“标识” 选项设置为 “是”。

    顾名思义, “主键 ”告知数据库,这是表的主键。 Is Identity 告诉数据库为每个新记录自动创建 ID 列,并分配从 1 开始的下一个连续编号。

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

  11. 在 Name 值处输入“Name”。

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

  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
    Pecan Pie 如果你喜欢桃子,这是给你的。 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 标识要查询的表。 该 * 字符指定查询应返回表中的所有列。 (如果只想查看某些列,还可以单独列出列,用逗号分隔)。该 Order By 子句指示应如何按 Name 列对数据进行排序- 在本例中。 这意味着数据根据每行的 Name 列的值按字母顺序排序。

    在页面正文中,标记将创建一个 HTML 表,用于显示数据。 在 <tbody> 元素内,使用循环 foreach 单独获取查询返回的每个数据行。 对于每个数据行,将创建一个 HTML 表行(<tr> 元素)。 然后,为每个列创建 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 表中的记录中提取 ID名称和价格列,并根据 Name 列的值按字母顺序返回结果。 此命令将返回一个结果集,其中包含满足条件的记录;如果没有记录匹配,则返回空集。

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

这会将新记录插入Product表中,将Name列设置为“牛角面包”,将Description列设置为“酥脆的美味”,并将价格设置为1.99。

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

此命令删除“ 产品 ”表中的记录,其到期日期列早于 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 — 此 && 测试是 如果这是表单提交,并且所有字段都已通过验证。)

    验证所有列均非空后,请创建一个 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-errors 的 CSS 类定义。 这是默认情况下用于 <div> 包含任何验证错误的元素的 CSS 类的名称。 在这种情况下,CSS 类指定验证摘要错误以红色和粗体显示,但你可以定义 .validation-summary-errors 类以显示你喜欢的任何格式。

测试插入页

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

    [屏幕截图显示了将在浏览器页面中呈现的表单。]

  2. 输入所有列的值,但请确保将 Price 列留空。

  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等等指定值。 (如前所述,出于安全性,应始终使用参数将值传递给 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 操作执行删除操作,那么任何人都可通过传递类似 http://<server>/DeleteProduct/4 的 URL 来删除数据库中的任何内容。 通过添加确认和编码页面,以便只能使用 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.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 文件)上运行。 您需要替换myServermyDatabase为相应的名称,并为usernamepassword指定 SQL Server 登录值。 (用户名和密码值不一定与 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

其他资源