鱼遇于池,池涸,相濡以沫,相鞠以湿,不若相忘于海。

while (alive) {
  object state = working & fighting & enjoying & living thanksgiving;
}
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

[笔记]ASP.NET 2.0 Preview -- Performing Data Access [I]

Posted on 2005-09-04 16:52  alittlefish  阅读(3085)  评论(0)    收藏  举报

Binding to Databases

web应用程序中显示的数据往往都来源于一个SQL数据库。SqlDataSource控件提供了一个桥梁,使Data-Bound控件可以方便的获取数据进行绑定。SqlDataSource可以代替应用程序中连接数据库、执行查询语句等的ADO.NET代码。因为查询、连接的细节被作为了SqlDataSource的属性,而这些细节信息都处于ASP.NET的页面中,所以一般情况下它都被作为一种两层的模型。出于这个原因,SqlDataSource通常只被用于轻量级的或者个人的站点中,在需要对获取到的数据进行带有业务逻辑的封装或者其他一些对数据操作相对复杂的情况下,它就并不合适了。后面的章节将介绍ObjectDataSource这个控件,他能为大型企业应用提供数据访问的分层支持。

GridView
GridView是ASP.NET2.0中提供的一种新的数据绑定控件,他与1.x下的DataGrid类似,或者说他是DataGrid的一个更好的替代,他提供了更简单的对象模型。GridView的每一行对应一条数据记录,每一列对应一个数据的字段。

概括的讲,GridView提供对以下特性的支持:
·与数据源控件进行绑定;
·内建的数据排序能力;
·内建的更新删除记录的能力;
·内建的分页支持能力;
·内建的记录行选择的能力;
·可编程的获取GridView的对象模型,以便可以动态的设置GridView对象的各个属性,并且编程处理其事件;
·增加了新的控件列的类型,比如显示CheckBox(复选框)和Image(图片)的控件列;
·对超链接列控件提供了多字段绑定;
·选择、更新以及删除时提供了多键值的支持;
·可根据主题以及样式自定义空间的外观。

创建数据报表
数据驱动的web页的最简单的应用就是只读的数据报表的显示,它提供对数据的内容的表示,但不允许用户更改其显示逻辑和内部数据。这里我们以根据SqlServer数据库中的数据创建一个数据报表为例,首先需要使用到SqlDataSource控件,该控件作为数据源的获取方式,然后将其绑定到GridView控件上,这里我们只需要将GridView的DataSourceID设置为SqlDataSource控件的ID,即可以完成所需要的操作。

<form runat="server">
  
<asp:GridView ID="GridView1" DataSourceID="SqlDataSource1" runat="server"/>
  
<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
    SelectCommand
="SELECT [au_id], [au_lname], [au_fname] FROM [authors]"
    ConnectionString
="<%$ ConnectionStrings:Pubs %>" />
</form>


SqlDataSource控件有几个特殊的属性,ConnectionString用来指定访问数据库的字符串,SelectCommand用来指定需要执行的查询字符串。在这里ConnectionString可以在页面中被定义成名文的形式,但是上面这个例子则使用了一种新的表达式,该表达式在上面一篇文章中提到过,在这里,这个表达式由web.config中的一个节点的值来替换。

SqlDataSource控件不仅仅支持Microsoft SQL Server这一种数据库的链接,实际上它可以连接任何托管的ADO.NET数据提供者,这些对象可以参见System.Data.Common.DbProviderFactory。默认情况下,在machine.config中提供了四种数据提供者:

<configuration>
  
<system.data>
    
<DbProviderFactories>
      
<add name="Odbc Data Provider" invariant="System.Data.Odbc" type="System.Data.Odbc.OdbcFactory, " />
      
<add name="OleDb Data Provider" invariant="System.Data.OleDb" type="System.Data.OleDb.OleDbFactory, " />
      
<add name="OracleClient Data Provider" invariant="System.Data.OracleClient" type="System.Data.OracleClient.OracleClientFactory, " />
      
<add name="SqlClient Data Provider" invariant="System.Data.SqlClient" type="System.Data.SqlClient.SqlClientFactory, " />
    
