这个添加界面将用于展示产品的信息,用户可以在此进行产品的添加和管理操作。通过简单的操作,用户可以直观地看到产品的类别、供应商、名称和单位价格等信息,并进行相应的操作。这种设计使得产品管理更加便捷和高效。
元素都被赋予了明确的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技术的研发和应用。我们欢迎广大开发者关注这一系列教程,共同学习、共同进步。我们相信,通过深入数据访问层的世界,您一定能够开启编程的新篇章。祝愿大家在编程的道路上越走越远,收获快乐与成长!