在ASP.NET 2.0中操作数据之六十四:GridView批量添加

网络编程 2025-04-04 13:33www.168986.cn编程入门

批量数据操作一直是数据处理中的核心任务之一,尤其在处理大量数据时,批量操作显得尤为重要。在前两篇文章中,我们了批量更新和批量删除数据的方法,并强调了事务在保障数据完整性方面的关键作用。今天,我们将深入如何实现批量添加数据,并借助事务确保数据的完整性和准确性。

设想一个场景:我们接收到一批从东京发出的货物,包括六种不同的茶和咖啡。若用户在DetailsView控件中逐一输入产品信息,则面临着大量重复性的工作,且容易出错。为此,我们需要创建一个批添加界面,用户只需一次性选择供应商和类别,输入一系列产品的名称和单价,点击按钮即可将新产品添加到数据库。这一过程如图1所示。

接下来,我们将逐步构建这一批添加界面。

创建一个展示界面。这个界面包含两个区域:展示区域和添加区域。展示区域包含一个用于展示产品的GridView控件以及一个标题为“Process Product Shipment”的按钮。当点击该按钮时,展示界面将切换为一个批添加界面。再次点击“Add Products from Shipment”或“Cancel”按钮时,将返回展示页面。这一展示界面的设计如图2所示。

在BatchData文件夹中打开BatchInsert.aspx页面,进入设计模式。从工具箱中拖出一个Panel控件到页面,设置其ID为DisplayInterface。接着,拖入一个Button和GridView控件到Panel控件内。设置Button的ID为ProcessShipment,Text属性为“Process Product Shipment”。设置GridView的ID为ProductsGrid,并通过智能标签将其绑定到名为ProductsDataSource的ObjectDataSource。

为了从ProductsBLL class类获取产品数据以在GridView中展示,我们需要设置ObjectDataSource调用ProductsBLL class类的GetProducts方法。由于该GridView控件仅用于展示数据,因此在UPDATE、INSERT、DELETE标签中选择“(None)”。完成这些设置后,Visual Studio会自动添加一些BoundFields以及一个CheckBoxField。

在完成了展示界面的设计后,下一步是创建批添加界面,这将在后续的文章中详细介绍。为了保证数据的完整性和准确性,我们将使用事务来封装这些批量操作。通过事务,我们可以确保一系列的操作要么全部成功执行,要么全部不执行,从而避免数据在传输或处理过程中可能出现的不一致状态。

批量添加数据是数据处理中的一项重要任务,通过合理的设计和利用事务机制,我们可以高效、准确地处理大量数据,确保数据的完整性和准确性。在接下来的文章中,我们将继续如何创建批添加界面,并完成整个批量数据处理的流程。在优化网页界面的旅程中,我们专注于打造一个既实用又吸引人的产品展示界面。这个界面融合了先进的Web开发技术,旨在提供流畅的用户体验和高效的交互功能。以下是我们工作的成果展示和详细步骤。

我们设计了一个名为“DisplayInterface”的ASP.NET Panel控件,用于集中放置我们的主要控件。在这个Panel内,我们放置了一个用于处理产品发货的按钮“Process Product Shipment”,以及一个用于展示产品信息的GridView控件。这个GridView控件经过精心配置,只保留了关键的列信息,包括产品名称(ProductName)、类别(CategoryName)、供应商(SupplierName)、单价(UnitPrice)和是否停产(Discontinued)。我们对UnitPrice列进行了货币值定制,并对列进行了排序。GridView的智能标签启用了分页和排序功能,以提供更加灵活和便捷的用户体验。

我们的界面设计充分考虑了用户的交互体验。例如,用户可以轻松浏览产品列表,通过点击列标题进行排序,或者使用分页功能查看更多产品。这种设计不仅提高了用户的工作效率,也使得产品信息的展示更加清晰和直观。

接下来是后台代码部分,我们使用了ObjectDataSource控件来绑定GridView的数据源。这意味着我们的GridView将显示从“ProductsBLL”类中的“GetProducts”方法获取的产品数据。这是一个强大的功能,因为它允许我们在不改变前端代码的情况下更新后端数据。我们还设置了Panel控件的可见性属性,可以通过编程方式改变它,以显示或隐藏添加界面。