</DbProviderFactories>
  
</system.data>
</configuration>


SqlDataSource的ProviderName可以被设置为数据提供者工厂里的任何一个成员的invariant的值(默认的是System.Data.SqlClient)。如果你改动了ProviderName的值的话,必须保证ConnectionString与SelectCommand这两个属性的都使用了与指定数据提供者相对应的语法格式。

SelectCommand这个属性也可以设置为存储过程的名字,为了使SqlDataSource执行对存储过程的访问,我们需要将SelectCommandType这个属性设置为StoredProcedure。

默认情况下,SqlDataSource返回一个DataView对象,该对象从查询结果填充后的DataSet中获得。我们也可以通过设置SqlDataSourceMode这个属性,比如将其设置为“DataReader”,来使SqlDataSource返回不同的对象实例。一般情况下,如果是只读的并且是forward-only的形式访问数据,比较建议使用DataReader这个方式返回数据,它比以DataSet的形式返回数据来的更高效。但是如果使用了DataReader,则SqlDataSource控件的排序功能将不能得以实现。

数据库连接字符串的设置
ASP.NET2.0中对数据库连接字符串的设置提供了一个很方便的办法(其实我们在1.x里也是这么做的,只是需要自己编写额外的代码)。只需要在web.config中为connectionString这个节点作具体的设置就可以了。这样只要在web.config里做了设置,整个应用程序都可以方便的获取到指定的连接字符串,方便了维护。

<configuration>
  
<connectionStrings>
    
<add name="Pubs" connectionString="Server=(local);Integrated Security=True;Database=pubs;"
      providerName
="System.Data.SqlClient" />
  
</connectionStrings>
</configuration>


当然,在web.config中存储连接字符串不仅仅是为了方便维护,同样,他也增强了应用程序的安全性。ASP.NET2.0提供一个命令行的工具,他可以对连接字符串进行加密(关于对连接字符串的加密我会在后面的总结中具体介绍)。

分页与排序
GridView在数据绑定控件中的一个优点就是他可以利用数据源对象的一些特点完成一些自动化的操作。除了通过少量的编码完成对数据集合的排序或者分页以外,他还可以利用支持这些方法(例如排序)的数据源对象来自动完成这些操作。

我们都知道DataSet(准确地说是DataView)提供对数据的排序,对于SqlDataSource控件,我们刚才说了,可以设置DataSourceMode来让SqlDataSource返回不同类型的数据源对象,如果我们把这个属性设置为DataSet,通过将GridView的AllowSorting属性设置为true,以及传递一个排序字符串给SqlDataSource(通过设置GridView的SortExpression),就可以非常方便的完成数据排序。

虽然不同的数据提供者对查询结果排序的语法不同,但是在这里,SqlDataSorce所接受的排序语法对应的是System.Data.DataView的Sort语法,而且此处对排序的支持其实正是因为SqlDataSource可以返回DataView,所以,仅仅当使用SqlDataSource作为数据源控件,并且其DataSourceMode被设置为DataSet的时候,才可以使用自动排序。这里可以注意一点,SortExpression对应的是GridView中的某一列的字段名称,而且在每次点击排序连接的时候,GridView也会自动的添加ASC或DESC的后缀,以保持升序与降序之间的切换。

(如果SortExpression设置为返回的DataView中某一列的字段名称,而这一列并没有显示在GridView上,是否会报错?)

再来看看分页,一般情况下,只要我们把GridView的AllowPaging属性设置为true,GridView就可以自动的完成分页。但是这里有个前提条件,就是只有在GridView绑定的数据源对象实现了ICollection接口,才可以保证GridView完成自动分页。举个例子,当SqlDataSource的DataSourceMode设置为DataSet时,由于返回的数据源对象是一个DataView,而他实现了ICollection这个接口,所以我们说GridView支持对这种数据源的自动分页;而相反,如果是以DataReader作为数据源,由于它并未实现指定的接口,所以GridView无法自动完成分页操作。

