ASP.NET2.0 ObjectDataSource的使用详解(2)

4 绑定到业务逻辑

在上面 GetProduct 的定义时,可以看到该方法返回的类型是 SqlDataReader ,由于 ObjectDataSource 将来需要作为绑定控件的数据来源,所以它的返回类型必须如下的返回类型之一:

Ienumerable DataTable DataView DataSet 或者 Object

为了更好的进行业务处理,我们需要更进一步的封装业务逻辑,以便返回强类型。接下来我们定义一个 Product 类来封装数据库,具体由 Product.cs 实现并放置在 App_Code 目录,代码如下

using System;

public class Product

{

    protected int _productID;

    protected String _productName;

    protected int _categoryID;

    protected decimal _price;

    protected int _inStore;

    protected String _description;

 

    public int ProductID

    {

        get { return _productID; }

        set { _productID = value; }

   

    }

 

    public String ProductName

    {

        get { return _productName; }

        set { _productName = value; }

    }

 

    public int CategoryID

    {

        get { return _categoryID; }

        set { _categoryID = value; }

    }

 

    public decimal Price

    {

        get { return _price; }

        set { _price = value; }

    }

 

    public int InStore

    {

        get { return _inStore; }

        set { _inStore = value; }

    }

    public String Description

    {

        get { return _description; }

        set { _description = value; }

    }

 

    public Product()

    { }

 

    public Product(int productID, string productName, int categoryID, decimal price, int instore, string description)

    {

        this._productID = productID;

        this._productName = productName;

        this._categoryID = categoryID;

        this._price = price;

        this._inStore = instore;

        this._description = description;

    }

}

           代码 2-12 Product.cs 源代码



然后在业务处理里定义
ProductDB.cs 类来进行处理,代码如下

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Configuration;

using System.Data;

using System.Data.Common;

using System.Data.SqlClient;

using System.Web;

 

/// <summary>

/// Summary description for ProductDB

/// </summary>

public class ProductDB

{

   public ProductDB()

   {}

 

    public List<Product> LoadAllProduct()

    {

        List<Product> products = new List<Product>();

        SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);

 

        string commandText = "select * from Products";

        SqlCommand command = new SqlCommand(commandText, conn);

        conn.Open();

        SqlDataReader dr = command.ExecuteReader();

        while (dr.Read())

        {

            Product prod = new Product();

            prod.ProductID = (int)dr["ProductID"];

            prod.ProductName = (string)dr["ProductName"];

            prod.CategoryID = (int)dr["CategoryID"];

            prod.Price = (decimal)dr["price"];

            prod.InStore = (Int16)dr["InStore"];

            prod.Description = (String)dr["Description"];

            products.Add(prod);

        }

        dr.Close();

        conn.Close();

      return products;

    }

 

 

    public void UpdateProduct(Product pro)

    {

        SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);

        SqlCommand updatecmd = new SqlCommand("UPDATE Products set ProductName=@ProductName,CategoryID=@CategoryID,Price=@Price,InStore=@InStore,Description=@Description where ProductID=@ProductID", conn);

        updatecmd.Parameters.Add(new SqlParameter("@ProductName", pro.ProductName));

        updatecmd.Parameters.Add(new SqlParameter("CategoryID", pro.CategoryID));

        updatecmd.Parameters.Add(new SqlParameter("@Price", pro.Price));

        updatecmd.Parameters.Add(new SqlParameter("@InStore", pro.InStore));

        updatecmd.Parameters.Add(new SqlParameter("@Description", pro.Description));

        updatecmd.Parameters.Add(new SqlParameter("@ProductID",pro.ProductID));

        conn.Open();

        updatecmd.ExecuteNonQuery();

        conn.Close();

    }

 

    public void DeleteProduct(Product pro)

    {

 

        SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);

        SqlCommand delcmd = new SqlCommand("delete from Products where ProductID=@ProductID", conn);

        delcmd.Parameters.Add(new SqlParameter("@ProductID", pro.ProductID));

        conn.Open();

        delcmd.ExecuteNonQuery();

        conn.Close();

    }

}

     代码 2-13 ProductDB.cs 源代码

