添加其他 DataTable 列 (VB)

作者 :Scott Mitchell

下载 PDF

使用 TableAdapter 向导创建类型化数据集时,相应的 DataTable 包含main数据库查询返回的列。 但在某些情况下,DataTable 需要包含其他列。 在本教程中,我们将了解在需要其他 DataTable 列时为何建议使用存储过程。

简介

将 TableAdapter 添加到类型化数据集时,相应的 DataTable 架构由 TableAdapter main 查询确定。 例如,如果main查询返回数据字段 ABC,则 DataTable 将具有三个名为 ABC 的相应列。除了main查询之外,TableAdapter 还可以包含其他查询,这些查询可能基于某个参数返回数据的子集。 例如,除了ProductsTableAdapter返回有关所有产品的信息的 main 查询外,它还包含 和 GetProductByProductID(productID)GetProductsByCategoryID(categoryID)方法,这些方法基于提供的参数返回特定产品信息。

如果所有 TableAdapter 方法返回的数据字段都与main查询中指定的字段相同或更少,则让 DataTable 架构反映 TableAdapter main 查询的模型效果良好。 如果 TableAdapter 方法需要返回其他数据字段,则应相应地展开 DataTable 的架构。 在母版/详细信息使用带详细信息数据列表的主记录项目符号列表教程中,我们向 CategoriesTableAdapter 添加了一个方法,该方法返回CategoryIDCategoryName了 main 查询中定义的 、 和数据Description字段,以及NumberOfProducts报告与每个类别关联的产品数量的附加数据字段。 我们手动向 CategoriesDataTable 添加了一个新列,以便从此新方法捕获 NumberOfProducts 数据字段值。

上传文件教程中所述,对于使用即席 SQL 语句的 TableAdapter,并且具有数据字段与main查询不精确匹配的方法,必须格格谨慎。 如果重新运行 TableAdapter 配置向导,它将更新所有 TableAdapter 方法,使其数据字段列表与main查询匹配。 因此,任何具有自定义列列表的方法都将还原到main查询列列表,并且不返回预期的数据。 使用存储过程时不会出现此问题。

本教程介绍如何扩展 DataTable 架构以包含其他列。 由于使用临时 SQL 语句时 TableAdapter 的脆性,本教程将使用存储过程。 有关配置 TableAdapter 以使用存储过程的详细信息,请参阅为 Typed DataSet s TableAdapters 创建新的存储过程和 针对类型化数据集的 TableAdapters 使用现有 存储过程教程。

步骤 1:将PriceQuartile列添加到ProductsDataTable

为类型化数据集创建新的存储过程的 TableAdapters 教程中,我们创建了名为 的类型 NorthwindWithSprocs化数据集。 此数据集当前包含两个 DataTable: ProductsDataTableEmployeesDataTable。 有 ProductsTableAdapter 以下三种方法:

  • GetProducts- main查询,该查询返回表中的所有记录Products
  • GetProductsByCategoryID(categoryID) - 返回具有指定 categoryID 的所有产品。
  • GetProductByProductID(productID) - 返回具有指定 productID 的特定产品

main查询和两个附加方法都返回相同的数据字段集,即表中的所有列Products。 没有相关子查询或 JOINCategoriesSuppliers 表拉取相关数据。 因此, 表中 ProductsDataTable 每个字段 Products 都有相应的列。

在本教程中,让我们将 ProductsTableAdapter 一个返回所有产品的 名为 GetProductsWithPriceQuartile 的方法添加到 。 除了标准产品数据字段外, GetProductsWithPriceQuartile 还将包含一个 PriceQuartile 数据字段,用于指示产品价格下降的四分位数。 例如,价格在最昂贵的 25% 的产品的 PriceQuartile 值为 1,而价格低于 25% 的产品的值为 4。 但是,在担心创建存储过程以返回此信息之前,我们首先需要更新 ProductsDataTable 以包含一个列,以在使用 方法时GetProductsWithPriceQuartile保存PriceQuartile结果。

打开 NorthwindWithSprocs 数据集并右键单击 ProductsDataTable。 从上下文菜单中选择“添加”,然后选择“列”。

向 ProductsDataTable 添加新列

图 1:将新列添加到 ProductsDataTable (单击以查看全尺寸图像)

这会向 DataTable 中添加一个名为 Column1 的新列,类型为 System.String。 我们需要将此列的名称更新为 PriceQuartile 及其类型, System.Int32 因为它将用于保存介于 1 和 4 之间的数字。 选择 中ProductsDataTable新添加的列,并从属性窗口将 属性设置为 Name PriceQuartile,将 DataType 属性设置为 System.Int32

设置新列的 Name 和 DataType 属性

