作者 :斯科特·米切尔
了解如何在单个操作中更新多个数据库记录。 在用户界面层中,我们生成一个 GridView,其中每一行都是可编辑的。 在数据访问层中,我们会在事务中包装多个更新操作,以确保所有更新都成功或回滚所有更新。
介绍
在 前面的教程 中,我们了解了如何扩展数据访问层,以添加对数据库事务的支持。 数据库事务保证将一系列数据修改语句视为一个原子操作,这可确保所有修改都将失败或全部成功。 有了这种低级别 DAL 功能,我们就可以开始关注如何创建批处理数据修改接口。
在本教程中,我们将生成一个 GridView,其中每一行都是可编辑的(请参阅图 1)。 由于每一行都呈现在其编辑界面中,因此无需一列“编辑”、“更新”和“取消”按钮。 相反,页面上有两个“更新产品”按钮,单击后,枚举 GridView 行并更新数据库。
图 1:GridView 中的每个行都是可编辑的(单击可查看全尺寸图像)
让我们开始吧!
注释
在 “执行批处理更新 ”教程中,我们使用 DataList 控件创建了批处理编辑界面。 本教程与前面使用的 GridView 不同,批处理更新是在事务范围内执行的。 完成本教程后,建议返回到前面的教程,并更新它以使用前面教程中添加的数据库事务相关功能。
检查使所有 GridView 行可编辑的步骤
如“插入、更新和删除数据概述”教程中所述,GridView 提供基于每行编辑其基础数据的内置支持。 在内部,GridView 会记录通过其 EditIndex
属性可编辑的行。 当 GridView 绑定到其数据源时,它会检查每一行,以查看该行的索引是否等于其值 EditIndex
。 如果是这样,则使用行的编辑接口呈现该行的字段。 对于 BoundFields,编辑接口是一个 TextBox,其 Text
属性被分配给 BoundField s DataField
属性指定的数据字段的值。 对于 TemplateFields, EditItemTemplate
将使用模板字段代替 ItemTemplate
。
回想一下,当用户单击行的“编辑”按钮时,编辑工作流将启动。 这会导致回发,将 GridView 属性 EditIndex
设置为单击的行索引,并将数据重新绑定到网格。 当单击行“取消”按钮时,在回发时,该 EditIndex
按钮将设置为一个值 -1
,然后再将数据重新绑定到网格。 由于 GridView 的行从零开始编制索引,所以设置为EditIndex
-1
具有以只读模式显示 GridView 的效果。
该 EditIndex
属性适用于每行编辑,但不适用于批处理编辑。 若要使整个 GridView 可编辑,我们需要使用其编辑界面让每一行呈现。 实现此目的的最简单方法是创建每个可编辑字段作为 TemplateField 实现的位置,并在其中定义了 ItemTemplate
其编辑界面。
在接下来的几个步骤中,我们将创建一个完全可编辑的 GridView。 在步骤 1 中,首先创建 GridView 及其 ObjectDataSource,并将其 BoundFields 和 CheckBoxField 转换为 TemplateFields。 在步骤 2 和步骤 3 中,我们将编辑接口从 TemplateFields EditItemTemplate
移动到其 ItemTemplate
S。
步骤 1:显示产品信息
在担心创建可编辑行的 GridView 之前,让我们首先只显示产品信息。
BatchUpdate.aspx
打开文件夹中的页面BatchData
,并将 GridView 从工具箱拖到设计器上。 将 GridView 的ID
设置为ProductsGrid
,并从其智能标记中选择将其绑定到名为ProductsDataSource
的新 ObjectDataSource。 配置 ObjectDataSource 以从 ProductsBLL
类 s GetProducts
方法检索其数据。
图 2:将 ObjectDataSource 配置为使用 ProductsBLL
类(单击以查看全尺寸图像)
图 3:使用 GetProducts
方法检索产品数据(单击以查看全尺寸图像)
与 GridView 一样,ObjectDataSource 的修改功能旨在按行工作。 为了更新一组记录,我们需要在 ASP.NET 页的代码隐藏类中编写一些代码,该类对数据进行批处理并将其传递给 BLL。 因此,将 ObjectDataSource 的 UPDATE、INSERT 和 DELETE 选项卡中的下拉列表设置为 (None)。 单击“完成”以完成向导。
图 4:将 UPDATE、INSERT 和 DELETE 选项卡中的“Drop-Down 列表”设置为“无”(单击可查看全尺寸图像)
完成“配置数据源”向导后,ObjectDataSource 的声明性标记应如下所示:
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
完成“配置数据源”向导还会导致 Visual Studio 为 GridView 中的产品数据字段创建 BoundFields 和 CheckBoxField。 在本教程中,我们仅允许用户查看和编辑产品名称、类别、价格和已停用状态。 删除除“ProductName
CategoryName
产品”、“类别”和UnitPrice
“价格”这三个字段的Discontinued
所有其他字段,并将前三个字段的属性分别重命名HeaderText
为“产品”、“类别”和“价格”。 最后,选中 GridView 智能标记中的“启用分页”和“启用排序”复选框。
此时,GridView 有三个 BoundFields (ProductName
和CategoryName
UnitPrice
) 和 CheckBoxField (Discontinued
)。 我们需要将这四个字段转换为 TemplateFields,然后将编辑界面从 TemplateField s EditItemTemplate
移动到其 ItemTemplate
。
注释
我们在自定义数据修改接口教程中探讨了如何创建和自定义 TemplateFields。 我们将逐步完成将 BoundFields 和 CheckBoxField 转换为 TemplateFields 并在模板 ItemTemplate
字段中定义其编辑接口的步骤,但如果遇到问题或需要刷新,请毫不犹豫地参考前面的教程。
在 GridView 智能标记中,单击“编辑列”链接以打开“字段”对话框。 接下来,选择每个字段,然后单击“将此字段转换为 TemplateField”链接。
图 5:将现有 BoundFields 和 CheckBoxField 转换为 TemplateField
现在,每个字段都是 TemplateField,我们便可以将编辑界面从 EditItemTemplate
s 移动到 ItemTemplate
s。
步骤 2:创建ProductName
和UnitPrice
Discontinued
编辑接口
ProductName
创建、UnitPrice
编辑Discontinued
接口是此步骤的主题,而且非常简单,因为模板字段中EditItemTemplate
已经定义了每个接口。
CategoryName
创建编辑界面有点复杂,因为我们需要创建适用类别的 DropDownList。 此 CategoryName
编辑界面在步骤 3 中处理。
让我们从 TemplateField 开始 ProductName
。 单击 GridView 智能标记中的“编辑模板”链接,向下钻取到 ProductName
TemplateFields EditItemTemplate
。 选择 TextBox,将其复制到剪贴板,然后将其粘贴到 ProductName
TemplateField s ItemTemplate
。 将 TextBox s ID
属性更改为 ProductName
.
接下来,将 RequiredFieldValidator 添加到 ItemTemplate
以确保用户为每个产品名称提供值。 将 ControlToValidate
属性设置为 ProductName,属性 ErrorMessage
必须提供产品名称。
Text
和属性到 *。 添加 ItemTemplate
这些内容后,屏幕应类似于图 6。
图 6: ProductName
TemplateField 现在包括一个 TextBox 和 RequiredFieldValidator(单击以查看全尺寸图像)
UnitPrice
对于编辑界面,请首先从 TextBox 复制到 EditItemTemplate
。ItemTemplate
接下来,将 $置于 TextBox 前面,并将其 ID
属性设置为 UnitPrice,并将其 Columns
属性设置为 8。
此外, UnitPrice
将 CompareValidator 添加到 s ItemTemplate
,以确保用户输入的值是大于或等于 $0.00 的有效货币值。 将验证程序的属性 ControlToValidate
设置为 UnitPrice,其 ErrorMessage
属性必须输入有效的货币值。 请省略任何货币符号。它的Text
属性为 *,其属性到Type
,其Currency
属性到Operator
,其GreaterThanEqual
ValueToCompare
属性为 0。
图 7:添加 CompareValidator 以确保输入的价格是非负货币值(单击以查看全尺寸图像)
Discontinued
对于 TemplateField,可以使用已在中ItemTemplate
定义的 CheckBox。 只需将其 ID
设置为“已停止”,其 Enabled
属性设置为 true
..
步骤 3:创建CategoryName
编辑界面
TemplateField 中的编辑界面CategoryName
包含一个 TextBox,用于显示数据字段的值EditItemTemplate
。CategoryName
我们需要将其替换为列出可能类别的 DropDownList。
注释
自定义数据修改接口教程包含更全面、更完整的讨论,介绍如何自定义模板以包含 DropDownList 而不是 TextBox。 虽然此处的步骤已完成,但它们呈现得非常顺利。 若要更深入地了解如何创建和配置类别 DropDownList,请参阅 自定义数据修改接口 教程。
将一个 DropDownList 从工具箱拖到 CategoryName
TemplateField s 上 ItemTemplate
,将其 ID
设置为 Categories
。 此时,我们通常会通过其智能标记定义 DropDownLists 数据源,从而创建新的 ObjectDataSource。 但是,这会在内 ItemTemplate
添加 ObjectDataSource,这将导致为每个 GridView 行创建 ObjectDataSource 实例。 相反,让我们在 GridView s TemplateFields 外部创建 ObjectDataSource。 结束模板编辑并将 ObjectDataSource 从工具箱拖动到 ObjectDataSource 下的 ProductsDataSource
设计器上。 命名新的 ObjectDataSource CategoriesDataSource
并将其配置为使用 CategoriesBLL
类的方法 GetCategories
。
图 8:将 ObjectDataSource 配置为使用 CategoriesBLL
类(单击以查看全尺寸图像)
图 9:使用 GetCategories
方法检索类别数据(单击以查看全尺寸图像)
由于此 ObjectDataSource 仅用于检索数据,因此请将 UPDATE 和 DELETE 选项卡中的下拉列表设置为 “无”。 单击“完成”以完成向导。
图 10:将“更新”和“删除”选项卡中的下拉列表设置为“无”(单击以查看全尺寸图像)
完成向导后, CategoriesDataSource
声明性标记应如下所示:
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
创建并配置后 CategoriesDataSource
,返回到 CategoryName
TemplateField s, ItemTemplate
并从 DropDownList 智能标记中单击“选择数据源”链接。 在数据源配置向导中,从第一个下拉列表中选择 CategoriesDataSource
该选项,并选择 CategoryName
用于显示和 CategoryID
作为值。
图 11:将 DropDownList CategoriesDataSource
绑定到 (单击可查看全尺寸图像)
此时 Categories
,DropDownList 列出了所有类别,但它尚未自动为绑定到 GridView 行的产品选择适当的类别。 为此,我们需要将 Categories
DropDownList s SelectedValue
设置为产品 CategoryID
值。 单击 DropDownList 智能标记中的“编辑 DataBindings”链接,并将 SelectedValue
属性与 CategoryID
数据字段相关联,如图 12 所示。
图 12:将 Product s CategoryID
值绑定到 DropDownList s SelectedValue
属性
最后一个问题是:如果产品未 CategoryID
指定值,则数据绑定语句 SelectedValue
将引发异常。 这是因为 DropDownList 仅包含类别的项,并且没有为具有 NULL
数据库值的 CategoryID
这些产品提供选项。 若要解决此问题,请将 DropDownList s 属性设置为 AppendDataBoundItems
DropDownList 并将true
新项添加到 DropDownList,省Value
略声明性语法中的属性。 也就是说,请确保 Categories
DropDownList 的声明性语法如下所示:
<asp:DropDownList ID="Categories" runat="server" AppendDataBoundItems="True"
DataSourceID="CategoriesDataSource" DataTextField="CategoryName"
DataValueField="CategoryID" SelectedValue='<%# Bind("CategoryID") %>'>
<asp:ListItem Value=">-- Select One --</asp:ListItem>
</asp:DropDownList>
请注意 ,“选择一个”属性<asp:ListItem Value="">
如何Value
显式设置为空字符串。
请参阅自定义数据修改接口教程,更深入地讨论为什么需要此附加 DropDownList 项来处理NULL
大小写,以及为什么将Value
属性分配给空字符串至关重要。
注释
此处存在潜在的性能和可伸缩性问题,值得一提。 由于每行都有一个 DropDownList,该 DropDownList 使用 CategoriesDataSource
其数据源, CategoriesBLL
因此每个页面访问的类 GetCategories
方法将调用 n 次,其中 n 是 GridView 中的行数。 这些 n 次调用会导致GetCategories
对数据库的 n 个查询。 通过在每请求缓存中缓存返回的类别或使用 SQL 缓存依赖项或基于时间非常短的到期时间,来降低对数据库的影响。
步骤 4:完成编辑界面
我们对 GridView 模板进行了许多更改,无需暂停即可查看进度。 花点时间通过浏览器查看进度。 如图 13 所示,每行都使用包含 ItemTemplate
单元格编辑界面的行呈现。
图 13:每个 GridView 行都是可编辑的(单击以查看全尺寸图像)
此时,我们应注意一些次要格式问题。 首先,请注意,该值 UnitPrice
包含四个小数点。 若要解决此问题,请返回到 UnitPrice
TemplateField s, ItemTemplate
并从 TextBox 智能标记中单击“编辑 DataBindings”链接。 接下来,指定属性 Text
的格式应为数字。
图 14:将 Text
属性格式化为数字
其次,让我们将复选框居中 Discontinued
(而不是左对齐)。 单击 GridView 智能标记中的“编辑列”,然后 Discontinued
从左下角的字段列表中选择 TemplateField。 向下 ItemStyle
钻取属性并将其 HorizontalAlign
设置为中心,如图 15 所示。
图 15:将 CheckBox 居中Discontinued
接下来,向页面添加 ValidationSummary 控件,并将其ShowMessageBox
属性true
设置为及其ShowSummary
属性。false
此外,添加按钮 Web 控件,单击时,将更新用户的更改。 具体而言,添加两个按钮 Web 控件,一个在 GridView 上方,一个在它下面,将这两个控件 Text
属性设置为更新产品。
由于 GridView 的编辑界面在其 TemplateFields 中 ItemTemplate
定义, EditItemTemplate
因此 s 是多余的,可以删除。
在进行上述格式更改、添加按钮控件和删除不必要的 EditItemTemplate
设置后,页面的声明性语法应如下所示:
<p>
<asp:Button ID="UpdateAllProducts1" runat="server" Text="Update Products" />
</p>
<p>
<asp:GridView ID="ProductsGrid" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ProductsDataSource"
AllowPaging="True" AllowSorting="True">
<Columns>
<asp:TemplateField HeaderText="Product" SortExpression="ProductName">
<ItemTemplate>
<asp:TextBox ID="ProductName" runat="server"
Text='<%# Bind("ProductName") %>'></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1"
ControlToValidate="ProductName"
ErrorMessage="You must provide the product's name."
runat="server">*</asp:RequiredFieldValidator>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Category"
SortExpression="CategoryName">
<ItemTemplate>
<asp:DropDownList ID="Categories" runat="server"
AppendDataBoundItems="True"
DataSourceID="CategoriesDataSource"
DataTextField="CategoryName"
DataValueField="CategoryID"
SelectedValue='<%# Bind("CategoryID") %>'>
<asp:ListItem>-- Select One --</asp:ListItem>
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Price"
SortExpression="UnitPrice">
<ItemTemplate>
$<asp:TextBox ID="UnitPrice" runat="server" Columns="8"
Text='<%# Bind("UnitPrice", "{0:N}") %>'></asp:TextBox>
<asp:CompareValidator ID="CompareValidator1" runat="server"
ControlToValidate="UnitPrice"
ErrorMessage="You must enter a valid currency value.
Please omit any currency symbols."
Operator="GreaterThanEqual" Type="Currency"
ValueToCompare="0">*</asp:CompareValidator>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
<ItemTemplate>
<asp:CheckBox ID="Discontinued" runat="server"
Checked='<%# Bind("Discontinued") %>' />
</ItemTemplate>
<ItemStyle HorizontalAlign="Center" />
</asp:TemplateField>
</Columns>
</asp:GridView>
</p>
<p>
<asp:Button ID="UpdateAllProducts2" runat="server" Text="Update Products" />
<asp:ObjectDataSource ID="ProductsDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
</asp:ObjectDataSource>
<asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
OldValuesParameterFormatString="original_{0}"
SelectMethod="GetCategories" TypeName="CategoriesBLL">
</asp:ObjectDataSource>
<asp:ValidationSummary ID="ValidationSummary1" runat="server"
ShowMessageBox="True" ShowSummary="False" />
</p>
图 16 显示了在添加按钮 Web 控件并更改格式设置后通过浏览器查看此页面。
图 16:页面现在包含两个更新产品按钮(单击以查看全尺寸图像)
步骤 5:更新产品
当用户访问此页面时,他们将进行修改,然后单击两个更新产品按钮之一。 此时,我们需要以某种方式将每一行的用户输入的值保存到一个 ProductsDataTable
实例中,然后将该值传递给 BLL 方法,然后将该 ProductsDataTable
实例传递给 DAL s UpdateWithTransaction
方法。 在UpdateWithTransaction
前面的教程中创建的方法可确保将更改批处理更新为原子操作。
创建名为 BatchUpdate.aspx.cs
的方法并添加以下代码:
private void BatchUpdate()
{
// Enumerate the GridView's Rows collection and create a ProductRow
ProductsBLL productsAPI = new ProductsBLL();
Northwind.ProductsDataTable products = productsAPI.GetProducts();
foreach (GridViewRow gvRow in ProductsGrid.Rows)
{
// Find the ProductsRow instance in products that maps to gvRow
int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
Northwind.ProductsRow product = products.FindByProductID(productID);
if (product != null)
{
// Programmatically access the form field elements in the
// current GridViewRow
TextBox productName = (TextBox)gvRow.FindControl("ProductName");
DropDownList categories =
(DropDownList)gvRow.FindControl("Categories");
TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
CheckBox discontinued =
(CheckBox)gvRow.FindControl("Discontinued");
// Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim();
if (categories.SelectedIndex == 0)
product.SetCategoryIDNull();
else
product.CategoryID = Convert.ToInt32(categories.SelectedValue);
if (unitPrice.Text.Trim().Length == 0)
product.SetUnitPriceNull();
else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
product.Discontinued = discontinued.Checked;
}
}
// Now have the BLL update the products data using a transaction
productsAPI.UpdateWithTransaction(products);
}
此方法首先通过调用 BLL 方法ProductsDataTable
将所有产品传回GetProducts
。 然后,它会枚举 ProductGrid
GridView 集合Rows
。 该 Rows
集合包含 GridViewRow
GridView 中显示的每一行的实例 。 由于我们每页最多显示 10 行,因此 GridView 集合 Rows
的项数不超过 10 个。
对于每一行,将从 ProductID
集合中抓取 DataKeys
,并从中选择相应的 ProductsRow
值 ProductsDataTable
。 以编程方式引用四个 TemplateField 输入控件及其分配给 ProductsRow
实例属性的值。 在每个 GridView 行的值都用于更新之后 ProductsDataTable
,它将传递给 BLL s UpdateWithTransaction
方法,正如我们在前面的教程中看到的那样,只需调用 DAL 方法 UpdateWithTransaction
。
本教程使用的批处理更新算法会更新与 GridView 中的 ProductsDataTable
行对应的每一行,而不考虑产品信息是否已更改。 虽然此类盲目更新通常不是性能问题,但如果正在审核数据库表的更改,它们可能会导致多余的记录。 回到“执行批处理更新”教程中,我们探索了一个包含 DataList 的批处理更新接口,并添加了仅更新用户实际修改的记录的代码。 如果需要,可以随意使用执行 Batch 更新 中的技术来更新本教程中的代码。
注释
通过智能标记将数据源绑定到 GridView 时,Visual Studio 会自动将数据源的主键值(s)分配给 GridView 属性 DataKeyNames
。 如果未按照步骤 1 中所述,通过 GridView 智能标记将 ObjectDataSource 绑定到 GridView,则需要将 GridView 属性DataKeyNames
手动设置为 ProductID,以便通过ProductID
集合访问DataKeys
每行的值。
中使用的 BatchUpdate
代码与 BLL 方法 UpdateProduct
中使用的代码类似,主要区别在于方法中 UpdateProduct
只有一个 ProductRow
实例从体系结构中检索。 分配该属性的代码ProductRow
在方法与循环UpdateProducts
中的foreach
代码之间BatchUpdate
是相同的,就像总体模式一样。
若要完成本教程,我们需要在 BatchUpdate
单击任一更新产品按钮时调用该方法。 为 Click
这两个 Button 控件的事件创建事件处理程序,并在事件处理程序中添加以下代码:
BatchUpdate();
ClientScript.RegisterStartupScript(this.GetType(), "message",
"alert('The products have been updated.');", true);
首先调用 BatchUpdate
。 接下来,ClientScript property
用于注入 JavaScript,以显示消息框,上面写着产品已更新。
花点时间测试此代码。 浏览 BatchUpdate.aspx
浏览器,编辑多行,然后单击其中一个“更新产品”按钮。 假设没有输入验证错误,应会看到一个消息框,用于读取产品已更新。 若要验证更新的原子性,请考虑添加一个随机 CHECK
约束,就像禁止 UnitPrice
1234.56 的值一样。 然后,编辑 BatchUpdate.aspx
一些记录,确保将产品 UnitPrice
值之一设置为禁止值(1234.56)。 单击“更新产品”时,该批处理操作期间的其他更改将回滚到其原始值时,这将导致错误。
替代BatchUpdate
方法
BatchUpdate
我们刚刚检查的方法从 BLL s 方法检索GetProducts
产品,然后仅更新显示在 GridView 中的记录。 如果 GridView 不使用分页,但如果这样做,则可能有数百、数千或数万个产品,但 GridView 中只有十行,则此方法是理想的方法。 在这种情况下,仅从数据库获取所有产品以修改其中 10 个产品并不理想。
对于这些类型的情况,请考虑改用以下 BatchUpdateAlternate
方法:
private void BatchUpdateAlternate()
{
// Enumerate the GridView's Rows collection and create a ProductRow
ProductsBLL productsAPI = new ProductsBLL();
Northwind.ProductsDataTable products = new Northwind.ProductsDataTable();
foreach (GridViewRow gvRow in ProductsGrid.Rows)
{
// Create a new ProductRow instance
int productID = Convert.ToInt32(ProductsGrid.DataKeys[gvRow.RowIndex].Value);
Northwind.ProductsDataTable currentProductDataTable =
productsAPI.GetProductByProductID(productID);
if (currentProductDataTable.Rows.Count > 0)
{
Northwind.ProductsRow product = currentProductDataTable[0];
// Programmatically access the form field elements in the
// current GridViewRow
TextBox productName = (TextBox)gvRow.FindControl("ProductName");
DropDownList categories =
(DropDownList)gvRow.FindControl("Categories");
TextBox unitPrice = (TextBox)gvRow.FindControl("UnitPrice");
CheckBox discontinued =
(CheckBox)gvRow.FindControl("Discontinued");
// Assign the user-entered values to the current ProductRow
product.ProductName = productName.Text.Trim();
if (categories.SelectedIndex == 0)
product.SetCategoryIDNull();
else
product.CategoryID = Convert.ToInt32(categories.SelectedValue);
if (unitPrice.Text.Trim().Length == 0)
product.SetUnitPriceNull();
else
product.UnitPrice = Convert.ToDecimal(unitPrice.Text);
product.Discontinued = discontinued.Checked;
// Import the ProductRow into the products DataTable
products.ImportRow(product);
}
}
// Now have the BLL update the products data using a transaction
productsAPI.UpdateProductsWithTransaction(products);
}
BatchMethodAlternate
首先创建一个名为 的新空 ProductsDataTable
名称 products
。 然后,它逐步执行 GridView 集合 Rows
,并针对每一行使用 BLL 方法 GetProductByProductID(productID)
获取特定产品信息。 检索到的ProductsRow
实例的属性更新方式与BatchUpdate
相同,但在更新该行后,它通过 DataTable 的ImportRow(DataRow)
方法被导入到products``ProductsDataTable
中。
foreach
循环完成后,products
包含 GridView 中每一行的一个ProductsRow
实例。 由于每个 ProductsRow
实例都已添加到 products
(而不是更新),因此如果我们盲目地将其 UpdateWithTransaction
传递给方法,则会 ProductsTableAdapter
尝试将每个记录插入数据库中。 相反,我们需要指定已修改每一行(未添加)。
这可以通过将新方法添加到名为 UpdateProductsWithTransaction
BLL 的 BLL 来实现。
UpdateProductsWithTransaction
如下所示,设置RowState
ProductsRow
传入的每个实例ProductsDataTable
Modified
,然后将该实例传递给 ProductsDataTable
DAL s UpdateWithTransaction
方法。
public int UpdateProductsWithTransaction(Northwind.ProductsDataTable products)
{
// Mark each product as Modified
products.AcceptChanges();
foreach (Northwind.ProductsRow product in products)
product.SetModified();
// Update the data via a transaction
return UpdateWithTransaction(products);
}
概要
GridView 提供每行内置编辑功能,但不支持创建完全可编辑的接口。 正如我们在本教程中看到的,此类接口是可能的,但需要一些工作。 若要创建可编辑每一行的 GridView,我们需要将 GridView 字段转换为 TemplateFields,并在其中定义编辑接口 ItemTemplate
。 此外,必须将“全部更新”类型的按钮 Web 控件添加到页面,与 GridView 分开。 这些 Buttons Click
事件处理程序需要枚举 GridView 集合 Rows
、将更改存储在 a ProductsDataTable
中,并将更新的信息传递到相应的 BLL 方法。
在下一教程中,我们将了解如何创建用于批量删除的接口。 具体而言,每个 GridView 行都将包含一个复选框,而不是“全部更新”类型按钮,我们将有“删除所选行”按钮。
快乐编程!
关于作者
斯科特·米切尔,七本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com 的创始人,自1998年以来一直在与Microsoft Web 技术合作。 斯科特担任独立顾问、教练和作家。 他的最新书是 《Sams Teach Yourself ASP.NET 2.0 in 24 Hours》。 可以通过 mitchell@4GuysFromRolla.com 联系到他。
特别致谢
本教程系列由许多有用的审阅者审阅。 本教程的主要审阅者是 Teresa Murphy 和 David Suru。 有兴趣查看即将发布的 MSDN 文章? 如果是这样,请给我写信。mitchell@4GuysFromRolla.com