在这段代码里使用了泛型,所以需要导入 System.Collections.Generic; 命名空间,编辑和删除传递的参数是 Product 类型。另外在 Command 命令参数的加入方式上使用的是 Add ,读者也可以想上面一样使用 AddWithValue 方法。

  然后建立 DB_ObjectDataSource.aspx 页面,下面列出了 ObjectDataSource 设置如 2-14

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="LoadAllProduct"

              DataObjectTypeName="Product" TypeName="ProductDB" DeleteMethod="DeleteProduct" UpdateMethod="UpdateProduct"></asp:ObjectDataSource>

    代码 2-14 DB_ObjectDataSource.aspx 部分代码

在这段代码里使用了 DataObjectTypeName 属性,并将改值设置为 Product 类。运行结果和图 3-34 一样。

 

5 DataKeyNames OldValuesParameterFormatString

1 DataKeyNames

如果读者使用 Simple_ObjectDataSource.aspx ,可以发现如果没有设置 GridView DataKeynames 属性,则无法更新或者删除操作。

Update Delete 操作中扮演特殊角色的一个重要属性是 DataKeyNames 属性。此属性通常被设置为数据源中字段的名称,这些字段是用于匹配该数据源中的给定行的主键的一部分。当以声明方式指定此属性时,多个键之间用逗号分隔,尽管通常情况下只有一个主键字段。

为了保留原始值以传递给 Update Delete 操作, DataKeyNames 属性指定的字段的值在视图状态中往返,即使该字段并未作为 GridView 控件中的列之一被呈现。当 GridView 调用数据源 Update Delete 操作时,它在一个特殊的 Keys 字典中将这些字段的值传递给数据源,该字典独立于包含用户在行处于编辑模式时(对于更新操作)输入的新值的 Values 字典。 Values 字典的内容是从为处于编辑模式的行呈现的输入控件中获得的。

例如,假设数据库里由如下一条记录

ProductID     ProductName   CategoryID     Price         InStore      Description

24             生物技术           7             9.0000          2             生物技术丛书

为了进行数据传递,在实际执行该行的编辑时, ASP.NET 框架将以 Key/Value 字典的形式进行存储的,这里我们将它写成如下的方式以便理解:

key                     value

{"@ProductID"   ,           "24"     }

{"@ProductName",          " 生物技术 "}

{"@CategoryID",            "7"      }

{"@price",                   "9.0000"}

{"@InStore",                "2"       }

{"@Description",             " 生物技术丛书 "}

然而我们知道在数据库里 productID 是递增的主键,所以在实际更新中,该行并不需要进行更新,若要排除此字典中的该字段,我们可以在 GridView 的绑定列中设置该列为只读。当将 Columns 集合中的对应 BoundField ReadOnly 属性设置为 true 时,该字段将不会在 key/value 里传递。另一方面还请注意,默认的如果在 Visual Studio 中使用 GridView 设计器,主键字段的 ReadOnly 属性会自动设置为 true

由于我们在前面的演示里已经将 ProductID 设置为已经将 ProductID 设置为 ReadOnly true ,自然的传递到 UpdateProduct Key/Value 的值为:

{"@ProductName",          " 生物技术 "}

{"@CategoryID",            "7"      }

{"@price",                   "9.0000"}

{"@InStore",                "2"       }

{"@Description",             " 生物技术丛书 "}

这里可以看到没有了 @ProductID 列,那么系统如何知道你当前编辑的 ProductID 呢?这个功能就是由 DataKeyNames 来完成。原来当您将 GridView DataKeyNames 设置为 ProductID 时,该列在更新时会自动调用 ProductID 的数值。

 

在删除方法 DeleteProduct 里,如果您设置断点查看 pro 的值,您会发现在删除产品里仅仅传递 DataKeyname 的值(也就是仅仅传递 ProductID ),而并不传递 ProductName CategoryID 等的值,所以您会发现,对于编辑我定义的方式是:

public Product(int productID, string productName, int categoryID, decimal price, int instore, string description)

对于删除,我定义的方式是

public   void DeleteProduct(int ProductId)

就是这个原因。

 

2 OldValuesParameterFormatString

在使用前面的例子里,请注意分配给 UpdateCommand Update 语句中的参数的命名约定。 Update Delete 的参数都采用默认的列命名方式,例如 ProductDAL.cs 里的 DeleteProduct 定义如下:

public   void DeleteProduct(int ProductId)

        {

            SqlConnection con = new SqlConnection(_connectionString);

             string deleteString = "DELETE FROM  Products  WHERE ProductID=@ProductID";

            SqlCommand cmd = new SqlCommand(deleteString, con);

            cmd.Parameters.AddWithValue("@ProductID", ProductId);

            con.Open();

            cmd.ExecuteNonQuery();

            con.Close();

        }

  如果你想更改列的名称,例如更改 DeleteProduct 如下

public   void DeleteProduct(int old_ProductId)

       {

           SqlConnection con = new SqlConnection(_connectionString);

           string deleteString = "DELETE FROM  Products  WHERE ProductID=@ProductID";

           SqlCommand cmd = new SqlCommand(deleteString, con);

           cmd.Parameters.AddWithValue("@ProductID", old_ProductId);

           con.Open();

           cmd.ExecuteNonQuery();

           con.Close();

       }

  那么你在运行时将出现错误如图2-34

 




                
2-34 参数不匹配错误

 

这是因为 GridView 和其他数据绑定控件调用 Update 操作的自动功能需依赖此命名约定才能工作。参数的命名预期应与 SelectCommand 返回的关联字段值相同。使用此命名约定使得数据绑定控件传递给数据源的值与 SQL Update 语句中的参数相对应成为可能。

此默认命名约定的使用假设 Keys Values 字典的内容相互排斥 -- 即用户能够在数据绑定控件处于编辑模式时更新的字段值的命名应该与用于匹配要更新的行的字段值(对于 SqlDataSource ,这些字段值在 WHERE 子句中)的命名不同。考虑这点的另一种方式是在 DataKeyNames 上设置的任何字段都应该设置为只读或在数据绑定控件中(例如在 GridView Columns 集合中)不可见。虽然键字段为只读的情况很普遍,但是存在一些有效的方案,其中您将希望能够更新同时还用于匹配要更新的数据行的字段。

例如,如果我们将 Products 数据库的 ProductID 列在设计表格结构时设置为 nvarchar ,它存放的是图书 ISDN 编号,该编号并不是递增的,因此在运行时,您可以更改 ProductID 的只,前提是主要不重复即可。

这样我们就需要将该 ProductID 列设置为 ReadOnly=”false” 以便允许编辑,另一方面,为了确认哪条记录被更新还需要传递该列的只到更新 / 删除方法,所以还需要将 DataKeyNames 设置为 ProductID

这样 GridView 将在 Keys 字典中传递该字段的旧值,而在 Values 字典中传递该字段的新值。仍以 UpdateProduct 为例,当将 ProductID ReadOnly 设置为 ”false” ,并且将 DataKeyNames 设置为 ProductID 后,对于前面介绍的这条记录

ProductID     ProductName   CategoryID     Price         InStore      Description

24             生物技术           7             9.0000          2             生物技术丛书

我想将 ProductID 更改为 ISBN001 ,此时传递给 UpdateProduct 的方法是:

key                     value

{"24 "   ,            "ISBN001"     }

{"@ProductName",          " 生物技术 "}

{"@CategoryID",            "7"      }

{"@price",                   "9.0000"}

{"@InStore",                "2"      }

{"@Description",             " 生物技术丛书 "}