图 2:设置“新建列 Name ”和 DataType “属性” (单击以查看全尺寸图像)

如图 2 所示,可以设置其他属性,例如列中的值是否必须唯一、列是否为自动递增列、是否允许数据库 NULL 值等。 将这些值保留为默认值。

步骤 2:创建GetProductsWithPriceQuartile方法

现在, ProductsDataTable 已将 更新为包含 PriceQuartile 列,我们已准备好创建 GetProductsWithPriceQuartile 方法。 首先,右键单击“TableAdapter”,然后从上下文菜单中选择“添加查询”。 此时会显示 TableAdapter 查询配置向导,该向导首先提示我们是要使用即席 SQL 语句还是新的或现有的存储过程。 由于我们还没有返回价格四分位数数据的存储过程,因此允许 TableAdapter 为我们创建此存储过程。 选择“创建新存储过程”选项,然后单击“下一步”。

指示 TableAdapter 向导为我们创建存储过程

图 3:指示 TableAdapter 向导为我们创建存储过程 (单击以查看全尺寸图像)

在随后的屏幕(如图 4 所示)中,向导将询问要添加哪种类型的查询。 GetProductsWithPriceQuartile由于 该方法将返回表中的所有列和记录Products,请选择返回行的 SELECT 选项,然后单击“下一步”。

查询将是返回多行的 SELECT 语句

图 4:我们的查询将是一个 SELECT 返回多行的语句 (单击以查看全尺寸图像)

接下来,系统会提示我们进行 SELECT 查询。 在向导中输入以下查询:

SELECT ProductID, ProductName, SupplierID, CategoryID, 
       QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, 
       ReorderLevel, Discontinued,
       NTILE(4) OVER (ORDER BY UnitPrice DESC) as PriceQuartile
FROM Products

上述查询使用 SQL Server 2005 的新NTILE函数将结果划分为四组,其中组由UnitPrice按降序排序的值确定。

遗憾的是,查询生成器不知道如何分析OVER关键字 (keyword) ,在分析上述查询时将显示错误。 因此,无需使用查询生成器,直接在向导的文本框中输入上述查询。

注意

有关 NTILE 和 2005 SQL Server其他排名函数的详细信息,请参阅 SQL Server 2005 联机丛书中的 ROW_NUMBER (Transact-SQL) 排名函数部分

输入 SELECT 查询并单击“下一步”后,向导会要求我们提供它将创建的存储过程的名称。 将新存储过程 Products_SelectWithPriceQuartile 命名为 ,然后单击“下一步”。

将存储过程命名为Products_SelectWithPriceQuartile

图 5:命名存储过程 Products_SelectWithPriceQuartile (单击以查看全尺寸图像)

最后,系统会提示我们命名 TableAdapter 方法。 选中“填充 DataTable”和“返回 DataTable”复选框,并将方法和FillWithPriceQuartileGetProductsWithPriceQuartile命名为 。

将 TableAdapter 命名为“方法”,然后单击“完成”

图 6:将 TableAdapter 命名为“方法”,然后单击“完成” (单击以查看全尺寸图像)

指定 SELECT 查询以及存储过程和名为 TableAdapter 方法后,单击“完成”以完成向导。 此时,可能会从向导收到一两条警告,指出 OVER 不支持 SQL 构造或语句。 可以忽略这些警告。

完成向导后,TableAdapter 应包含 FillWithPriceQuartileGetProductsWithPriceQuartile 方法,数据库应包含名为 的 Products_SelectWithPriceQuartile存储过程。 请花点时间验证 TableAdapter 确实包含此新方法,以及存储过程是否已正确添加到数据库。 检查数据库时,如果没有看到存储过程,请尝试右键单击“存储过程”文件夹,然后选择“刷新”。

验证是否已将新方法添加到 TableAdapter

图 7:验证是否已将新方法添加到 TableAdapter

确保数据库包含Products_SelectWithPriceQuartile存储过程

图 8:确保数据库包含 Products_SelectWithPriceQuartile 存储过程 (单击 以查看全尺寸图像)

注意

使用存储过程而不是临时 SQL 语句的一个好处是,重新运行 TableAdapter 配置向导不会修改存储过程列列表。 通过右键单击“TableAdapter”,从上下文菜单中选择“配置”选项以启动向导,然后单击“完成”以完成向导,对此进行验证。 接下来,转到数据库并查看 Products_SelectWithPriceQuartile 存储过程。 请注意,其列列表尚未修改。 如果我们使用的是即席 SQL 语句,则重新运行 TableAdapter 配置向导会还原此查询的列列表以匹配main查询列列表,从而从 方法使用的GetProductsWithPriceQuartile查询中删除 NTILE 语句。