当我们完成这些基本步骤后,页面呈现了一个完整的展示界面,用户可以通过浏览器访问该页面。当页面加载时,用户会看到一个包含产品信息的GridView和一个用于处理发货的按钮。点击按钮不会立即触发任何动作,因为我们还没有编写相应的代码来处理这个按钮的点击事件。这是我们在接下来的步骤中要完成的任务之一。目前这个阶段的主要目标是创建一个清晰、直观且功能丰富的展示界面。为了实现这一点,我们采用了动态的数据绑定和丰富的UI元素来创建一个吸引人的用户界面。现在我们已经完成了一个功能强大的产品展示界面,用户可以通过这个界面查看和管理产品信息。接下来我们将继续开发添加和编辑产品的功能,以进一步完善这个系统。在这个过程中,我们将充分利用ASP.NET的技术优势,确保我们的系统既易于使用又高效可靠。在本文教程中,我们将为用户展示如何创建一个允许添加五个产品的界面。这些产品的特性在于它们的类别和供应商相同,但名称和单位价格各异。对于我们的网站——狼蚁网站,我们将进行SEO优化,在界面的Panel控件上实现这一功能。

从工具箱中拖出一个Panel控件到页面,为其设置ID为“DisplayInterface”。接着,我们需要对这个Panel控件进行一项关键设置:将其Visible属性设为false,同时清除其Height和Width属性值。我们将在后续步骤中添加代码来将Visible属性改为true。

值得注意的是,在设计器模式中,虽然可以使用工具箱的工具来添加

元素,但这样会自动添加一些我们不需要的样式属性。我更倾向于在源视图模式中添加HTML
元素。当完成类
的声明代码后,我喜欢切换到设计器模式,进一步添加Web控件并细致地设置其属性。

这个添加界面将用于展示产品的信息,用户可以在此进行产品的添加和管理操作。通过简单的操作,用户可以直观地看到产品的类别、供应商、名称和单位价格等信息,并进行相应的操作。这种设计使得产品管理更加便捷和高效。

我们注意到每个

元素都被赋予了明确的CSS class,以区分不同的功能区域。例如,放置名为supplier和category的DropDownLists控件的头部行被称为BatchInsertHeaderRow。与此包含产品名称和单价的TextBox控件的行则通过BatchInsertRow和BatchInsertAlternatingRow进行区分。这些特定的CSS样式已经在Styles.css文件中定义。

对于显示供应商的DropDownList控件,我们将其ID设置为Suppliers,并绑定到一个名为SuppliersDataSource的ObjectDataSource。这个数据源将调用SuppliersBLL class类的GetSuppliers方法。在配置过程中,我们选择了“(None)”选项并完成了设置向导。这意味着当用户在供应商下拉列表中选择一个选项时,实际上是在选择SupplierID的值,而显示的是CompanyName列。这个过程在图7和图8中详细展示。

类似地,我们设置了第二个DropDownList(用于类别选择),将其ID设为Categories,并绑定到名为CategoriesDataSource的ObjectDataSource。该数据源调用CategoriesBLL class类的GetCategories方法。用户在这个下拉列表中选择一个类别时,实际上是在选择CategoryID的值,显示的是CategoryName列。完成这些设置后,屏幕将呈现出图9所示的界面。

在网站的后台管理界面,我们需要对“狼蚁商城”的产品信息进行优化设置。在对应的表单中,我们注意到每行都有两个格子,分别标注着“name”和“price”。我们的任务是在这两个格子里分别放置一个TextBox控件。为了确保数据的唯一性和可识别性,我们需要为每个TextBox控件设置一个独特的ID。比如,对于第一行的产品名称和单价,我们将ID设置为“ProductName1”和“UnitPrice1”;对于第二行的产品名称和单价,我们将ID设置为“ProductName2”和“UnitPrice2”,以此类推。