另外,我们可以通过设置PagerStyle以及PagerSetting来自定义分页的样式。PageStyle定义分页的样式的效果,而PagerSetting则定义了分页显示的种类(页码 or “上一页”、“下一页”),分页显示的位置以及相关的属性。

注意上面说的这些分页都是属于把分页逻辑混在GridView的Render的过程中的,通常这种分页被称为“UI Paging”,显示的数据只是返回的数据中的一部分,而那些不在指定分页中的数据都被丢弃掉了。后面的章节里会介绍另外一种分页方式,这里暂时不做太多熬述。

更新以及删除数据
与分页和排序一样,通过GridView控件与SqlDataSource控件的配合,也可以完成对数据更新和删除的自动操作。SqlDataSource控件提供了UpdateCommand以及DeleteCommand这两个属性,他们分别指定数据源更新以及删除所使用的Sql查询语句或者存储过程名称,如果这两个属性设置的是Sql命令,则命令中必须包含需要的参数,这些参数的实际值则由GridView传递得到;如果设置的是存储过程名,则使用UpdateParameters以及DeleteParameters来定义参数集合,我们可以为这些参数设置数据类型,传递方向,默认值的属性,同样的,这些参数对应的也是GridView的每一列的值。

<asp:SqlDataSource ID="SqlDataSource1" runat="server"
  ConnectionString
="<%$ ConnectionStrings:Pubs %>"
  SelectCommand
="SELECT [au_id], [au_lname], [au_fname], [state] FROM [authors]"
  UpdateCommand
="UPDATE [authors] SET [au_lname] = @au_lname, [au_fname] = @au_fname, [state] = @state WHERE [au_id] = @original_au_id"
  DeleteCommand
="DELETE FROM [authors] WHERE [au_id] = @original_au_id"/>


通过将GridView控件的AutoGenerateEditButton或AutoGenerateDeleteButton属性设置为true,或者添加一个CommandField的列并且将ShowEditButton或者ShowDeleteButton设置为true,就可以使GridView控件自动创建更新或者删除的显示逻辑。与1.x一样,在更新与删除操作中起到重要作用的还有一个“数据键”,2.0支持多数据键,所以这个属性从1.x的DataKeyField变成了DataKeyNames。DataKeyNames包含了数据源中每条记录中代表主键的那些字段的名称,这些键名之间以逗号分隔。因为在更新或者删除中需要用到数据键的原始值,因此被定义在DataKeyNames中的那些字段值会被保存在ViewState中在客户端与服务器端来回传递。

这里需要注意的一个地方是UpdateCommand属性中Sql语句的参数命名的规则。为了使GridView可以自动完成更新操作,代表需要更新的字段的值(当GridView控件的某一行被设置为编辑模式时,用户更改的那个字段的值)的参数名必须与SqlDataSource的SelectCommand查询返回结果中的字段名相同;而该字段原始值(在GridView的数据行被设置为编辑模式前的字段值)的参数名则需要加上前缀“original_”。

GridView将更新字段保存在与原始查询结果的字段数据不同的键值对中,换句话说,更新过的字段其数据的键值对有两份,一份是原始数据,一份是更新数据。而原始数据中的键名称基于原始字段名称作了一定的重新格式化。默认情况下,更新数据的键名同字段名,而原始数据的键名
加上了“original_”的前缀。这样,在SqlDataSource与底层ADO.NET通信完成更新操作时,更新的数据不会与原始数据混淆。不过,我们也可以通过设置SqlDataSource控件的OldValuesParameterFormatString属性,来定义一个不同的字段原始数据的键名格式。比如,默认情况这个值为“original_{0}”,如果在字段的原始值与更新值不会发生冲突的情况下(字段值不变),则完全可以将这个属性设置为“{0}”。

当执行删除操作时,由于没有更新字段的值,因此SqlDataSource使用原始数据的键值对,因此OldValuesParameterFormatString可以被看成“{0}”,即原始字段键值不变。