调用数据访问层 方法 GetProductsWithPriceQuartile 时,TableAdapter 将执行 Products_SelectWithPriceQuartile 存储过程,并为每个返回的记录添加一行 ProductsDataTable 。 存储过程返回的数据字段映射到 ProductsDataTable s 列。 由于存储过程返回了一个 PriceQuartile 数据字段,因此其值将 ProductsDataTable 分配给 s PriceQuartile 列。

对于查询不返回 PriceQuartile 数据字段的 TableAdapter 方法, PriceQuartile 列值是其 DefaultValue 属性指定的值。 如图 2 所示,此值设置为 DBNull默认值。 如果希望使用不同的默认值,只需相应地设置 DefaultValue 属性。 只需确保 DefaultValue 该值在列 DataType (System.Int32 即列 PriceQuartile) 有效。

此时,我们已执行将其他列添加到 DataTable 的必要步骤。 若要验证此附加列是否按预期工作,让我们创建一个 ASP.NET 页面,显示每个产品的名称、价格和价格四分位数。 但是,在执行此操作之前,我们首先需要更新业务逻辑层,以包含调用 DAL 方法的方法 GetProductsWithPriceQuartile 。 接下来,我们将在步骤 3 中更新 BLL,然后在步骤 4 中创建 ASP.NET 页。

步骤 3:扩充业务逻辑层

使用表示层中的新 GetProductsWithPriceQuartile 方法之前,应首先将相应的方法添加到 BLL。 打开 ProductsBLLWithSprocs 类文件并添加以下代码:

<System.ComponentModel.DataObjectMethodAttribute_
    (System.ComponentModel.DataObjectMethodType.Select, False)> _
Public Function GetProductsWithPriceQuartile() As NorthwindWithSprocs.ProductsDataTable
    Return Adapter.GetProductsWithPriceQuartile()
End Function

与 中的其他数据检索方法一 ProductsBLLWithSprocs样, GetProductsWithPriceQuartile 该方法只需调用 DAL 对应的 GetProductsWithPriceQuartile 方法并返回其结果。

步骤 4:在 ASP.NET 网页中显示价格四分位数信息

完成 BLL 添加后,我们已准备好创建一个 ASP.NET 页面,其中显示了每个产品的价格四分位数。 AddingColumns.aspx打开 文件夹中的页面AdvancedDAL,并将 GridView 从工具箱拖到Designer,并将其ID属性设置为 Products。 从 GridView 的智能标记中,将其绑定到名为 ProductsDataSource的新 ObjectDataSource。 将 ObjectDataSource 配置为使用 ProductsBLLWithSprocs 类 s GetProductsWithPriceQuartile 方法。 由于这是一个只读网格,因此请将“更新”、“插入”和“删除”选项卡中的下拉列表设置为 (“无”) 。

将 ObjectDataSource 配置为使用 ProductsBLLWithSprocs 类

图 9:将 ObjectDataSource 配置为使用 ProductsBLLWithSprocs 类 (单击以查看全尺寸图像)

从 GetProductsWithPriceQuartile 方法检索产品信息

图 10:从 GetProductsWithPriceQuartile 方法中检索产品信息 (单击以查看全尺寸图像)

完成“配置数据源”向导后,Visual Studio 会自动为方法返回的每个数据字段添加 BoundField 或 CheckBoxField。 其中一个数据字段是 PriceQuartile,它是我们在步骤 1 中添加 ProductsDataTable 的列。

编辑 GridView 字段,删除除 、 UnitPricePriceQuartile BoundFields 外ProductName的所有字段。 将 UnitPrice BoundField 配置为将其值格式化为货币,并将 UnitPricePriceQuartile BoundFields 分别右对齐和居中对齐。 最后,将剩余的 BoundFields HeaderText 属性分别更新为“产品”、“价格”和“价格四分位数”。 此外,检查 GridView 智能标记中的“启用排序”复选框。

进行这些修改后,GridView 和 ObjectDataSource 的声明性标记应如下所示:

<asp:GridView ID="Products" runat="server" AllowSorting="True"
    AutoGenerateColumns="False" DataKeyNames="ProductID" 
    DataSourceID="ProductsDataSource">
    <Columns>
        <asp:BoundField DataField="ProductName" HeaderText="Product" 
            SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" DataFormatString="{0:c}" 
            HeaderText="Price" HtmlEncode="False" 
            SortExpression="UnitPrice">
            <ItemStyle HorizontalAlign="Right" />
        </asp:BoundField>
        <asp:BoundField DataField="PriceQuartile" HeaderText="Price Quartile" 
            SortExpression="PriceQuartile">
            <ItemStyle HorizontalAlign="Center" />
        </asp:BoundField>
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server" 
    OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProductsWithPriceQuartile" 
    TypeName="ProductsBLLWithSprocs">