我们之所以需要这两个值是因为,利用“ 24 ”我们需要获取该记录,利用“ ISBN001 ”我们需要知道将来要把 24 更新为什么值。因为这样我们就需要区分 Key value 的值。为了区别这两类值,需要在 SQL 语句中以不同的方式命名参数,例如:

<asp:SqlDataSource ID="SqlDataSource1" runat="server"

  ConnectionString="<%$ ConnectionStrings:ConnectionString %>"

  SelectCommand="SELECT [productid], [productname], [categoryID], [Price],[InStore],[Description] FROM [products]"

  UpdateCommand="UPDATE [products] SET [productid] = @productid, [productname] = @productname, [categoryid] = @categoryid, [price] = @price,description=@Description WHERE [productid] = @old_productid"

  DeleteCommand="DELETE FROM [products] WHERE [productid] = @ old_productid "/>

  OldValuesParameterFormatString="old_{0}"

在上面例子中,参数名称 @old_productid 用于引用 Key 字段的原始值 24 @productid 用于引用新 Value 字段的新值 ISBN001 。其中旧值和新值的命名是通过 OldValuesParameterFormatString 来完成

SqlDataSource OldValuesParameterFormatString 属性也被设置为有效的 .NET Framwork 格式字符串,以指示应该如何重命名 Keys 字典中的参数。当 SqlDataSource ConflictDetection 属性设置为 CompareAllValues 时,此格式字符串还应用于数据绑定控件传递的非键字段的旧值。对于 Delete 操作, SqlDataSource 默认仅应用 Keys 字典(不存在用于删除操作的新值),并使用 OldValuesParameterFormatString 属性的值格式化键参数名称。代码 2-14 FormatPara_ObjectDataSource.aspx 演示了上面的说明。

        <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" DeleteMethod="DeleteProduct"

            SelectMethod="GetProduct" TypeName="ProductDAL" UpdateMethod="UpdateProduct"

              OldValuesParameterFormatString="old_{0}">

             </asp:ObjectDataSource>

            

        &nbsp;&nbsp;

        <asp:GridView ID="GridView1" DataKeyNames="ProductID" runat="server" AutoGenerateDeleteButton="True"

            AutoGenerateEditButton="True" CellPadding="4" DataSourceID="ObjectDataSource1" AutoGenerateColumns="false"

            Font-Names="Verdana" Font-Size="XX-Small" ForeColor="#333333" GridLines="None"

            >

              <Columns>

                <asp:BoundField DataField="ProductID" HeaderText="ProductID" ReadOnly="True" SortExpression="ProductID"/>

                <asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" />

                <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" SortExpression="CategoryID" />

                <asp:BoundField DataField="Price" HeaderText="Price" SortExpression="Price" />

                <asp:BoundField DataField="InStore" HeaderText="InStore" SortExpression="InStore" />

                <asp:BoundField DataField="Description" HeaderText="Description" SortExpression="Description" />

                 </Columns>

          </asp:GridView>

  代码 2-14FormatPara_ObjectDataSource.aspx 部分源代码

  同时将 DeleteUpdate 方法改成代码 2-15

public   void DeleteProduct(int old_ProductId)

        {

            SqlConnection con = new SqlConnection(_connectionString);

            string deleteString = "DELETE FROM  Products  WHERE ProductID=@ProductID";

            SqlCommand cmd = new SqlCommand(deleteString, con);

            cmd.Parameters.AddWithValue("@ProductID", old_ProductId);

            con.Open();

            cmd.ExecuteNonQuery();

            con.Close();

         }

        代码 2-15 DeleteProduct 方法

上面代码的运行结果和图 2-33 一样。然而在使用上面代码时,可能有些人将 2-14 的代码写成如下的形式:

   <asp:ObjectDataSource ID="ObjectDataSource1" runat="server" DeleteMethod="DeleteProduct"

            SelectMethod="GetProduct" TypeName="ProductDAL" UpdateMethod="UpdateProduct"

              OldValuesParameterFormatString="old_{0}">

                     <DeleteParameters>

                <asp:Parameter Name="ProductId" Type="Int32" />

            </DeleteParameters>

             </asp:ObjectDataSource>