筛选数据
数据驱动的web页面的一个特性就是选择性的显示数据。比如,通过选择一个下拉框的不同选项获取匹配的不同数据显示。在ASP.NET 1.x中,我们必须书写以下步骤的代码:
1. 在页面回发的时候取消DataBinding操作;
2. 定义下拉框的SelectedIndexChanged事件的处理函数;
3. 将下拉框的选定值加入命令对象的参数集合中;
4. 执行命令并调用DataBind。

在2.0中,可以通过显示的调用Data Parameter对象来完成以上的操作,不需要多写任何多余的代码。一个数据参数对象允许将外部的数据关联到数据源的操作上,这些参数通常对应着命令表达式中参数(例如SqlDataSource控件的Command属性提供的SQL语句或存储过程的参数)的值。数据源控件对各种数据操作(Select、Update、Delete等)提供关联到各种Data Parameter对象的参数值的支持。例如下面的代码:

<asp:DropDownList ID="DropDownList1"  runat="server"/>

<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
  ConnectionString
="<%$ ConnectionStrings:Pubs %>"
  SelectCommand
="SELECT [au_id], [au_lname], [au_fname], [state] FROM [authors] WHERE [state] = @state">
  
<SelectParameters>
    
<asp:ControlParameter Name="state" ControlID="DropDownList1" PropertyName="SelectedValue" />
  
</SelectParameters>
</asp:SqlDataSource>


我们可以设置数据操作的参数集合,使其关联到各种不同的Data Parameter对象。以下列出各种Data Parameter:
·Parameter
  Parameter类是一个基础的数据参数的实现,其他所有的数据参数对象都是其子类。Parameter也可以作为静态参数,通过设置DefaultValue来传递值给命令对象。

  Parameter对象定义了一个Name的属性,这个名称对应的就是数据源控件(比如SqlDataSource)的查询命令中参数的名称。同时Parameter通过Type属性定义了对应参数的数据类型。

  当数据源控件的查询命令被定义为存储过程时,参数对象会有传递方向的区别。Parameter对象通过一个Direction属性来区别参数的传递方向(Input、Ouput以及ReturnValue,或者Input and Output)。

·QueryStringParameter
  QueryStringParameter对象将数据操作命令的参数关联到当前web请求的QueryString项,通过QueryStringField属性来设置QueryString中与查询命令中的参数匹配的数据项的名称。这里需要注意的是,如果QueryString中不存在指定的项,或者该项不存在有效值,就会返回DefaultValue属性的值。

·ControlParameter
  ControlParameter对象将参数值关联到了页面控件的指定属性上。ControlID属性用来指定被关联的控件ID,PropertyName属性用来指定参数值对应控件的哪个具体的属性。而被关联的控件对象一般会有一个可选的ControlValuePropertyAttribute属性,它定义了默认关联到参数的属性名称。以下列举部分控件的ControlValuePropertyAttribute:
   ·Label.Text
   ·TextBox.Text
   ·ListControl.SelectedValue (for example, DropDownList)
   ·CheckBox.Checked
   ·Calendar.SelectedDate
   ·DetailsView.SelectedValue
   ·GridView.SelectedValue
   ·TreeView.SelectedValue
   ·FileUpload.FileBytes

·SessionParameter
  SessionParameter对象将参数值关联到Session对象集合的指定数据项。通过SessionField属性定义关联的Session对象的键名。与QueryStringParameter对象一样,如果指定的Session键值不存在,则返回DefaultValue属性的值。

·FormParameter
  FormParameter对象将参数关联到网页表单的某个元素的值。通过FormField属性定义关联到的表单元素名称。如果指定的表单元素不存在,则返回DefaultValue属性的值。

·CookieParameter
  CookieParameter对象将参数值关联到HttpCookie对象集合的指定数据项。通过CookieName属性定义关联的Cookie对象的键名。如果指定的Cookie键值不存在,则返回DefaultValue属性的值。

·ProfileParameter
  ProfileParameter对象将参数值关联到User Profile对象。ParameterName属性定义了与参数匹配的User Profile对象的字段值。如果User Profile对象中的指定字段不存在有效的值,则返回DefaultValue的值。