接下来,我们要确保用户输入的价格是有效的。为了实现这一点,我们需要对每个价格TextBox添加一个CompareValidator控件。这个控件能够帮助我们验证用户输入的数据是否符合我们的要求。具体来说,我们将ControlToValidate属性设置为相应控件的ID值,确保验证的是正确的TextBox控件。我们将Operator属性设置为GreaterThanEqual,意味着价格必须大于或等于零。我们将ValueToCompare属性设置为“0”,作为比较的基准值。Type属性设置为Currency,确保输入的是货币值。

我们设置了Text属性和ErrorMessage属性。当验证成功时,Text属性为空;而当验证失败时,将显示一条错误消息:“价格必须大于或等于零。请注意不要包含任何货币符号。”这样用户可以清晰地知道他们的输入是否有效。

当您开始构建产品管理系统时,确保产品名称(ProductName)的输入是必需的。在用户完成产品名称(name)的输入后,我们只需通过编程验证用户是否也输入了该产品的单价(unit price)。这一验证流程将在第四步中实施。

在用户输入数据的过程中,如果输入值包含货币符号,CompareValidator控件将识别并报告无效数据。为了简化用户输入,我们可以在每个单价(unit price)的TextBox控件前添加一个“$”符号,提示用户在输入数据时忽略货币符号。

在InsertingInterface Panel控件中,添加一个ValidationSummary控件,并设置其ShowMessageBox属性为true,ShowSummary属性为false。这样的设置将确保,当用户输入一个无效的单价时,在相应的TextBox控件旁边会显示一个星号。ValidationSummary控件将弹出一个客户端消息框,显示相应的错误消息。

您的界面布局应与图10类似。

图10:界面现在包含显示产品名称和价格的TextBox控件

接下来,我们在底部添加“从发货添加产品”和“取消”两个按钮。从工具箱中拖出两个Button控件,分别放置在界面底部。将这两个按钮的ID设置为AddProducts和CancelButton,并将Text属性分别设置为“从发货添加产品”和“取消”。将CancelButton的CausesValidation属性设置为false,以便在取消操作时不会触发验证。

我们还需要添加一个Label Web控件,用于显示与这两个界面相关的状态信息。例如,当用户成功添加一批产品时,我们希望切换到展示界面并显示确认消息。如果用户只提供了价格而没有提供产品名称的信息,我们需要通过Label控件显示警告信息,强调产品名称是必需的。由于需要显示与这两个界面相关的信息,因此将这个Label控件放置在两个Panel控件的上方。

从工具箱中拖出一个Label控件,设置其ID为StatusLabel。清除其Text属性,并将Visible和EnableViewState属性设置为false。在之前的教程中,我们已经讨论过将EnableViewState属性设置为false的好处,这样我们可以通过编程方式改变Label控件的属性值,而在页面回传时恢复到默认状态。某些用户行为会触发状态信息的显示,而在页面回传时,状态信息会消失。为StatusLabel设置CssClass属性为“Warning”,这是我们在Styles.css文件中定义的CSS类名。

如图11所示,是在Panel控件上方放置了id为StatusLabel的Label控件的样子。

现在我们来到了第三步,即在展示界面和添加界面之间切换。到目前为止,我们已经完成了展示和添加界面的构建,但还有两项任务需要完成:一是在展示界面和添加界面之间切换;二是将产品添加到数据库。目前,展示界面是默认的可见界面,而添加界面是隐藏的。这是因为DisplayInterface Panel控件的Visible属性默认为true,而InsertingInterface Panel控件的Visible属性为false。

特别是那些DropDownList控件和TextBox控件,它们会在ReturnToDisplayInterface方法的操控下,回到预编辑状态。想象一下,如果你点击了“从发货处理产品”按钮,输入了一些产品信息后,又点击了“从发货中添加产品”按钮。这时,产品会被成功添加,同时界面会回到展示状态,所有的控件也会回到初始状态,准备迎接你的下一次操作。这样的设计确保了用户体验的连贯性和流畅性。在您的程序中,点击“Add Products from Shipment”按钮时,您将开始将产品数据添加到数据库。这一过程的实现需要细致处理,以确保数据的准确性和完整性。以下是关于如何改进这一过程的描述和代码示例。

您需要在`AddProducts_Click`事件处理器中创建一个新的产品行实例,并通过您的界面控件获取必要的数据。然后,您可以将这些数据保存到数据库。以下是这一过程的伪代码和解释:

```csharp

protected void AddProducts_Click(object sender, EventArgs e)

{

// 创建新的产品行实例

ProductsRow newProductRow = new ProductsRow();

// 从界面获取数据并设置到产品行实例中

newProductRow.ProductName = ((TextBox)InsertingInterface.FindControl("ProductName" + /相应的索引值/)).Text;

newProductRow.UnitPrice = decimal.Parse(((TextBox)InsertingInterface.FindControl("UnitPrice" + /相应的索引值/)).Text); // 请确保进行异常处理以防输入无效数据

// 更多类似的代码来设置其他产品属性...

// 将产品行添加到ProductsDataTable中(假设您已经创建了该表)

ProductsDataTable.Rows.Add(newProductRow);

// 将ProductsDataTable中的数据保存到数据库

// 这里可能需要调用数据访问层或存储过程等来处理实际的数据库操作

// 重置界面并显示成功消息(可选)

ReturnToDisplayInterface(); // 显示成功添加产品的消息或相关反馈

}

```

您还需要确保在界面上正确地显示这些产品数据,以便用户可以直观地看到他们输入的数据以及这些数据的后续处理结果。这可能涉及到更新界面上的显示控件,如GridView或DataList等。您可能还需要在数据库中更新产品的状态或其他相关信息,以反映产品的当前状态(例如已添加、待审核等)。这需要根据您的具体业务需求来确定。在我们将ProductsRows添加到系统中后,紧接着的任务就是调用并传递ProductsDataTable至ProductsBLL class类的UpdateWithTransaction方法。这一操作是在我们精心设计的第61章中所提及的。记得我们在那个章节里详细阐述了如何创建UpdateWithTransaction方法,它作为一个桥梁,将ProductsDataTable传递至ProductsTableAdapter的UpdateWithTransaction方法。

此刻,一个ADO.NET事务被启动。TableAdapter针对每一个被添加的ProductsRow,都会向数据库发出一个明确的INSERT命令。如果所有的添加操作都没有问题,那么事务就会被成功提交,数据库将记录下所有的更改。如果在添加过程中出现了任何错误,那么事务就会自动回滚,保证数据的完整性和一致性。

特别是当我们对“Add Products from Shipment”按钮的Click处理器进行编码的时候,我们更需要实施严格的错误校验。虽然我们在界面设计上没有使用RequiredFieldValidators控件来强制用户输入必要的信息,但这并不意味着我们可以忽视对输入数据的验证。

一旦确认页面有效,处理器会进入一个循环,用于从用户界面获取产品信息并将其添加到ProductsDataTable中。它会从用户界面的文本框中获取产品的名称和单位价格,并确保如果提供了单位价格,则必须同时提供产品的名称。如果用户只提供了单位价格而没有提供产品名称,我们会显示一条警告信息并退出事件处理器。

只有当用户提供产品名称时,我们才会添加产品。我们创建一个新的ProductsRow对象并将其添加到ProductsDataTable中。然后我们从网页上获取产品的详细信息并将其分配给新的ProductsRow对象。如果提供了单位价格,我们还会将其转换为十进制数并分配给ProductsRow对象。我们还会为新产品设置一些默认值,例如将其设置为未中断供应和零订单单位。

一旦我们添加了一个或多个产品到ProductsDataTable中,我们就会检查是否有任何产品被添加。如果有产品被添加,我们会使用事务将新产品添加到数据库中,并将数据重新绑定到网格上以便显示刚刚添加的产品。然后我们会显示一条确认信息告知用户已经成功添加了产品。最后我们会返回到用户界面以便进行下一步操作。如果没有任何产品被添加,我们会告诉用户输入产品的名称和单位价格到文本框中。

这段代码提供了一个流畅、细致的产品添加体验,确保用户能够轻松地添加新产品到我们的系统中。无论是成功添加产品还是遇到任何问题,我们都会通过友好的提示信息告知用户下一步应该做什么。在业务数据处理中,数据的准确性和完整性至关重要。一旦出现无效数据,我们必须及时做出响应,无论是选择停止添加产品,还是在尝试更新数据库时抛出异常。今天我们将一个场景,其中涉及到了产品的批量添加和用户输入数据的验证。