如果运行此段代码则出现错误如图 2-35 ,这是因为我们需要默认的参数 ProductID ,如果您显式设置则多此一举,系统认为你需要传递 ProductID old_Product 。如果真的要设置应该设置 old_Product ,也就是

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" DeleteMethod="DeleteProduct"

            SelectMethod="GetProduct" TypeName="ProductDAL" UpdateMethod="UpdateProduct"

              OldValuesParameterFormatString="old_{0}">

                     <DeleteParameters>

                <asp:Parameter Name="old_ProductId" Type="Int32" />

            </DeleteParameters>

             </asp:ObjectDataSource>

这种方法同样使用 UpdateMethod

 

 

 

 

2.3.5 冲突检测 ConflictDetection

正如在前面的主题中所提到的,数据绑定控件在单独的 Keys Values (新值)和 OldValues 字典中将值传递给数据源。默认情况下, SqlDataSource ObjectDataSource 忽略 OldValues 字典,仅应用 Keys Values 。这种行为由数据源的 ConflictDetection 属性确定,该属性默认设置为 OverwriteChanges OverwriteChanges 模式本质上意味着 仅为了更新或删除记录而匹配主键值 。这种行为意味着不管记录的基础值是否已更改,都要更新或删除该记录。通常,仅当行的值准确匹配最初选择的值时才允许 Update Delete 成功是更为适宜的。这样,如果另一个用户在从您选择行到更新该行这段时间内更新了该行,您的更新操作将会失败。

Products 表为例,数据库里 ProductID 24 的图书在库数量( InStore )是两本,如下

ProductID     ProductName   CategoryID     Price         InStore      Description

24             生物技术           7             9.0000          2             生物技术丛书

A B 两个员工分别负责图书的入库和出库。在某个时间, A 员工把新进的 5 本图书入库,所以它准备更改该记录在库数量为 7 本,而恰好同时有一读者购买了一本该书,员工 B 准备更新该记录在库为 1 本。在 A 员工正在更新而还没有更新的这段时间里, B 也进行了该记录的更新,这样即使 A 更新了图书为 7 本由于 B 接着会将在库图书更新为 1 本而发生逻辑上错误。为了解决这个问题可以利用“全值匹配”。

数据源通过将 ConflictDetection 属性设置为 CompareAllValues 来支持这种方法。在这种模式下,数据源向命令或方法应用 OldValues 参数,该命令或方法可以在更新或删除记录之前使用这些值确保更新或删除操作匹配该记录的所有这些值。还必须将 OldValuesParameterFormatString 属性设置为有效的 .NET Framework 格式字符串(例如 “lodl_{0}” ),以指示应该如何重命名 OldValues Keys 字典中的参数以将它们与 NewValues 进行区别。

下面的代码示例演示用于 SqlDataSource 控件的 OverwriteChanges CompareAllValues 模式的典型 SQL 命令。

  update   Products set ProductName=@ProductName,CategoryID=@CategoryID,

  Price=@Price,InStore=@InStore,Description=@Description 

   WHERE (productID = @original_ProductID

  AND   ProductName=@original_ProductName

  and CategoryID=@original_CategoryID

  and price=@original_price

  and InStore=@original_InStore

  and   description=@original_description)

代码 2-16 Conflict_ObjectDataSource.aspx 演示了这种功能的使用(注:为了便于理解,这里使用 SqlDataSource 进行说明)

<%@ Page Language="C#" %>

<script runat="server">

  protected void SqlDataSource1_Updated(object sender, SqlDataSourceStatusEventArgs e)

  {

    if (e.AffectedRows == 0)

      Response.Write(" 该行已经变更,您更新失败 <br />");

  }

  protected void SqlDataSource1_Deleted(object sender, SqlDataSourceStatusEventArgs e)

  {

    if (e.AffectedRows == 0)

      Response.Write(" 改行已经变更,您删除失败 <br />");

  }

</script>

