posts - 39,  comments - 256,  trackbacks - 10

ASP.NET 2.0中操作数据:使用SqlDataSource控件查询数据

英文原版  |   本教程的代码(C#  |   翻译目录   |   原文目录

导言

到目前为止,我们所做的教程都使用了一个包含表示层、业务逻辑层以及数据访问层的分层架构。在第一节教程(创建一个数据访问层)中,我们讲解了数据访问层(DAL),第二节教程(创建一个业务逻辑层)中,我们又讲解了业务逻辑层。从教程“使用ObjectDataSource展现数据”开始,我们看到了如何在这个架构里面,通过使用ASP.NET2.0中新出现的ObjectDataSource控件在表示层展示数据。

 

所有的这些教程都是使用这样的架构来操作数据的,当然,我们也可以绕过这个架构,直接在ASP.NET页面上访问、插入、更新以及删除数据库中的数据。要这样做的话,你需要将特定的数据库查询以及业务逻辑直接放到网页中。对于一个很大的或者很复杂的应用程序来说,设计、实现以及使用一个分层的架构,对其是否能够顺利完成以及日后的可升级性、可维护性都将是非常重要的。不过,对于一个非常简单的、就一个人用的小程序来说,开发一个所谓健壮的架构兴许就不那么必要了。

 

ASP.NET2.0提供了五个内建的数据源控件——SqlDataSourceAccessDataSourceObjectDataSourceXmlDataSource以及SiteMapDataSourceSqlDataSource可以用来直接访问和修改关系型数据库中的数据,比如Microsoft SQL ServerMicrosoft AccessOracleMySQL……等等。在本教程以及接下来的三个教程中,我们将讲解如何使用SqlDataSource,如何用它来查询数据库中的数据,以及如何用它来插入、更新、删除数据。

 

 

图一:ASP.NET2.0含有5个内建的数据源控件

 

比较ObjectDataSourceSqlDataSource

在概念上来讲,ObjectDataSourceSqlDataSource都是面向数据的简单代理。就像在教程“使用ObjectDataSource展现数据”中所讨论的那样,ObjectDataSource拥有一些指示对象类型的属性(Properties),这些对象类型提供了数据以及方法以便于查询、插入、更新以及删除。当ObjectDataSource的这些属性被配置好之后,一个数据Web控件(data Web control)——比如GridViewDetailsView或是DataList——就能够绑定它了,并通过ObjectDataSourceSelect()Insert()Delete()以及Update()方法与潜在的架构进行交互。

 

SqlDataSource提供了相同的功能,只不过是操作一个关系型数据库而不是一个对象库。通过SqlDataSource,我们需要给出一个数据库连接字符串,还有SQL语句或是存储过程,然后就可以执行插入、更新、删除、查询操作了。当调用SqlDataSourceSelect()Insert()Delete()以及Update()方法时,会连接到指定的数据库并发出相应的SQL查询。如下图所示,这些方法都替我们干了一些比较烦人的事情,包括连接数据库、发出查询请求以及返回查询结果。

 

 

图二:SqlDataSource就像一个数据库代理一样


注意:
在本教程中,我们主要讨论从数据库获取数据。在教程“使用SqlDataSource控件插入、更新以及删除数据”中,我们将看到如何配置SqlDataSource以支持插入、更新以及删除操作。

 

SqlDataSource控件与AccessDataSource控件

除了SqlDataSource控件之外,ASP.NET2.0还提供了一个叫做AccessDataSource的控件。这两个不同的控件让很多刚刚接触ASP.NET2.0的开发人员产生了误解,认为AccessDataSource控件就是专门为Microsoft Access设计的,而SqlDataSource控件则是专门为Microsoft SQL Server设计的。实际上,虽然AccessDataSource的确是专门为Microsoft Access而设计的,但SqlDataSource却是为任何能通过.NET访问的关系型数据库而设计的,包括任何兼容OleDbODBC的数据存储,比如Microsoft SQL ServerMicrosoft AccessOracleInformixMySQLPostgreSQL……等等。

 

AccessDataSource控件与SqlDataSource控件唯一的不同是数据库连接信息的指定方式。AccessDataSource控件仅需要一个指向Access数据库文件的路径即可,而SqlDataSource则需要一个完整的连接字符串。

 

第一步:创建包含SqlDataSource的页面

在介绍如何通过SqlDataSource控件直接操作数据库中的数据之前,让我们先在我们的WebSite项目中创建几个ASP.NET页面,这些页面将在本教程以及接下来的三个教程中用到。首先,添加一个叫做“SqlDataSource”的文件夹。然后,向这个文件夹中添加以下几个ASP.NET页面,还要确保每一个页面都关联到了Site.master页面:

·         Default.aspx

·         Querying.aspx

·         ParameterizedQueries.aspx

·         InsertUpdateDelete.aspx

·         OptimisticConcurrency.aspx

 

 

图三:SqlDataSource 相关的教程添加ASP.NET页面

 

SqlDataSource文件夹中的Default.aspx与其他文件夹中的一样,它将会列出这部分内容的所有教程。回忆一下,其实SectionLevelTutorialListing.ascx用户控件已经提供了这样的功能。那么,我们就直接把它从解决方案浏览器中拖到Default.aspx的设计视图里。

 

 

图四:Default.aspx 中添加SectionLevelTutorialListing.ascx用户控件

 

最后,把另外四个页面作为入口加入到Web.sitemap文件中。需要说明一下,你需要将下面的标记代码添加到“Adding Custom Buttons to the DataList and Repeater<siteMapNode>的后面:

 

 

 1<siteMapNode url="~/SqlDataSource/Default.aspx"
 2    title="Using the SqlDataSource Control"
 3    description="Work directly with database data using the SqlDataSource control.">
 4
 5    <siteMapNode url="~/SqlDataSource/Querying.aspx" title="Retrieving Database Data"
 6        description="Examines how to query data from a database that can then be
 7                     displayed  through a data Web control."/>
 8
 9    <siteMapNode url="~/SqlDataSource/ParameterizedQueries.aspx"
10        title="Parameterized Queries"
11        description="Learn how to specify parameterized WHERE clauses in the
12                     SqlDataSource's SELECT statement." />
13
14    <siteMapNode url="~/SqlDataSource/InsertUpdateDelete.aspx"
15        title="Inserting, Updating, and Deleting Database Data"
16        description="See how to configure the SqlDataSource to include INSERT, UPDATE,
17                      and DELETE statements." />
18
19    <siteMapNode url="~/SqlDataSource/OptimisticConcurrency.aspx"
20        title="Using Optimistic Concurrency"
21        description="Explore how to augment the SqlDataSource to include support for
22                     optimistic concurrency." />
23
24</siteMapNode>

 

 

更新了Web.sitemap之后,让我们花一点点的时间在浏览器中看看这个教程的网站。现在,左边的菜单就有了关于编辑、插入以及删除的教程的项目了。

 

 

图五:现在网站地图中有了所有SqlDataSource 教程的入口了

 

第二步:添加并配置SqlDataSource控件

首先,我们从SqlDataSource文件夹中打开Querying.aspx,并切换到设计视图。然后从工具箱中拖一个SqlDataSource控件到设计器中,并将其ID设置成ProductsDataSource。跟ObjectDataSource一样,SqlDataSource不会产生任何的输出呈现,所以它在设计器中表现为一个灰色的框框。要配置SqlDataSource,需要在它的智能标签上点击“配置数据源”链接。

 

 

图六:SqlDataSource 的智能标签中点击“配置数据源”链接

 

然后会弹出SqlDataSource控件的“配置数据源”向导。虽然这个向导的步骤跟ObjectDataSource的向导的步骤有所不同,但是最终的目的还是一样的——提供如何通过数据源获取、插入、更新以及删除数据的相关细节。对于SqlDataSource来说,我们必须指明需要用到的数据库并提供相关的SQL语句或是存储过程。

 

向导的第一步提示我们要指定一个数据库。下拉列表中列出了在这个WEB应用程序的App_Data文件夹中所找到的,以及那些已经添加到服务器浏览器的“数据连接”节点中的数据库。由于我们已经把App_Data文件夹中的NORTHWIND.MDF数据库的连接字符串添加到了我们项目的Web.config文件中,所以下拉列表中也有一个指向这个连接字符串的引用——NORTHWINDConnectionString。就选它了,然后点“下一步”。

 

 

图七:从下拉列表中选择NORTHWINDConnectionString

 

选好数据库之后,向导要求我们给出一个用于获取数据的查询。我们可以直接指定一个表或视图中的几个字段,也可以输入一个自定义的SQL语句或是一个存储过程。可以通过指定一个SQL语句或存储过程和“指定一个表或视图中的字段”这两个单选框来作出选择。

 

注意:对于这第一个例子,咱们就先选择“指定一个表或视图中的字段”吧。稍后我们会再回到这个向导并选择指定一个SQL语句或存储过程

 

当选中“指定一个表或视图中的字段”单选框之后,将出现“配置Select语句”页,图八向我们展示了这个页的屏幕截图。下拉列表中包含了Northwind数据库中的表和视图,被选中的表或视图的列将显示在下面的checkbox列表中。在这个例子中,我们就从Products表中返回ProductIDProductName以及UnitPrice三列吧。就像图八所显示的那样,做了上述选择之后,向导给出了相应的查询语句——SELECT [ProductID], [ProductName], [UnitPrice] FROM [Products]

 

 

图八:Products表中返回数据

 

当你在向导中配置好了从Products表中返回ProductIDProductName以及UnitPrice三列之后,点击“下一步”按钮。在这最后一个界面上,我们可以检查刚才配置好的查询的结果。点击“测试查询”按钮,就会执行刚才配置好的那个SELECT语句并将结果显示到表格中。

 

 

图九:点击“测试查询”按钮以复查你的SELECT查询

 

点一下“结束”按钮就可以完成这个向导了。(译者注:似乎中文版的软件中应该是“完成”按钮吧?没办法,我这里没有中文版的,各位自己灵活应变吧^_^

 

ObjectDataSource一样,这个SqlDataSource的向导不过是向其ConnectionString属性以及SelectCommand属性赋值罢了。完成了这个向导之后,你的SqlDataSource控件的声明标记代码应该是下面这个样子:

 

 

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

 

 

ConnectionString属性提供了如何连接到数据库的相关信息。这个属性可以被赋予一个完整的、硬编码的连接字符串,也可以指向Web.config中的连接字符串。要引用Web.config中的连接字符串,需要使用语法<%$ expressionPrefix:expressionValue %>。一般来说,expressionPrefix就是“ConnectionStrings” expressionValue则是Web.config<connectionStrings> 中的连接字符串的名字。不过,这个语法还可以用来引用<appSettings>元素或资源文件中的内容。关于这个语法的详细信息,请参见ASP.NET 表达式概览

 

SelectCommand属性给出了一个用于返回数据的SQL语句或是存储过程。

 

第三步:添加一个数据Web控件,并绑定SqlDataSource

SqlDataSource被配置好之后, 它就可以被绑定到一个数据Web控件上了,比如GridView或者DetailsView。在本教程中,我们就用一个GridView来显示数据吧。从工具箱中拖一个GridView 到页面上,并绑定ProductsDataSource(在GridView的智能标签中的下拉列表里面选择一个叫做ProductsDataSourceSqlDataSource就可以完成这个任务了)

 

 

图十:添加一个GridView控件,并绑定一个SqlDataSource控件

 

一旦你从GridView的智能标签的下拉列表中选择了一个SqlDataSource控件,Visual Studio将自动的为数据源控件所返回的每一列向GridView添加一个BoundFieldCheckBoxField。由于SqlDataSource返回了三个数据库列——ProductIDProductName以及UnitPrice——GridView中将会出现三个字段。

 

花一点时间来配置GridView中的这三个BoundField。把ProductName 字段的HeaderText属性更改为“Product Name”UnitPrice字段的HeaderText属性更改为“Price”。还要把UnitPrice字段的格式改成货币。做了这些修改之后,你的GridView声明标记代码应该是下面这个样子:

 

 

 1<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
 2    DataKeyNames="ProductID" DataSourceID="ProductsDataSource"
 3    EnableViewState="False">
 4    <Columns>
 5        <asp:BoundField DataField="ProductID" HeaderText="ProductID"
 6            InsertVisible="False" ReadOnly="True" SortExpression="ProductID" />
 7        <asp:BoundField DataField="ProductName" HeaderText="Product Name"
 8            SortExpression="ProductName" />
 9        <asp:BoundField DataField="UnitPrice" HeaderText="Price"
10            SortExpression="UnitPrice" DataFormatString="{0:c}"
11            HtmlEncode="False" />
12    </Columns>
13</asp:GridView>

 

 

通过浏览器访问这个页面. 就像图十一所展示的那样,GridView列出了每一个产品的ProductIDProductName以及UnitPrice的值。

 

 

图十一:GridView列出了每一个产品的ProductIDProductName以及UnitPrice的值

 

当页面被访问时,GridView就调用它的数据源控件的Select()方法。当年我们在使用ObjectDataSource控件的时候,这里调用的是ProductsBLL类的GetProducts()方法。然而在SqlDataSource中,Select()方法将建立一个到指定数据库的连接,并发出其SelectCommand(在这个例子中是SELECT [ProductID], [ProductName], [UnitPrice] FROM [Products], in this example)。然后GridView便枚举SqlDataSource返回的结果,并为每一个数据库记录创建一个行。

 

内建的数据Web控件的特性以及SqlDataSource控件

通常来说,数据Web控件所固有的特性——如分页、排序、编辑、删除以及插入等等——是不关心是否使用了数据源控件的。也就是说,GridView可以利用其内建的各种操作,而不用理会是否使用了ObjectDataSourceSqlDataSource。然而,数据Web控件的某些特性却对是否使用了数据源控件或数据源控件的配置是敏感的。

 

例如,在教程大数据量时提高分页的效率中我们讨论过,默认情况下,数据Web控件内建的分页逻辑从指定的数据源返回所有的记录,然后根据给定的页码以及每页显示的条数显示一个正确的子集。在对一个较大的记录集分页的时候,这个模型是非常低效的。幸运的是,ObjectDataSource可以被配置为支持自定义分页,以精确的返回需要显示的记录子集。然而,SqlDataSource却缺少用于实现自定义分页的属性。

 

SqlDataSource中出现了另外的关于分页和排序的小东西。默认情况下,SqlDataSource返回的数据将通过GridView来分页和排序。为了说明这个,请在Querying.aspx中的GridView的智能标签中勾上“允许分页”和“允许排序”,看看是不是像我们预期的那样?

 

分页和排序都如预期的那样工作了,这是因为SqlDataSource把获取到的数据放到了一个弱类型的DataSet中。查询所返回记录的总数——实现分页所不可或缺的部分——可通过这个DataSet弄清楚。此外,DataSet的结果还可以通过DataView来进行排序。在GridView需要对数据进行分页或排序时,这些能力将自动的被SqlDataSource使用。

 

SqlDataSource可以被配置为返回一个DataReader而不是DataSet,只需要将其DataSourceMode属性DataSet(默认)改成DataReader即可。在需要将SqlDataSource的结果传递给现有的需要DataReader的代码时,使用DataReader可能是比较好的做法。而且,由于DataReader是比DataSet简单很多的对象,所以它们能提供更好的性能。不过,如果你做了这样的修改,数据Web控件将不能再进行分页,因为SqlDataSource不能准确的获知到底有多少记录被返回,当然也不能进行排序,因为DataReader根本就没有提供任何可用于对返回的数据进行排序的技术。

 

第四步:使用自定义SQL语句或存储过程

配置SqlDataSource控件时,用于返回数据的查询可以通过两种方式进行指定,一个是自定义SQL语句或存储过程,另一个是指定某个已经存在的表或视图的列。在第二步中,我们选择了后者,现在,我们来试试自定义SQL语句的方式。

 

Querying.aspx添加另外一个GridView控件,并在其智能标签的下拉列表中选择“创建一个新的数据源”。然后声明数据将从一个数据库中弄出来——这将会创建一个新的SqlDataSource控件,我们给它命名为ProductsWithCategoryInfoDataSource

 

 

图十二:创建一个新的名为ProductsWithCategoryInfoDataSourceSqlDataSource控件

 

下一个页面要我们指定一个数据库。像我们在图七中所做的那样,从下拉列表中选择NORTHWINDConnectionString,然后点击“下一步”。在“配置Select语句”页,选择指定一个自定义SQL语句或存储过程单选框,并点击“下一步”。这时会显示定义自定义语句或存储过程页,这里提供了SELECTUPDATEINSERT以及DELETE等标签。在每一个标签下面,你都可以在Textbox中输入一个SQL语句或在下拉列表中选择一个存储过程。本教程中,我们还是关注输入自定义SQL语句,下一个教程中将包含一个使用存储过程的例子。

 

 

图十三:输入一个自定义SQL语句或选择一个存储过程

 

自定义SQL语句可以完全通过手写的方式输入到Textbox中,也可以通过点击“查询生成器”按钮来图形化的创建。不管怎么样,我们都要使用如下的查询来返回Products表中的ProductIDProductName列,并通过一个JOINCategories表中获取产品的CategoryName

 

 

1SELECT Products.ProductID, Products.ProductName, Categories.CategoryName
2FROM Categories
3    INNER JOIN Products ON
4        Categories.CategoryID = Products.CategoryID

 

 

 

图十四:你可以通过查询生成器来图形化的构造一个查询

 

在指定了查询之后,点击“下一步”以前进到“测试查询”页。点击“结束”以完成这个SqlDataSource向导。

 

完成了向导之后,GridView将会包含3BoundField分别用于显示查询所返回的ProductIDProductName以及CategoryName列。现在的声明标记代码如下所示:

 

 

 1<asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False"
 2    DataKeyNames="ProductID" DataSourceID="ProductsWithCategoryInfoDataSource"
 3    EnableViewState="False">
 4    <Columns>
 5        <asp:BoundField DataField="ProductID" HeaderText="ProductID"
 6            InsertVisible="False" ReadOnly="True" SortExpression="ProductID" />
 7        <asp:BoundField DataField="ProductName" HeaderText="ProductName"
 8            SortExpression="ProductName" />
 9        <asp:BoundField DataField="CategoryName" HeaderText="CategoryName"
10            SortExpression="CategoryName" />
11    </Columns>
12</asp:GridView>
13
14<asp:SqlDataSource ID="ProductsWithCategoryInfoDataSource" runat="server"
15    ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>"
16    SelectCommand="
17        SELECT Products.ProductID, Products.ProductName, Categories.CategoryName
18        FROM Categories
19        INNER JOIN Products ON Categories.CategoryID = Products.CategoryID">
20</asp:SqlDataSource>

 

 

 

图十五:GridView显示了每一个产品的ID、名称以及相应的分类

 

总结 

在本教程中,我们看到了如何通过SqlDataSource控件进行查询并显示数据。跟ObjectDataSource一样,SqlDataSource就像一个代理一样,提供了一个明确的方法以访问数据。它的属性指明了需要连接的数据库以及用来执行的SQL SELECT查询,它们也都可以通过属性窗口或配置数据源向导来进行指定。

 

本教程中我们所给出的SELECT查询将返回查询得到的所有记录。然而,SqlDataSource控件可以含有一个带参数的WHERE子句,其值可以通过编程的方式指定或从某个指定的源自动获取。我们将在下一节中介绍如何创建和使用参数化查询。

 

编程愉快!

 

关于作者

Scott Mitchell,著有六本ASP/ASP.NET方面的书,是4GuysFromRolla.com的创始人,自1998年以来一直应用微软Web技术。Scott是个独立的技术咨询顾问,培训师,作家,最近完成了将由Sams出版社出版的新作,24小时内精通ASP.NET 2.0。他的联系电邮为mitchell@4guysfromrolla.com,也可以通过他的博客http://ScottOnWriting.NET与他联系。

posted on 2007-08-15 12:31 电机拖动 阅读(...) 评论(...) 编辑 收藏