</asp:ObjectDataSource>

图 11 显示了通过浏览器访问时的此页面。 请注意,最初,产品按价格降序排序,每个产品都分配了适当的 PriceQuartile 值。 当然,这些数据可以按其他条件进行排序,价格四分位数列值仍然反映产品相对于价格的排名 (请参阅图 12) 。

产品按价格订购

图 11:按价格订购产品 (单击以查看全尺寸图像)

产品按其名称排序

图 12:产品按其名称排序 (单击以查看全尺寸图像)

注意

通过几行代码,我们可以扩充 GridView,以便它根据 PriceQuartile 产品行的值为其着色。 我们可能会将第一个四分位数中的这些产品着色为浅绿色,将第二个四分位数中的产品着色为浅黄色,依此类推。 我鼓励你花点时间添加此功能。 如果需要有关设置 GridView 格式的复习,请参阅 基于数据的自定义格式设置 教程。

替代方法 - 创建另一个 TableAdapter

正如我们在本教程中看到的,在向 TableAdapter 添加方法时,该方法返回main查询拼出的数据字段以外的数据字段时,我们可以向 DataTable 添加相应的列。 但是,仅当 TableAdapter 中有少量返回不同数据字段的方法,并且这些备用数据字段与main查询之间没有太大差异时,此方法才有效。

可以改为将另一个 TableAdapter 添加到 DataSet,其中包含返回不同数据字段的第一个 TableAdapter 中的方法,而不是向 DataTable 添加列。 对于本教程,我们可以将列添加到PriceQuartileProductsDataTable 仅由GetProductsWithPriceQuartile方法) 使用的 (,而是将另一个名为 的 TableAdapter 添加到使用Products_SelectWithPriceQuartile存储过程作为其main查询的数据集ProductsWithPriceQuartileTableAdapter。 ASP.NET 需要获取价格四分位数的产品信息的页面将使用 ProductsWithPriceQuartileTableAdapter,而那些不能继续使用 的页面 ProductsTableAdapter

通过添加新的 TableAdapter,DataTable 将保持不受阻碍,其列精确镜像其 TableAdapter 方法返回的数据字段。 但是,其他 TableAdapter 可能会引入重复的任务和功能。 例如,如果那些 ASP.NET 显示列 PriceQuartile 的页面还需要提供插入、更新和删除支持, ProductsWithPriceQuartileTableAdapter 则需要正确配置其 InsertCommandUpdateCommandDeleteCommand 属性。 虽然这些属性将镜像 ProductsTableAdapter ,但此配置引入了额外的步骤。 此外,现在有两种方法可以更新、删除产品或将产品添加到数据库 - 通过 ProductsTableAdapterProductsWithPriceQuartileTableAdapter 类。

本教程的下载内容包括 DataSet 中的NorthwindWithSprocs一个ProductsWithPriceQuartileTableAdapter类,该类演示了这种替代方法。

总结

在大多数情况下,TableAdapter 中的所有方法都将返回同一组数据字段,但有时一两个特定方法可能需要返回其他字段。 例如,在 Master/Detail Using a Bulleted List of Master Records with a Details DataList 教程中,我们向 CategoriesTableAdapter 添加了一个方法,该方法除了main查询的数据字段外,还返回了一个NumberOfProducts字段,该字段报告了与每个类别关联的产品数。 在本教程中,我们介绍了在 中添加ProductsTableAdapter除main查询数据字段外返回PriceQuartile字段的方法。 若要捕获 TableAdapter 方法返回的其他数据字段,我们需要将相应的列添加到 DataTable。

如果计划手动向 DataTable 添加列,建议 TableAdapter 使用存储过程。 如果 TableAdapter 使用即席 SQL 语句,则每当运行 TableAdapter 配置向导时,所有方法数据字段列表还原main查询返回的数据字段。 此问题不延伸到存储过程,这就是为什么建议在本教程中使用它们的原因。

编程快乐!

关于作者

斯科特·米切尔是七本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com 的创始人,自 1998 年以来一直在使用 Microsoft Web 技术。 Scott 担任独立顾问、培训师和作家。 他的最新一本书是 山姆斯在 24 小时内 ASP.NET 2.0。 可以在 上mitchell@4GuysFromRolla.com联系他,也可以通过他的博客(可在 中找到http://ScottOnWriting.NET)。

特别感谢

本教程系列由许多有用的审阅者审阅。 本教程的主要审阅者是 Randy Schmidt、Jacky Goor、Bernadette Leigh 和 Hilton Giesenow。 有兴趣查看我即将发布的 MSDN 文章? 如果是,请在 处mitchell@4GuysFromRolla.com放置一行。