<html xmlns="http://www.w3.org/1999/xhtml">

<head id="Head1" runat="server">

  <title>Optimistic Concurrency</title>

</head>

<body>

  <form id="form1" runat="server">

    <div>

      <asp:GridView AutoGenerateColumns="False" DataKeyNames="ProductID" DataSourceID="SqlDataSource1"

        ID="GridView1" runat="server" CellPadding="4" Font-Names="Verdana" Font-Size="XX-Small" ForeColor="#333333" GridLines="None">

        <Columns>

          <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />

          <asp:BoundField DataField="ProductID" HeaderText="ProductID" InsertVisible="False"

            ReadOnly="True" SortExpression="ProductID" />

             <asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" />

                 <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" SortExpression="CategoryID" />

                  <asp:BoundField DataField="Price" HeaderText="Price" SortExpression="Price" />

                 <asp:BoundField DataField="InStore" HeaderText="InStore" SortExpression="InStore" />

                 <asp:BoundField DataField="Description" HeaderText="Description" SortExpression="Description" />

        </Columns>

         … …

      </asp:GridView>

     

      <asp:SqlDataSource ConnectionString="<% $ ConnectionStrings:ConnectionString %> "

      ID="SqlDataSource1"

        ConflictDetection="CompareAllValues"

         OldValuesParameterFormatString="original_{0}"

         runat="server"

         SelectCommand="GetAllProducts"

        SelectCommandType="StoredProcedure"

         InsertCommand="InsertProduct"

        InsertCommandType="StoredProcedure"

        DeleteCommand="DeleteProduct"

        DeleteCommandType="StoredProcedure"

        UpdateCommand="UpdateProduct"

        UpdateCommandType="StoredProcedure"

        OnUpdated="SqlDataSource1_Updated"

        OnDeleted="SqlDataSource1_Deleted">

      

        <InsertParameters>

          <asp:Parameter Name="ProductName" Type="String" />

          <asp:Parameter Name="CategoryID" Type="Int32" />

          <asp:Parameter Name="Price" Type="decimal" />

          <asp:Parameter Name="InStore" Type="Int16"/>

          <asp:Parameter Name="Description" Type="String" />

          <asp:Parameter Direction="Output" Name="ProductID" Type="Int32" />

        </InsertParameters>

         <DeleteParameters>

         <asp:Parameter Name="original_ProductName" Type="String" />

          <asp:Parameter Name="original_CategoryID" Type="Int32" />

          <asp:Parameter Name="original_InStore" Type="Int16"/>

          <asp:Parameter Name="original_Description" Type="String" />

          <asp:Parameter Name="original_ProductID" Type="Int32" />

        </DeleteParameters>

        <UpdateParameters>

         <asp:Parameter Name="ProductName" Type="String" />

          <asp:Parameter Name="CategoryID" Type="Int32" />

          <asp:Parameter Name="Price" Type="decimal" />

          <asp:Parameter Name="InStore" Type="Int16"/>

          <asp:Parameter Name="Description" Type="String" />

          <asp:Parameter Name="original_ProductName" Type="String" />

          <asp:Parameter Name="original_CategoryID" Type="Int32" />

          <asp:Parameter Name="original_InStore" Type="Int16"/>

          <asp:Parameter Name="original_Description" Type="String" />

          <asp:Parameter Name="original_ProductID" Type="Int32" />

        </UpdateParameters>

      </asp:SqlDataSource>

      <br />

      <asp:DetailsView AutoGenerateRows="False" DataKeyNames="ProductID" DataSourceID="SqlDataSource1"

        DefaultMode="Insert" HeaderText=" 插入新产品 " Height="50px" ID="DetailsView1"

        runat="server" CellPadding="4" Font-Names="Verdana" Font-Size="XX-Small" ForeColor="#333333" GridLines="None" AutoGenerateInsertButton="True"  >

        <Fields>

          <asp:BoundField DataField="ProductID" HeaderText="ProductID" InsertVisible="False"

            ReadOnly="True" SortExpression="ProductID" />

          <asp:BoundField DataField="ProductName" HeaderText="ProductName" SortExpression="ProductName" />

           <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" SortExpression="CategoryID" />

           <asp:BoundField DataField="Price" HeaderText="Price" SortExpression="Price" />

             <asp:BoundField DataField="InStore" HeaderText="InStore" SortExpression="InStore" />

            <asp:BoundField DataField="Description" HeaderText="Description" SortExpression="Description" />

        </Fields>

       … …

      </asp:DetailsView>

    </div>

  </form>

