使用 SqlDataSource 控件查询数据 (C#)

作者 :斯科特·米切尔

下载 PDF

在前面的教程中,我们使用 ObjectDataSource 控件将呈现层与数据访问层完全分离。 从本教程开始,我们将了解如何将 SqlDataSource 控件用于不需要严格分离呈现和数据访问的简单应用程序。

简介

到目前为止,我们检查的所有教程都使用了一个由演示层、业务逻辑层和数据访问层组成的分层体系结构。 第一个教程(创建数据访问层)和第二个业务逻辑层(创建业务逻辑层)中创建了数据访问层(DAL)。 从“ 使用 ObjectDataSource 显示数据 ”教程开始,我们了解了如何使用 ASP.NET 2.0 s 新的 ObjectDataSource 控件以声明方式与呈现层中的体系结构进行交互。

尽管到目前为止的所有教程都使用体系结构来处理数据,但也可以直接从 ASP.NET 页访问、插入、更新和删除数据库数据,从而绕过体系结构。 这样做会将特定的数据库查询和业务逻辑直接放在网页中。 对于足够大的或复杂的应用程序,设计、实现和使用分层体系结构对于应用程序的成功、可更新性和可维护性至关重要。 但是,在创建极其简单的一次性应用程序时,开发可靠的体系结构可能没有必要。

ASP.NET 2.0 提供五个内置数据源控件 SqlDataSourceAccessDataSourceObjectDataSourceXmlDataSourceSiteMapDataSource。 SqlDataSource 可用于直接从关系数据库访问和修改数据,包括Microsoft SQL Server、Microsoft Access、Oracle、MySQL 等。 在本教程和接下来的三个教程中,我们将探讨如何使用 SqlDataSource 控件,探索如何查询和筛选数据库数据,以及如何使用 SqlDataSource 插入、更新和删除数据。

ASP.NET 2.0 包括五个 Built-In 数据源控件

图 1:ASP.NET 2.0 包括五个 Built-In 数据源控件

比较 ObjectDataSource 和 SqlDataSource

从概念上讲,ObjectDataSource 和 SqlDataSource 控件只是数据的代理。 如“ 使用 ObjectDataSource 显示数据 ”教程中所述,ObjectDataSource 具有属性,这些属性指示提供数据以及用于调用以从基础对象类型中选择、插入、更新和删除数据的方法。 配置 ObjectDataSource 属性后,可以使用 ObjectDataSource s Select()Insert()Delete()Update() 和方法与基础体系结构交互,将数据 Web 控件(如 GridView、DetailsView 或 DataList)绑定到该控件。

SqlDataSource 提供相同的功能,但针对关系数据库而不是对象库进行操作。 使用 SqlDataSource,必须指定数据库连接字符串和临时 SQL 查询或存储过程来执行以插入、更新、删除和检索数据。 调用 SqlDataSource s Select()Insert()Update()Delete() 方法时,连接到指定的数据库并发出相应的 SQL 查询。 如下图所示,这些方法执行连接到数据库、发出查询和返回结果的艰苦工作。

SqlDataSource 充当数据库的代理

图 2:SqlDataSource 充当数据库的代理

注意

在本教程中,我们将重点介绍如何从数据库检索数据。 在 SqlDataSource 控件教程的“插入、更新和删除数据 ”教程中,我们将了解如何配置 SqlDataSource 以支持插入、更新和删除。

SqlDataSource 和 AccessDataSource 控件

除了 SqlDataSource 控件,ASP.NET 2.0 还包括 AccessDataSource 控件。 这两个不同的控件导致许多开发人员 ASP.NET 2.0,怀疑 AccessDataSource 控件旨在与专用于Microsoft SQL Server 的 sqlDataSource 控件配合使用Microsoft Access。 虽然 AccessDataSource 旨在专门处理 Microsoft Access,但 SqlDataSource 控件适用于可通过 .NET 访问 的任何 关系数据库。 这包括任何符合 OleDb 或 ODBC 的数据存储,例如Microsoft SQL Server、Microsoft Access、Oracle、Informix、MySQL 和 PostgreSQL 等。

AccessDataSource 和 SqlDataSource 控件的唯一区别在于如何指定数据库连接信息。 AccessDataSource 控件只需要 Access 数据库文件的文件路径。 另一方面,SqlDataSource 需要完整的连接字符串。

步骤 1:创建 SqlDataSource 网页

在开始探索如何使用 SqlDataSource 控件直接处理数据库数据之前,让我们先花点时间在网站项目中创建 ASP.NET 页面,本教程和接下来的三个页面。 首先添加名为 <a0/a0> 的新文件夹。 接下来,将以下 ASP.NET 页添加到该文件夹,确保将每个页面与 Site.master 母版页相关联:

  • Default.aspx
  • Querying.aspx
  • ParameterizedQueries.aspx
  • InsertUpdateDelete.aspx
  • OptimisticConcurrency.aspx

为 SqlDataSource-Related 教程添加 ASP.NET 页

图 3:为 SqlDataSource-Related 教程添加 ASP.NET 页

与其他文件夹中一样, Default.aspxSqlDataSource 文件夹中将列出其部分中的教程。 回想一下, SectionLevelTutorialListing.ascx 用户控件提供了此功能。 因此,通过将此用户控件从解决方案资源管理器拖动到Default.aspx页面的设计视图中,将其添加到该控件。

将 SectionLevelTutorialListing.ascx 用户控件添加到 Default.aspx

图 4:将用户控件Default.aspx添加到 SectionLevelTutorialListing.ascx单击以查看全尺寸图像

最后,将这四个页面作为条目添加到 Web.sitemap 文件中。 具体而言,在向 DataList 和 Repeater <siteMapNode>添加自定义按钮后添加以下标记:

<siteMapNode url="~/SqlDataSource/Default.aspx"
    title="Using the SqlDataSource Control"
    description="Work directly with database data using the SqlDataSource control.">
    <siteMapNode url="~/SqlDataSource/Querying.aspx" title="Retrieving Database Data"
        description="Examines how to query data from a database that can then be
                     displayed  through a data Web control."/>
    <siteMapNode url="~/SqlDataSource/ParameterizedQueries.aspx"
        title="Parameterized Queries"
        description="Learn how to specify parameterized WHERE clauses in the
                     SqlDataSource's SELECT statement." />
    <siteMapNode url="~/SqlDataSource/InsertUpdateDelete.aspx"
        title="Inserting, Updating, and Deleting Database Data"
        description="See how to configure the SqlDataSource to include INSERT, UPDATE,
                      and DELETE statements." />
    <siteMapNode url="~/SqlDataSource/OptimisticConcurrency.aspx"
        title="Using Optimistic Concurrency"
        description="Explore how to augment the SqlDataSource to include support for
                     optimistic concurrency." />
</siteMapNode>

更新 Web.sitemap后,请花点时间通过浏览器查看教程网站。 左侧菜单现在包括用于编辑、插入和删除教程的项目。

站点地图现在包括 SqlDataSource 教程的条目

图 5:站点地图现在包括 SqlDataSource 教程的条目

步骤 2:添加和配置 SqlDataSource 控件

首先打开 Querying.aspx 文件夹中的页面 SqlDataSource 并切换到“设计”视图。 将 SqlDataSource 控件从工具箱拖到设计器上,并将其 ID 设置为 ProductsDataSource。 与 ObjectDataSource 一样,SqlDataSource 不会生成任何呈现的输出,因此在设计图面上显示为灰色框。 若要配置 SqlDataSource,请单击 SqlDataSource 智能标记中的“配置数据源”链接。

单击 SqlDataSource 智能标记中的“配置数据源链接”

图 6:单击 SqlDataSource 智能标记中的“配置数据源链接”

此时会显示 SqlDataSource 控件的“配置数据源”向导。 虽然向导的步骤与 ObjectDataSource 控件不同,但最终目标是提供有关如何通过数据源检索、插入、更新和删除数据的详细信息。 对于 SqlDataSource,这需要指定基础数据库来使用和提供即席 SQL 语句或存储过程。

第一个向导步骤会提示我们输入数据库。 下拉列表包括 Web 应用程序 App_Data 文件夹中找到的数据库,以及已添加到服务器资源管理器中的数据连接节点的数据库。 由于我们已将文件夹中数据库的NORTHWIND.MDF连接字符串App_Data添加到项目Web.config文件,因此下拉列表包含对该连接字符串NORTHWINDConnectionString的引用。 从下拉列表中选择此项,然后单击“下一步”。

从 Drop-Down 列表中选择 NORTHWINDConnectionString

图 7:请从 Drop-Down 列表中选择NORTHWINDConnectionString

选择数据库后,向导会要求查询返回数据。 我们可以指定要返回的表或视图的列,也可以输入自定义 SQL 语句或指定存储过程。 可以通过“指定自定义 SQL 语句或存储过程”和“从表或视图单选按钮指定列”来切换此选项。

注意

对于第一个示例,让我们使用表或视图选项中的“指定列”。 本教程稍后将返回到向导,并浏览“指定自定义 SQL 语句或存储过程”选项。

图 8 显示了“从表或视图单选按钮中选择指定列时配置 Select 语句”屏幕。 下拉列表包含 Northwind 数据库中的表和视图集,其中选中的表或视图列显示在下面的复选框列表中。 对于此示例,让我们返回ProductID表中的ProductNameUnitPriceProducts列。 如图 8 所示,在进行这些选择后,向导会显示生成的 SQL 语句 SELECT [ProductID], [ProductName], [UnitPrice] FROM [Products]

从产品表返回数据

图 8:从 Products 表返回数据

将向导配置为返回表中的 ProductIDProductNameUnitPriceProducts 后,单击“下一步”按钮。 此最终屏幕提供了检查上一步中配置的查询结果的机会。 单击“测试查询”按钮将执行配置的 SELECT 语句,并在网格中显示结果。

单击“测试查询”按钮查看 SELECT 查询

图 9:单击“测试查询”按钮以查看 SELECT 查询

若要完成向导,请单击 “完成”。

与 ObjectDataSource 一样,SqlDataSource 向导只是将值分配给控件的属性,即 ConnectionString 属性和 SelectCommand 属性。 完成向导后,SqlDataSource 控件的声明性标记应如下所示:

<asp:SqlDataSource ID="ProductsDataSource" runat="server"
    ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
    SelectCommand="SELECT [ProductID], [ProductName], [UnitPrice] FROM [Products]">
</asp:SqlDataSource>

ConnectionString 属性提供有关如何连接到数据库的信息。 可以为此属性分配完整的硬编码连接字符串值,也可以指向连接字符串。Web.config 若要在 Web.config 中引用连接字符串值,请使用语法<%$ expressionPrefix:expressionValue %>。 通常,expressionPrefix 是 ConnectionStrings,expressionValue 是节中的Web.config<connectionStrings>连接字符串的名称。 但是,语法可用于引用 <appSettings> 资源文件中的元素或内容。 有关此语法的详细信息 ,请参阅 ASP.NET 表达式概述

SelectCommand 属性指定要执行的即席 SQL 语句或存储过程以返回数据。

步骤 3:添加数据 Web 控件并将其绑定到 SqlDataSource

配置 SqlDataSource 后,可以绑定到数据 Web 控件,例如 GridView 或 DetailsView。 在本教程中,让我们在 GridView 中显示数据。 从工具箱中,将 GridView 拖到绘图页上,并通过从 GridView 智能标记中的下拉列表中选择数据源, ProductsDataSource 将其绑定到 SqlDataSource。

添加 GridView 并将其绑定到 SqlDataSource 控件

图 10:添加 GridView 并将其绑定到 SqlDataSource 控件(单击以查看全尺寸图像

从 GridView 智能标记的下拉列表中选择 SqlDataSource 控件后,Visual Studio 会自动将 BoundField 或 CheckBoxField 添加到 GridView 中,以获取数据源控件返回的每个列。 由于 SqlDataSource 返回三个数据库列 ProductIDProductName并且 UnitPrice GridView 中有三个字段。

花点时间配置 GridView s 三个 BoundFields。 将 ProductName 字段属性 HeaderText 更改为产品名称,并将 UnitPrice 字段更改为 Price。 此外,将 UnitPrice 字段的格式格式化为货币。 进行这些修改后,GridView 的声明性标记应如下所示:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ProductsDataSource"
    EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="ProductID" HeaderText="ProductID"
            InsertVisible="False" ReadOnly="True" SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" HeaderText="Product Name"
            SortExpression="ProductName" />
        <asp:BoundField DataField="UnitPrice" HeaderText="Price"
            SortExpression="UnitPrice" DataFormatString="{0:c}"
            HtmlEncode="False" />
    </Columns>
</asp:GridView>

通过浏览器访问此页面。 如图 11 所示,GridView 列出了每个产品ProductIDProductName以及UnitPrice值。

GridView 显示每个产品的 ProductID、ProductName 和 UnitPrice 值

图 11:GridView 显示每个产品ProductIDProductNameUnitPrice值(单击以查看全尺寸图像

访问页面时,GridView 将调用其数据源控件的方法 Select() 。 当我们使用 ObjectDataSource 控件时,这称为 ProductsBLL 类的方法 GetProducts() 。 但是,使用 SqlDataSource 时,该方法 Select() 与指定的数据库建立连接并发出 SelectCommandSELECT [ProductID], [ProductName], [UnitPrice] FROM [Products]在本示例中)。 SqlDataSource 将返回其结果,GridView 随后枚举该结果,并在 GridView 中为每个返回的数据库记录创建一行。

内置数据 Web 控件功能和 SqlDataSource 控件

通常,数据 Web 控件固有的功能是特定于数据 Web 控件的分页、排序、编辑、删除、插入等,不依赖于所使用的数据源控件。 也就是说,GridView 可以利用其内置的分页、排序、编辑和删除是绑定到 ObjectDataSource 还是 SqlDataSource。 但是,某些数据 Web 控件功能对所使用的数据源控件或数据源控件的配置很敏感。

例如,在 “有效分页到大量数据” 教程中,我们讨论了数据 Web 控件的分页逻辑如何默认简单地从基础数据源返回所有记录,然后根据当前页索引和每页要显示的记录数量,仅显示相关的记录子集。 当分页到足够大的结果集时,此模型效率很高。 幸运的是,可以将 ObjectDataSource 配置为支持自定义分页,该分页仅返回要显示的记录的精确子集。 但是,SqlDataSource 控件缺少实现自定义分页的属性。

SqlDataSource 出现了另一个微妙的分页和排序。 默认情况下,可以从 SqlDataSource 返回的数据进行分页或排序,也可以通过 GridView 进行排序。 若要演示这一点,请检查 GridView 智能标记 Querying.aspx 中的“启用分页”和“启用排序”选项,并验证这是否按预期工作。

排序和分页的工作原理是 SqlDataSource 将数据库数据检索到松散类型的数据集中。 可以从 DataSet 确定查询返回的记录总数,这是实现分页的一个重要方面。 此外,数据集的结果也可以通过 DataView 进行排序。 当 GridView 请求分页或排序数据时,SqlDataSource 会自动使用这些功能。

可以通过将 SqlDataSource 的 DataSourceMode 属性从 DataSet(默认值)更改为 DataReader 来配置以返回 DataReader 而不是 DataSet。 在将 SqlDataSource 结果传递给需要 DataReader 的现有代码时,使用 DataReader 可能首选 DataReader。 此外,由于 DataReaders 比数据集要简单得多,因此它们可提供更好的性能。 但是,如果进行此更改,则数据 Web 控件既不能进行排序,也不能对页面进行排序,因为 SqlDataSource 无法确定查询返回的记录数,DataReader 也没有提供用于对返回的数据进行排序的任何方法。

步骤 4:使用自定义 SQL 语句或存储过程

配置 SqlDataSource 控件时,可以使用两种方法之一指定用于返回数据的查询作为自定义 SQL 语句或存储过程,也可以指定为现有表或视图中的列。 在步骤 2 中,我们检查了从 Products 表中选择列。 让我们看看如何使用自定义 SQL 语句。

将另一个 GridView 控件添加到 Querying.aspx 页面,然后选择从智能标记中的下拉列表创建新的数据源。 接下来,指示将从数据库拉取数据,这将创建新的 SqlDataSource 控件。 将控件 ProductsWithCategoryInfoDataSource命名为 。

创建名为 ProductsWithCategoryInfoDataSource 的新 SqlDataSource 控件

图 12:新建名为 的 SqlDataSource 控件 ProductsWithCategoryInfoDataSource

下一个屏幕要求我们指定数据库。 正如我们在图 7 中所做的那样,从下拉列表中选择 NORTHWINDConnectionString “下一步”。 在“配置 Select 语句”屏幕中,选择“指定自定义 SQL 语句”或存储过程单选按钮,然后单击“下一步”。 此时会显示“定义自定义语句”或“存储过程”屏幕,该屏幕提供标记为 SELECT、UPDATE、INSERT 和 DELETE 的选项卡。 在每个选项卡中,可以在文本框中输入自定义 SQL 语句,或从下拉列表中选择存储过程。 在本教程中,我们将了解如何输入自定义 SQL 语句;下一教程包含使用存储过程的示例。

输入自定义 SQL 语句或选取存储过程

图 13:输入自定义 SQL 语句或选取存储过程

自定义 SQL 语句可以手动输入到文本框中,也可以通过单击“查询生成器”按钮以图形方式构造。 在查询生成器或文本框中,使用以下查询从表中返回ProductID表的字段和ProductName字段,该查询Products使用从JOIN表中检索产品CategoryNameCategories

SELECT Products.ProductID, Products.ProductName, Categories.CategoryName
FROM Categories
    INNER JOIN Products ON
        Categories.CategoryID = Products.CategoryID

可以使用查询生成器以图形方式构造查询

图 14:可以使用查询生成器以图形方式构造查询

指定查询后,单击“下一步”转到“测试查询”屏幕。 单击“完成”以完成 SqlDataSource 向导。

完成向导后,GridView 将添加三个 BoundFields,其中显示了ProductIDProductName从查询返回的列和CategoryName列,并生成以下声明性标记:

<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ProductsWithCategoryInfoDataSource"
    EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="ProductID" HeaderText="ProductID"
            InsertVisible="False" ReadOnly="True" SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" HeaderText="ProductName"
            SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName" HeaderText="CategoryName"
            SortExpression="CategoryName" />
    </Columns>
</asp:GridView>
<asp:SqlDataSource ID="ProductsWithCategoryInfoDataSource" runat="server"
    ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
    SelectCommand="
        SELECT Products.ProductID, Products.ProductName, Categories.CategoryName
        FROM Categories
        INNER JOIN Products ON Categories.CategoryID = Products.CategoryID">
</asp:SqlDataSource>

GridView 显示每个产品的 ID、名称和关联的类别名称

图 15:GridView 显示每个产品的 ID、名称和关联的类别名称(单击以查看全尺寸图像

总结

本教程介绍了如何使用 SqlDataSource 控件查询和显示数据。 与 ObjectDataSource 一样,SqlDataSource 充当代理,提供访问数据的声明性方法。 其属性指定要连接到的数据库和要执行的 SQL SELECT 查询;可以通过属性窗口或使用“配置数据源”向导来指定这些数据库。

SELECT本教程中介绍的查询示例返回了指定查询中的所有记录。 但是,SqlDataSource 控件可以包含 WHERE 参数的子句,其值以编程方式分配或从指定源自动拉取。 我们将在下一教程中了解如何创建和使用参数化查询!

快乐编程!

深入阅读

有关本教程中讨论的主题的详细信息,请参阅以下资源:

关于作者

斯科特·米切尔,七本 ASP/ASP.NET 书籍的作者和 4GuysFromRolla.com 的创始人,自1998年以来一直在与Microsoft Web 技术合作。 斯科特担任独立顾问、教练和作家。 他的最新书是《Sams 24小时自学ASP.NET 2.0》。 可以通过 mitchell@4GuysFromRolla.com 联系到他。

特别感谢

本教程系列由许多有用的审阅者审阅。 本教程的主要审阅者是 Susan Connery、Bernadette Leigh 和 David Suru。 有兴趣查看即将发布的 MSDN 文章? 如果是这样,请给我写信。mitchell@4GuysFromRolla.com