当用户开始添加产品时,我们创建一个新的ProductsDataTable实例(即products)。随后,我们进入一个循环,逐一读取关于产品名称和单位价格的TextBox控件的Text属性,分别存储在局部变量productName和unitPrice中。这里,我们强调如果用户只提供了单位价格而忘记输入产品名称,StatusLabel控件会立刻显示消息:“如果您提供单位价格,请务必包含产品名称。”并退出事件处理器。

对于每一个有效的产品条目,我们使用ProductsDataTable的NewProductsRow方法创建一个新的ProductsRow实例。我们为实例的ProductName属性赋值相应的TextBox内容,为SupplierID和CategoryID属性赋值时则参考添加界面顶部DropDownList控件的SelectedValue。至于单位价格,如果用户有输入,我们就将其赋值给ProductsRow实例的UnitPrice属性;如果没有,则置空,以便在数据库中添加时UnitPrice的值为NULL。其他属性如Discontinued和UnitsOnOrder则分别被硬编码为“false”和“0”。

完成所有ProductsRow实例的属性赋值后,我们将其添加到ProductsDataTable中。随后,我们检查是否已添加产品,因为有可能用户在未输入任何信息的情况下点击了“Add Products from Shipment”按钮。如果存在至少一个产品,我们将调用ProductsBLL class的UpdateWithTransaction方法,并重新绑定名为ProductsGrid的GridView控件。这样,添加的产品就会出现在展示界面中。StatusLabel会更新以显示确认消息,并调用ReturnToDisplayInterface方法,将界面从添加模式切换回展示模式。

如果没有添加任何产品,界面将显示消息:“未添加产品。请在文本框中输入产品名称和单位价格。”

通过前兩章及本章的内容,我们构建了数据批更新、批删除和批添加的界面,这些界面都运用了事务处理机制。在实际应用中,这有助于我们提高数据处理效率,同时确保数据的准确性和完整性。在数据世界的——第61章数据访问层的进阶之旅

在数据世界的中,我们已触及数据访问层(Data Access Layer)的更深之处。在这里,我们并非止步于简单的数据访问,而是深入了批数据处理界面的应用。这些界面在某些情境下,极大地提升了最终用户的效率。那么,我们所走过的路究竟如何呢?接下来,让我们一同这一层次中的更多高级应用场景。

我们将聚焦于在TableAdapter的方法中使用存储过程。存储过程作为数据库的一种重要功能,可以大大提高数据处理的速度和效率。在数据访问层中引入存储过程,不仅能够简化编程复杂性,而且能提高数据的处理能力和系统的响应速度。对于开发者而言,熟练掌握存储过程的使用是提升数据访问层性能的关键。

我们将深入如何在DAL中进行连接和命令级别的设置。在数据访问层中,连接字符串的管理至关重要。开发者需要在保障数据安全性的进行高效的数据连接和操作。我们将分享如何对连接字符串进行加密等高级技术,确保数据的安全性和隐私性。我们还会如何在数据访问层中实现更细粒度的控制,以优化性能和提高系统稳定性。我们还将深入如何通过命令级别的设置来实现更灵活的数据操作和处理。

随着这一系列文章的深入,我们将带领大家领略数据访问层的丰富世界。无论是新手还是资深开发者,我们都希望通过这些文章能够帮助大家更好地理解和掌握ASP.NET开发中的数据处理技术。在这个过程中,我们将一起成长、一起进步。

本系列教程的作者是Scott Mitchell先生。他是一位经验丰富的ASP/ASP.NET开发者,著有六本相关书籍。作为4GuysFromRolla.的创始人,他自1998年以来一直专注于微软Web技术的研发和应用。我们欢迎广大开发者关注这一系列教程,共同学习、共同进步。我们相信,通过深入数据访问层的世界,您一定能够开启编程的新篇章。祝愿大家在编程的道路上越走越远,收获快乐与成长!

上一篇:SQLServer XML查询18句话入门教程 下一篇:没有了

Copyright © 2016-2025 www.168986.cn 狼蚁网络 版权所有 Power by