</body>

</html>

   代码 2-16 Conflict_ObjectDataSource.aspx 的部分代码

在这段代码里, SqlDataSource UpdateCommand 被设置为存储过程,该存储过程的名称为 UpdateProduct ,具体代码如 2-17

ALTER PROCEDURE [UpdateProduct]

  (

  @ProductName varchar (50),

   @CategoryID int ,

   @Price decimal ,

   @InStore int ,

   @Description nvarchar (100),

   @original_ProductID int ,

   @original_ProductName varchar (50),

   @original_CategoryID int ,

   @original_Price decimal ,

   @original_InStore int ,

   @original_Description nvarchar (100))

AS

  update   Products set ProductName=@ProductName,CategoryID=@CategoryID,

  Price=@Price,InStore=@InStore,Description=@Description 

   WHERE (productID = @original_ProductID

  AND   ProductName=@original_ProductName

  and CategoryID=@original_CategoryID

  and price=@original_price

  and InStore=@original_InStore

  and   description=@original_description)

           代码 2-17 UpdateProduct 源代码

同样, DeleteCommand 也被设置为存储过程 , 该存储过程的代码加 2-18

ALTER PROCEDURE [DeleteProduct]

  (@original_ProductID int,

   @original_ProductName varchar(50),

   @original_CategoryID int,

   @original_Price decimal,

   @original_InStore int,

   @original_Description nvarchar(100))

AS

  DELETE FROM Products WHERE productID = @original_ProductID

  AND  ProductName=@original_ProductName

  and CategoryID=@original_CategoryID

  and price=@original_price

  and InStore=@original_InStore

  and  description=@original_description

           代码 2-18 DeleteProduct 源代码

SelectCommand 的存储过程为 GetAllProducts ,该语句较为简单如 2-19

ALTER PROCEDURE GetAllProducts

AS

  select * from Products

              代码 2-19 GetAllProducts 源代码

为了便于详细列举数据源控件的使用,我们使用了 DetailView 控件用于插入记录, InsertCommand 被设置为存储过程,代码如 2-20.

ALTER PROCEDURE [InsertProduct]

  (

   @CategoryID int,

   @Price decimal,

   @InStore int,

   @Description nvarchar(100),

   @ProductID int output

   )

AS

   INSERT INTO products (ProductName,CategoryID,Price,InStore,Description) VALUES

    (@ProductName,@CategoryID,@Price,@InStore,@Description)

  SELECT ProductID = @@IDENTITY

          代码 2-20 InsertProduct 源代码

 

若要运行此示例,请在单独的浏览器窗口中打开该示例的两个实例如图 2-36

 



2-36 准备编辑

 

然后对两个窗口中的相同行单击 “Edit” (编辑)按钮,以便将该行置于编辑模式。在第一个窗口中,更改某个行值并单击 “Update” (更新),并注意更新是成功的。在第二个窗口中,可以为相同行输入新值并单击 “Update” (更新),但是更新不会成功,这是因为基础行值被第一个更新操作更改了。该示例检测到 Updated Deleted 事件参数的 AffectedRows 属性为 0 ,从而确认发生了冲突。 2-37 一个窗口对数据进行更新

 

 

    另外,页面夏布有一个“输入产品”页面,可以利用该页面插入产品数据,如图 3-39 。在进行插入数据时,由于不会产生冲突,所以不用传递原 ProductID 等值。

代码下载


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值