一个经得起时间考验的人
ASP.net
ASP.net
来点WebCast的SPS的资料
七 11th
|
以下是您查询的微软TechNet中文网络广播课程。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
防洪保安资金金额类开发心得
六 4th
(1)decimal mj=Decimal.Parse(dr["zdmj"].ToString());
原来从DataRow中取得的记录为对象,需要经过转换才能使用的呢!
(2)下面的语名,据说可以防止SQL注入
SqlDataAdapter mjselectCommand = new SqlDataAdapter ( "select jsydmj from jsydxx where xmbh = @xmbh",con);
mjselectCommand.SelectCommand .Parameters .Add ( new SqlParameter ( "@xmbh",SqlDbType.Char ,20 ) );
mjselectCommand.SelectCommand .Parameters [ "@xmbh" ].Value = strxmbh;
(3)/* 应用ExecuteScalar 未使用视图 取出收费标准*/
string strsql ="select xzfbz.sfbz from xzfbz,xzfdjqy,jsydxx where xzfbz.sfjb = xzfdjqy.qydj and xzfdjqy.xsqbh = jsydxx.xsqbh ";
strsql += "and jsydxx.xmbh = @xmbh";
SqlCommand bzselectCommand = new SqlCommand ( strsql, con );
bzselectCommand.Parameters .Add ( new SqlParameter ( "@xmbh",SqlDbType.Char ,20 ) );
bzselectCommand.Parameters [ "@xmbh" ] .Value = strxmbh;
con.Open ();
double bz = Convert.ToDouble ( bzselectCommand.ExecuteScalar () );
con.Close ();
/* ————————————–*/
(4)在开发中使用了Join On来组合查询,只是还不太熟悉,需要更进一步地学习.
(5)使用Top 1来提高查询的效率.至于为什么能有这样的效果,想知道的自己想想吧.
(6)编写详细的注释.
(7)尽量地少用DataSet(它会大量地占用服务器的内存),特别是在只处理一个记录的时候.
(8)对使用到的数据表和数据库进行详细的说明和注释.
(9)Convert.ToDouble(sqlreader.GetSqlMoney(0).ToString()):可以用来进行数据类型的转换.它是多种方法可用.这是一个处理Money类型的例子.下面是更多的例子.
cost=Convert.ToDouble(sqlreader.GetDecimal(0));
temp=Decimal.Round(Decimal.Multiply(zdmj,new Decimal(cost)),2);
Decimal.Divide
throw new Exception()
cmd.CommandText=sub_sql
Visual Studio .NET 中的设计时数据工具
五 24th
数据库设计
以下工具允许您在 Visual Studio 中创建和编辑数据库结构。
| 工具 | 说明 | 更多信息 |
|---|---|---|
| Server Explorer | 查看和处理任何您可以通过网络访问的服务器上的数据链接、数据库连接以及系统资源。 | Connecting to Remote Resources with Server Explorer |
| Data Link Properties Dialog Box | 配置连接字符串。 | Adding New Data Connections in Server Explorer |
| Visual Database Tools | 创建和维护数据库;通常从 Server Explorer(服务器资源管理器)进行访问。 | Work You Can Do With the Visual Database Tools |
数据适配器
数据适配器是 ADO.NET 对象,其中包含对 SQL 命令或存储过程的引用,用于向数据集中填充数据以及从数据集中将更改信息重新写入数据存储中。
| 工具 | 说明 | 更多信息 |
|---|---|---|
| Data Adapter Configuration Wizard | 设置新的或现有的数据适配器的属性。 | Creating Data Adapters Using a Wizard |
| Data Adapter Preview Dialog Box | 查看如何将数据填充到数据集中。 | ADO.NET Data Adapters |
| Table Mappings Dialog Box | 指定适配器如何将数据源中的列转换为数据集表中的列。 | Table Mapping in Data Adapters |
数据集
数据集将数据存储在一个断开连接的缓存中。以下工具允许您在应用程序中创建,生成,编辑和使用 ADO.NET 数据集。
类型化数据集
类型化数据集由以下各项定义:
- XML Schema,XML 架构说明了数据集中的表、列、键和各项之间的关系;
- 类文件,类文件继承自 System.Data.DataSet,并实现了一些成员,以便访问具有该指定架构的数据集。
因此,用于类型化数据集的工具包括那些用于编辑 XML 架构的工具,因为架构用于定义数据集的结构。
| 工具 | 说明 | 更多信息 |
|---|---|---|
| Generate Dataset Dialog Box | 生成数据集架构和类型化数据集类。结构从指定的数据适配器中推断出。 | ADO.NET Datasets |
| Add Dataset Dialog Box | 向应用程序中添加类型化或非类型化数据集实例。 | Introduction to Datasets |
| Dataset Properties Dialog Box | 在只读窗口中显示数据集的结构。 | Visual Studio Tools for Creating Datasets |
| XML Designer | 以可视化方式为数据集创建和编辑 XML 架构。 | XML Schemas and Data |
| Edit Key Dialog Box | 为定义关系数据结构的 XML 架构创建和编辑主键定义。 | Creating Primary and Unique Keys in XML Schemas |
| Edit Relation Dialog Box | 创建和编辑定义了数据结构之间的关系的 XML 元素,例如外键关系。 | Introduction to DataRelation Objects |
非类型化数据集
非类型化数据集是 System.Data.DataSet 类的实例。数据集的结构不通过架构定义,而是在运行时编程实现的,或者通过集合编辑器(通过属性窗口访问)定义,下表对其进行了说明。
| 工具 | 说明 | 更多信息 |
|---|---|---|
| Add Dataset Dialog Box | 向应用程序中添加类型化或非类型化数据集实例。 | Introduction to Datasets |
| Tables Collection Editor | 在非类型化数据集中添加和编辑表。 | Adding Untyped Datasets to a Form or Component |
| Columns Collection Editor | 在非类型化数据集中添加和编辑列。 | Adding Untyped Datasets to a Form or Component |
| Constraints Collection Editor | 在非类型化数据集中添加和编辑约束。 | Adding Untyped Datasets to a Form or Component |
| Relations Collection Editor | 向非类型化数据集中添加关系。 | Introduction to DataRelation Objects |
| Relation Dialog Box | 在非类型化数据集中编辑关系。 | Introduction to DataRelation Objects |
数据绑定
数据绑定定义了数据如何显示在窗体的控件中。对于 Windows 窗体,还定义了如何格式化数据并将它重新写入数据源。
下面是在 Windows 窗体中进行数据绑定的可用工具。
| 工具 | 说明 | 更多信息 |
|---|---|---|
| Data Form Wizard | 创建带有数据绑定控件的 Web 窗体页或 Windows 窗体。 | Data Form Wizard Generated Code |
| Advanced Data Binding Dialog Box | 将控件的属性窗口中出现的任何属性绑定到值(从有效的数据提供程序到 Windows 窗体等)。 | Data Binding and Windows Forms |
XML 架构和文件
以下工具允许您创建 XML 架构并直接编辑 XML 文件。XML 架构可用于定义类型化数据集的结构,也可用于定义任何 XML 文件的结构。
| 工具 | 说明 | 更多信息 |
|---|---|---|
| XML Designer | 可视化地创建和编辑 XML 架构。 | XML Schemas and Data |
| Edit Key Dialog Box | 为定义关系数据结构的 XML 架构创建和编辑主键定义。 | Creating Primary and Unique Keys in XML Schemas |
| Edit Relation Dialog Box | 创建和编辑定义了数据结构之间的关系的 XML 元素,例如外键关系。 | Introduction to DataRelation Objects |
设计和管理数据库结构的工具
在 Visual Studio 中,可以使用各种工具查看数据库中的数据,以及添加和编辑数据库结构(例如表、列、数据库关系图、存储过程、函数和触发器等)。实际上,可以使用数据库自带的工具集完成的大部分任务都可以使用 Visual Studio 工具来执行。在设计时,可以通过 Server Explorer 访问大多数数据工具。
创建连接
在管理一个数据库之前,必须首先建立与该数据库的连接。用于创建连接的设计工具是 Data Link Properties Dialog Box。
| 目的 | 操作 | 更多信息 |
|---|---|---|
| 连接到数据源 | 从 Tools(工具)菜单或 Server Explorer(服务器资源管理器)中,单击 Connect to Database(连接到数据库)。 | Adding New Data Connections in Server Explorer |
添加和修改数据库元素
在 Server Explorer(服务器资源管理器)中用于处理数据的工具是 Visual Database Tools。要访问可视化数据库工具,请右击 Server Explorer(服务器资源管理器)中的相应区域。例如,要创建新表,请展开数据连接直到看见 Tables(表)节点。右击 Tables(表)节点,然后在快捷菜单上单击 New Table(新建表)。
注意:Visual Studio 数据工具的功能取决于所连接的各个数据源。例如,同处理其他数据库相比,Visual Studio 为处理 SQL Server 数据库提供了更多的工具。
以下设计时工具可用于数据库元素。
| 目的 | 操作 | 更多信息 |
|---|---|---|
| 创建新的 SQL Server 数据库 | 右击 Data Connections(数据连接)节点,然后在快捷菜单上单击 Create New SQL Server Database(创建新的 SQL Server 数据库)。 | Creating a New SQL Server Database in Server Explorer |
| 修改数据库连接 | 右击数据库节点,然后在快捷菜单上单击 Modify Connection(修改连接)。 | Data Link Properties Dialog Box |
数据库关系图
| 目的 | 操作 | 更多信息 |
|---|---|---|
| 创建新的数据库关系图 | 右击 Database Diagrams(数据库关系图)节点,然后在快捷菜单上单击 New Diagram(新建关系图)。 | Creating a New Database Diagram |
| 编辑现有的数据库关系图 | 右击要编辑的数据库关系图,然后在快捷菜单上选择 Design Database Diagram(设计数据库关系图)。 | Opening Database Diagrams |
| 查看现有的数据库关系图 | 双击现有的数据库关系图,在设计器中打开关系图。 | Opening Database Diagrams |
表
| 目的 | 操作 | 更多信息 |
|---|---|---|
| 创建新表 | 右击 Tables(表)节点,然后在快捷菜单上单击 New Table(新建表)。 | Adding Tables |
| 编辑现有表 | 右击要编辑的表,然后在快捷菜单上单击 Design Table(设计表)。 | Working with Tables |
| 显示表中的数据 | 右击要查看的表,然后在快捷菜单上单击 Retrieve Data from Table(从表中检索数据);或者双击表以返回其数据。 | Manipulating Data |
视图
| 目的 | 操作 | 更多信息 |
|---|---|---|
| 创建新视图 | 右击 Views(视图)节点,然后在快捷菜单上单击 New View(新建视图)。 | Creating Views |
| 编辑现有视图 | 右击要编辑的视图,然后在快捷菜单上单击 Design View(设计视图)。 | Working With Views |
| 显示视图返回的数据 | 右击要查看的表,然后在快捷菜单上单击 Retrieve Data from View(从视图中检索数据);或者双击视图以返回其数据。 | Manipulating Data |
触发器
| 目的 | 操作 | 更多信息 |
|---|---|---|
| 创建触发器 | 右击要为其创建触发器的表或视图,然后在快捷菜单上单击 New Trigger(新建触发器)。 | Creating a Trigger |
| 编辑触发器 | 右击要编辑的触发器,然后在快捷菜单上单击 Edit Trigger(编辑触发器)。 | Opening a Trigger |
存储过程
| 目的 | 操作 | 更多信息 |
|---|---|---|
| 创建新的存储过程 | 右击 Stored Procedures(存储过程)节点,然后在快捷菜单上单击 New Stored Procedure(新建存储过程)。 | Creating Stored Procedures and User-Defined Functions |
| 编辑现有的存储过程 | 右击要编辑的存储过程,然后在快捷菜单上单击 Edit Stored Procedure(编辑存储过程);或者双击要编辑的存储过程。 | Opening Stored Procedures and User-Defined Functions |
| 运行存储过程 | 右击要运行的存储过程,然后在快捷菜单上单击 Run Stored Procedure(运行存储过程)。 | Running Stored Procedures and User-Defined Functions |
| 单步调试存储过程 | 右击要单步执行的存储过程,然后在快捷菜单上单击 Step Into Stored Procedure(单步执行存储过程)。 | Opening Stored Procedures and User-Defined Functions |
函数
| 目的 | 操作 | 更多信息 |
|---|---|---|
| 创建新函数 | 右击 Functions(函数)节点,然后根据要创建的函数类型,在快捷菜单上单击 New Inline Function(新建内联函数)、New Table-valued Function(新建表值函数)或 New Scalar-valued Function(新建标量值函数)。 | Creating Stored Procedures and User-Defined Functions |
| 编辑现有函数 | 右击要编辑的函数,然后根据所使用的函数类型,在快捷菜单上单击 Edit Inline Function(编辑内联函数)、Edit Table-valued Function(编辑表值函数)或 Edit Scalar-valued Function(编辑标量值函数);或者双击要编辑的函数。 | Opening Stored Procedures and User-Defined Functions |
| 运行现有函数 | 右击要运行的函数,然后根据所使用的函数类型,在快捷菜单上单击 Run Inline Function(运行内联函数)、Run Table-valued Function(运行表值函数)或 Run Scalar-valued Function(运行标量值函数)。 | Running Stored Procedures and User-Defined Functions |
| 调试函数 | 右击要单步执行的函数,然后根据所使用的函数类型,单击 Step Into Inline Function(单步执行内联函数)、Step Into Table-valued Function(单步执行表值函数)或者 Step Into Scalar-valued Function(单步执行标量值函数)。 | Opening Stored Procedures and User-Defined Functions |
向应用程序添加 ADO.NET 数据访问的工具
应用程序设计的一个重要部分就是向窗体、Web 页、XML Web services、组件以及其他应用程序元素添加数据访问。在多数情况下,这一过程首先需要向应用程序添加对象,然后在应用程序运行时实例化和执行这些对象。
添加数据连接
要连接到数据源,应用程序需要使用 ADO.NET 数据连接对象。连接对象包括一个在运行时使用的连接字符串,用于在连接对象被实例化时,与数据库建立连接。
了解设计时连接(用于查看和管理数据库元素)和运行时连接(用于读取和写入数据)之间的区别是十分重要的。设计时连接是 Visual Studio 集成开发环境 (IDE) 与数据库之间的实时连接。而添加到窗体、Web 页和组件的连接对象并不是实时的连接。它们只是对象,这些对象的属性包含一个在应用程序运行时被激活的连接字符串。
要创建连接,可以将连接从 Data Tab of the Toolbox 中显式拖放到窗体上,将数据库元素从 Server Explorer 中显式拖放到窗体上,或者设置其他数据对象的特定连接相关属性。
配置连接
要配置连接,可以使用 Data Link Properties Dialog Box,该对话框允许您指定作为连接对象的连接字符串保存的信息。要显示 Data Link Properties(数据链接属性)对话框,请执行以下操作之一:
- 将连接对象或数据适配器从 Data Toolbox 中拖放到窗体上。
- 从 Server Explorer(服务器资源管理器)中将大部分数据库元素拖放到窗体上。请参阅下面的“使用 Server Explorer(服务器资源管理器)创建连接”。
- 设置特定数据对象的连接或连接字符串属性。请参阅下面的“通过设置属性创建连接”。
- 从 Data Adapter Configuration Wizard 中选择 New Connection(新建连接)。
使用 Server Explorer(服务器资源管理器)创建连接
应用程序的每个数据连接只需要一个连接对象。仅在应用程序中没有连接到同一数据库的其他连接时,才会创建连接对象。例如,将表拖放到窗体上时,将创建一个连接以及一个数据适配器。现在将第二个表拖放到窗体上(从同一个数据库中),则只会创建一个数据适配器。如果检查数据适配器的属性,会看到每个命令的 Connection 属性都设置为现有的连接对象。
下表显示了创建连接对象时需要从 Server Explorer(服务器资源管理器)中拖放的对象。
| 将以下对象拖放到窗体上 | 输出 |
|---|---|
| 数据库 | 连接对象。 |
| 整个表节点 | 每个表的连接对象和数据适配器。 |
| 单个表 | 配置为读取和更新所选的数据库表的连接对象和数据适配器。 |
| 一个或多个表或列 | 从中选择了列的每个表的连接对象和数据适配器。 |
| 整个视图节点 | 每个视图的连接对象和数据适配器。 |
| 单个视图 | 所选视图的连接对象和数据适配器。 |
| 整个存储过程节点 | 连接对象和数据命令对象(其中包含一个对存储过程的引用)。 |
| 单个存储过程 | 连接对象和数据命令对象(其中包含一个对存储过程的引用)。 |
从 Toolbox(工具箱)的 Data(数据)选项卡创建连接
从 Toolbox(工具箱)的 Data(数据)选项卡拖放到组件的任何元素都需要一个相关的连接。
下表详细说明了可以拖放哪些对象、所产生的结果以及如何配置对象所需的连接。
| 将以下对象拖放到窗体上 | 输出 |
|---|---|
| OleDbConnection 或 SqlConnection | 一个未配置的连接对象被添加到组件。要配置该连接,请设置其 ConnectionString 属性。选择 None(无)将打开 Data Link Properties(数据链接属性)对话框。 |
| OleDbDataAdapter 或 SqlDataAdapter | 将启动 Data Adapter Configuration Wizard(数据适配器配置向导),从中可以选择或创建一个连接。在向导中选择 New Connection(新建连接)将打开 Data Link Properties(数据链接属性)对话框,并创建一个新的 OleDbConnection 对象。 |
通过设置属性创建连接
可以通过设置特定对象的属性来编辑或创建连接对象。这些对象可以是其他对象的成员。例如,命令对象是数据适配器对象的成员,因此浏览到数据适配器的命令属性可以看到该命令的连接属性。
下表显示了一些对象,将其属性设置为 New 时,将打开 Data Link Properties(数据链接属性)对话框。
| 对象 | 创建或修改连接的属性 |
|---|---|
| OleDbConnection | OleDbConnection.ConnectionString |
| SqlConnection | SqlConnection.ConnectionString |
| OleDbCommand | OleDbCommand.Connection |
| SqlCommand | SqlCommand.Connection |
使用 Data Adapter Configuration Wizard(数据适配器配置向导)创建连接
Data Adapter Configuration Wizard(数据适配器配置向导)可用于帮助设置新的或现有数据适配器的属性。
运行 Data Adapter Configuration Wizard(数据适配器配置向导),然后选择 Choose Your Data Connection(选择您的数据连接)页面上的 New Connection(新建连接),将打开 Data Link Properties(数据链接属性)对话框并创建一个新的连接对象。有关运行 Data Adapter Configuration Wizard(数据适配器配置向导)的详细信息,请参阅本文后面的“添加或编辑数据适配器”。
编辑现有的连接对象
选择要编辑的连接对象。(当窗体位于设计视图中时,连接对象位于组件栏中。)在属性窗口中,选择 ConnectionString 属性,并从下拉列表中选择一个连接。如果不存在所需的连接,请选择 New Connection(新建连接)以显示 Data Link Properties(数据链接属性)对话框并创建一个新连接。
提示:其他数据对象可能具有指向一个现有数据连接的属性。如果现有数据连接对象被删除,则依赖它的数据对象可能不能继续工作,直至这些对象的相应属性被重置为指向新的连接对象。如果在创建连接对象后,需要更改数据连接,则应编辑现有连接(而不要删除连接,然后再创建新连接)。
添加或编辑数据适配器
数据适配器是处理数据库和数据集之间的通信的 ADO.NET 对象。适配器包含四个数据命令对象:选择、更新、插入和删除命令对象。每个对象都包含一个相应的 SQL 语句或一个对存储过程的引用。
注意:通过右击现有适配器,然后在快捷菜单上单击 Preview Data(预览数据),可以预览将由一个数据适配器的 Select 语句返回的数据。
在 Visual Studio .NET 中,可以使用 Data Adapter Configuration Wizard 创建数据适配器。当执行以下任何操作时,将启动向导:
- 从 Toolbox(工具箱)的 Data(数据)选项卡中,将一个数据适配器对象拖放到窗体上。
- 右击现有的数据适配器对象,然后在快捷菜单上单击 Configure Data Adapter(配置数据适配器)。
- 选择一个现有的数据适配器对象,然后单击属性窗口中的 Configure Data Adapter(配置数据适配器)。
- 选择一个现有的数据适配器对象,然后单击 Data(数据)菜单上的 Configure Data Adapter(配置数据适配器)。
从 Toolbox(工具箱)的 Data(数据)选项卡创建新的数据适配器
下表显示了创建数据适配器时需要从 Toolbox(工具箱)的 Data(数据)选项卡中拖放的对象。
| 将以下对象拖放到窗体上 | 输出 |
|---|---|
| OleDbDataAdapter | 将启动 Data Adapter Configuration Wizard(数据适配器配置向导)。完成后,一个 OleDbDataAdapter 对象和一个 OleDbConnection 对象将显示在根据向导中的选择所配置的组件栏中。 |
| SqlDataAdapter | 将启动 Data Adapter Configuration Wizard(数据适配器配置向导)。完成后,一个 SqlDataAdapter 对象和一个 SqlConnection 对象将显示在根据向导中的选择所配置的组件栏中。 |
从 Server Explorer(服务器资源管理器)中创建新的数据适配器
下表显示了创建数据适配器时需要从 Server Explorer(服务器资源管理器)中拖放的对象。
| 将以下对象拖放到窗体上 | 输出 |
|---|---|
| 整个表节点 | 每个表的连接对象和数据适配器。 |
| 单个表 | 所选表的连接对象和数据适配器。 |
| 列 – 来自一个或多个表的任何数量的列或组合 | 从中选择了列的每个表的连接对象和数据适配器。 |
| 整个视图节点 | 每个视图的连接对象和数据适配器。 |
| 单个视图 | 所选视图的连接对象和数据适配器。 |
添加或修改数据集
数据集相当于应用程序数据的脱机缓存。其中包含一个或多个数据表,可以像直接使用数据库中的表那样使用这些表。
数据集包括两种类型:
- 类型化数据集,其结构在 XML 架构中进行定义,该架构定义了数据集的表名称、列定义、约束以及关系。使用类型化数据集时,实际上是在使用一个类,其中包含了在架构中定义的所有元素的成员。
- 非类型化数据集,这种数据集不是由架构定义的,而是需要自己向其中添加表、列和其他元素,或者通过在设计时设置属性,或者在运行时添加这些元素。
要使用数据集,需要向组件中添加数据集的一个实例。然后还需提供一种方法来填充数据集(通常为一个数据适配器)。
数据集本身并不知道为其提供填充数据的数据源,了解这一点很重要。如果要从数据适配器填充数据集,必须确保数据适配器中的 SQL 命令或存储过程与数据集的结构同步。保持这种同步最简单的方法就是使用数据适配器,并在完成修改后通过数据适配器重新生成数据集。
类型化数据集 生成类型化数据集
要生成类型化数据集,首先需要为其创建一个架构,然后创建一个从 System.Data.DataSet 中衍生的类文件,并在其中包含数据集元素的成员。可以通过两种方法生成类型化数据集:
- 使用 XML Designer(XML 设计器)创建一个架构。该设计器可以自动生成适当的类文件。
- 向应用程序组件中添加一个数据适配器,然后使用该适配器,令 Visual Studio 推断出架构并生成类型化数据集类。
以下工具可用于生成和创建类型化数据集。
| 工具 | 说明 |
|---|---|
| Generate Dataset Dialog Box(用于类型化数据集) | 从一个或多个数据适配器推断出数据集架构并生成一个类型化数据集类。 |
| XML Designer(用于类型化数据集) | 可视化地创建和编辑类型化数据集。 |
向组件添加类型化数据集
可以通过三种方法向应用程序中添加类型化数据集:
- 通过从 Toolbox(工具箱)的 Data(数据)选项卡中拖放 Dataset(数据集)对象。
- 基于现有的数据适配器生成数据集。
- 从头开始使用 XML Designer(XML 设计器)。
以下工具可用于向组件中添加类型化数据集。
| 工具 | 说明 |
|---|---|
| Generate Dataset Dialog Box(用于类型化数据集) | 向 Solution Explorer(解决方案资源管理器)中添加一个 .xsd 文件(带有一个隐藏的 .vb 或 .cs 文件,定义了数据集类)。如果选择了 Add this dataset to the designer(将此数据集添加到设计器中)选项,还将向应用程序中添加一个数据集的实例。 |
| Add Dataset Dialog Box(用于类型化和非类型化数据集) | 添加存在于项目中的类型化数据集类的实例。 |
预览类型化数据集的内容
可以使用 Data Adapter Preview(数据适配器预览)对话框预览类型化数据集的内容。从 Data(数据)菜单中,选择 Preview Data(预览数据)。
查看数据集属性
右击类型化数据集,然后在快捷菜单上单击 Dataset Properties(数据集属性)以打开类型化数据集结构的只读视图。
非类型化数据集
通过 Toolbox(工具箱)的 Data(数据)选项卡可以向应用程序中添加非类型化数据集。
从 Toolbox(工具箱)的 Data(数据)选项卡创建新的数据集
从 Toolbox(工具箱)的 Data(数据)选项卡可以创建类型化或非类型化数据集,这取决于 Add Dataset(添加数据集)对话框中所选择的选项。
从 Toolbox(工具箱)的 Data(数据)选项卡中将一个 DataSet(数据集)对象拖放到 Add Dataset(添加数据集)对话框中。
| 目的 | 操作 |
|---|---|
| 创建非类型化数据集 | 从 Toolbox(工具箱)的 Data(数据)选项卡中将一个 DataSet(数据集)对象拖放到窗体上,然后在 Add Dataset(添加数据集)对话框中单击 Untyped dataset(非类型化数据集)。 |
| 创建类型化数据集 | 从 Toolbox(工具箱)的 Data(数据)选项卡中将一个 DataSet(数据集)对象拖放到窗体上,然后在 Add Dataset(添加数据集)对话框中单击 Typed dataset(类型化数据集)。选择项目中现有数据集的名称,或者某个引用数据集的名称。 |
以下设计时工具专门用于处理非类型化数据集。
| 目的 | 工具 |
|---|---|
| 处理非类型化数据集中的表 | Tables Collection Editor |
| 处理非类型化数据集中的列 | Columns Collection Editor |
| 处理非类型化数据集中的约束 | Constraints Collection Editor |
| 处理非类型化数据集中的关系 | Relations Collection Editor 和 Relation Dialog Box |
添加或编辑命令对象
命令对象允许您直接从应用程序中执行数据库语句或存储过程。
注意:数据适配器包含了数据命令,但通常并不单独使用这些命令。数据适配器中的数据命令不会像单个对象一样出现在组件栏中。如果需要管理数据适配器的命令对象,可以通过处理适配器的各个命令属性来完成。
从 Toolbox(工具箱)的 Data(数据)选项卡创建新的数据命令
下表显示了创建数据命令时需要从 Toolbox(工具箱)的 Data(数据)选项卡中拖放的对象。
| 将以下对象拖放到窗体上 | 输出 |
|---|---|
| OleDbCommand | 一个未配置的 OleDbCommand 对象出现在组件栏中。 |
| SqlCommand | 一个未配置的 SqlCommand 对象出现在组件栏中。 |
要配置数据命令,请设置 CommandText 属性,该属性将启动 Query Builder(查询生成器)。
从 Sever Explorer(服务器资源管理器)中创建新的数据命令
下表显示了创建数据适配器时需要从 Server Explorer(服务器资源管理器)中拖放的对象。
| 将以下对象拖放到窗体上 | 输出 |
|---|---|
| 整个存储过程节点 | 为每个存储过程创建一个单独的命令对象。 |
| 单个存储过程 | 为存储过程创建一个命令对象。 |
使用现有的数据命令
在设计时使用 Query Builder(查询生成器)编辑现有命令对象。要启动 Query Builder(查询生成器),请单击任何命令对象的 CommandText 属性旁边的省略号。
注意:如果要编辑的命令不在组件栏中,可以展开相应数据适配器中的特定命令(SelectCommand、InsertCommand 等等)来访问该命令。例如,如果将表拖放到窗体上来创建一个数据适配器,则各个命令将作为数据适配器的属性,从中可以访问全部命令。
数据绑定
本文未对数据绑定进行深入讨论。
注意:通过 Advanced Data Binding Dialog Box 可以将显示在控件的属性窗口中的任何属性绑定到值(从有效的数据提供程序到 Windows 窗体)。
Data Form Wizard(数据窗体向导)
Data Form Wizard(数据窗体向导)可指导您完成整个数据绑定 Windows 窗体或 Web 窗体的创建过程。
注意:Data Form Wizard(数据窗体向导)创建的窗体同其他添加到项目的任何窗体一样,这表明它不会自动成为项目的启动窗体。
总结
Visual Studio .NET 为处理数据提供了很多设计工具。本文为用户掌握这些工具提供了参考信息,同时提供了 Visual Studio .NET 文档的链接,以帮助用户获得有关详细信息。
ASP.NET中常用的优化性能方法
五 12th
数据库的连接和关闭
访问数据库资源需要创建连接、打开连接和关闭连接几个操作。这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器资源。ASP.NET中提供了连接池(Connection Pool)改善打开和关闭数据库对性能的影响。系统将用户的数据库连接放在连接池中,需要时取出,关闭时收回连接,等待下一次的连接请求。
连接池的大小是有限的,如果在连接池达到最大限度后仍要求创建连接,必然大大影响性能。因此,在建立数据库连接后只有在真正需要操作时才打开连接,使用完毕后马上关闭,从而尽量减少数据库连接打开的时间,避免出现超出连接限制的情况。
使用存储过程
存储过程是存储在服务器上的一组预编译的SQL语句,类似于DOS系统中的批处理文件。存储过程具有对数据库立即访问的功能,信息处理极为迅速。使用存储过程可以避免对命令的多次编译,在执行一次后其执行规划就驻留在高速缓存中,以后需要时只需直接调用缓存中的二进制代码即可。
另外,存储过程在服务器端运行,独立于ASP.NET程序,便于修改,最重要的是它可以减少数据库操作语句在网络中的传输。
优化查询语句
ASP.NET中ADO连接消耗的资源相当大,SQL语句运行的时间越长,占用系统资源的时间也越长。因此,尽量使用优化过的SQL语句以减少执行时间。比如,不在查询语句中包含子查询语句,充分利用索引等。
2. 字符串操作性能优化
使用值类型的ToString方法
在连接字符串时,经常使用"+"号直接将数字添加到字符串中。这种方法虽然简单,也可以得到正确结果,但是由于涉及到不同的数据类型,数字需要通过装箱操作转化为引用类型才可以添加到字符串中。但是装箱操作对性能影响较大,因为在进行这类处理时,将在托管堆中分配一个新的对象,原有的值复制到新创建的对象中。
使用值类型的ToString方法可以避免装箱操作,从而提高应用程序性能。
运用StringBuilder类
String类对象是不可改变的,对于String对象的重新赋值在本质上是重新创建了一个String对象并将新值赋予该对象,其方法ToString对性能的提高并非很显著。
在处理字符串时,最好使用StringBuilder类,其.NET 命名空间是System.Text。该类并非创建新的对象,而是通过Append,Remove,Insert等方法直接对字符串进行操作,通过ToString方法返回操作结果。
其定义及操作语句如下所示:
int num;
System.Text.StringBuilder str = new System.Text.StringBuilder(); //创建字符串
str.Append(num.ToString()); //添加数值num
Response.Write(str.ToString); //显示操作结果
3. 优化 Web 服务器计算机和特定应用程序的配置文件以符合您的特定需要
默认情况下,ASP.NET 配置被设置成启用最广泛的功能并尽量适应最常见的方案。因此,应用程序开发人员可以根据应用程序所使用的功能,优化和更改其中的某些配置,以提高应用程序的性能。下面的列表是您应该考虑的一些选项。
仅对需要的应用程序启用身份验证。默认情况下,身份验证模式为 Windows,或集成 NTLM。大多数情况下,对于需要身份验证的应用程序,最好在 Machine.config 文件中禁用身份验证,并在 Web.config 文件中启用身份验证。
根据适当的请求和响应编码设置来配置应用程序。ASP.NET 默认编码格式为 UTF-8。如果您的应用程序为严格的 ASCII,请配置应用程序使用 ASCII 以获得稍许的性能提高。
考虑对应用程序禁用 AutoEventWireup。在 Machine.config 文件中将 AutoEventWireup 属性设置为 false,意味着页面不将方法名与事件进行匹配和将两者挂钩(例如 Page_Load)。如果页面开发人员要使用这些事件,需要在基类中重写这些方法(例如,需要为页面加载事件重写 Page.OnLoad,而不是使用 Page_Load 方法)。如果禁用 AutoEventWireup,页面将通过将事件连接留给页面作者而不是自动执行它,获得稍许的性能提升。
从请求处理管线中移除不用的模块。默认情况下,服务器计算机的 Machine.config 文件中 <httpModules> 节点的所有功能均保留为激活。根据应用程序所使用的功能,您可以从请求管线中移除不用的模块以获得稍许的性能提升。检查每个模块及其功能,并按您的需要自定义它。
例如,如果您在应用程序中不使用会话状态和输出缓存,则可以从 <httpModules>列表中移除它们,以便请求在不执行其他有意义的处理时,不必执行每个模块的进入和离开代码。
4. 一定要禁用调试模式
在部署生产应用程序或进行任何性能测量之前,始终记住禁用调试模式。如果启用了调试模式,应用程序的性能可能受到非常大的影响。
5. 对于广泛依赖外部资源的应用程序,请考虑在多处理器计算机上启用网络园艺
ASP.NET 进程模型帮助启用多处理器计算机上的可缩放性,将工作分发给多个进程(每个 CPU 一个),并且每个进程都将处理器关系设置为其 CPU。此技术称为网络园艺。如果应用程序使用较慢的数据库服务器或调用具有外部依赖项的 COM 对象(这里只是提及两种可能性),则为您的应用程序启用网络园艺是有益的。但是,在决定启用网络园艺之前,您应该测试应用程序在网络园中的执行情况。
6. 只要可能,就缓存数据和页输出
ASP.NET 提供了一些简单的机制,它们会在不需要为每个页请求动态计算页输出或数据时缓存这些页输出或数据。另外,通过设计要进行缓存的页和数据请求(特别是在站点中预期将有较大通讯量的区域),可以优化这些页的性能。与 .NET Framework 的任何 Web 窗体功能相比,适当地使用缓存可以更好的提高站点的性能,有时这种提高是超数量级的。
使用 ASP.NET 缓存机制有两点需要注意。首先,不要缓存太多项。缓存每个项均有开销,特别是在内存使用方面。不要缓存容易重新计算和很少使用的项。其次,给缓存的项分配的有效期不要太短。很快到期的项会导致缓存中不必要的周转,并且经常导致更多的代码清除和垃圾回收工作。若关心此问题,请监视与 ASP.NET Applications 性能对象关联的 Cache Total Turnover Rate 性能计数器。高周转率可能说明存在问题,特别是当项在到期前被移除时。这也称作内存压力。
7. 选择适合页面或应用程序的数据查看机制
根据您选择在 Web 窗体页显示数据的方式,在便利和性能之间常常存在着重要的权衡。例如,DataGrid Web 服务器控件可能是一种显示数据的方便快捷的方法,但就性能而言它的开销常常是最大的。在某些简单的情况下,您通过生成适当的 HTML 自己呈现数据可能很有效,但是自定义和浏览器定向会很快抵销所获得的额外功效。Repeater Web 服务器控件是便利和性能的折衷。它高效、可自定义且可编程。
8. 将 SqlDataReader 类用于快速只进数据游标
SqlDataReader 类提供了一种读取从 SQL Server 数据库检索的只进数据流的方法。如果当创建 ASP.NET 应用程序时出现允许您使用它的情况,则 SqlDataReader 类提供比 DataSet 类更高的性能。情况之所以这样,是因为 SqlDataReader 使用 SQL Server 的本机网络数据传输格式从数据库连接直接读取数据。另外,SqlDataReader 类实现 IEnumerable 接口,该接口也允许您将数据绑定到服务器控件。有关更多信息,请参见 SqlDataReader 类。有关 ASP.NET 如何访问数据的信息,请参见通过 ASP.NET 访问数据。
9. 将 SQL Server 存储过程用于数据访问
在 .NET Framework 提供的所有数据访问方法中,基于 SQL Server 的数据访问是生成高性能、可缩放 Web 应用程序的推荐选择。使用托管 SQL Server 提供程序时,可通过使用编译的存储过程而不是特殊查询获得额外的性能提高。
10. 避免单线程单元 (STA) COM 组件
默认情况下,ASP.NET 不允许任何 STA COM 组件在页面内运行。若要运行它们,必须在 .aspx 文件内将 ASPCompat=true 属性包含在 @ Page 指令中。这样就将执行用的线程池切换到 STA 线程池,而且使 HttpContext 和其他内置对象可用于 COM 对象。前者也是一种性能优化,因为它避免了将多线程单元 (MTA) 封送到 STA 线程的任何调用。
使用 STA COM 组件可能大大损害性能,应尽量避免。若必须使用 STA COM 组件,如在任何 interop 方案中,则应在执行期间进行大量调用并在每次调用期间发送尽可能多的信息。另外,小心不要在构造页面期间创建任何 STA COM 组件。例如下面的代码中,在页面构造时将实例化由某个线程创建的 MySTAComponent,而该线程并不是将运行页面的 STA 线程。这可能对性能有不利影响,因为要构造页面就必须完成 MTA 和 STA 线程之间的封送处理。
<%@ Page Language="VB" ASPCompat="true" %>
<script runat=server>
Dim myComp as new MySTAComponent()
Public Sub Page_Load()
myComp.Name = "Bob"
End Sub
</script>
<html>
<%
Response.Write(myComp.SayHello)
%>
</html>
首选机制是推迟对象的创建,直到以后在 STA 线程下执行上述代码,如下面的例子所示。
<%@ Page Language="VB" ASPCompat="true" %>
<script runat=server>
Dim myComp
Public Sub Page_Load()
myComp = new MySTAComponent()
myComp.Name = "Bob"
End Sub
</script>
<html>
<%
Response.Write(myComp.SayHello)
%>
</html>
推荐的做法是在需要时或者在 Page_Load 方法中构造任何 COM 组件和外部资源。
永远不要将任何 STA COM 组件存储在可以由构造它的线程以外的其他线程访问的共享资源里。这类资源包括像缓存和会话状态这样的资源。即使 STA 线程调用 STA COM 组件,也只有构造此 STA COM 组件的线程能够实际为该调用服务,而这要求封送处理对创建者线程的调用。此封送处理可能产生重大的性能损失和可伸缩性问题。在这种情况下,请研究一下使 COM 组件成为 MTA COM 组件的可能性,或者更好的办法是迁移代码以使对象成为托管对象。
11. 将调用密集型的 COM 组件迁移到托管代码
.NET Framework 提供了一个简单的方法与传统的 COM 组件进行交互。其优点是可以在保留现有投资的同时利用新的平台。但是在某些情况下,保留旧组件的性能开销使得将组件迁移到托管代码是值得的。每一情况都是不一样的,决定是否需要迁移组件的最好方法是对 Web 站点运行性能测量。建议您研究一下如何将需要大量调用以进行交互的任何 COM 组件迁移到托管代码。
许多情况下不可能将旧式组件迁移到托管代码,特别是在最初迁移 Web 应用程序时。在这种情况下,最大的性能障碍之一是将数据从非托管环境封送到托管环境。因此,在交互操作中,请在任何一端执行尽可能多的任务,然后进行一个大调用而不是一系列小调用。例如,公共语言运行库中的所有字符串都是 Unicode 的,所以应在调用托管代码之前将组件中的所有字符串转换成 Unicode 格式。
另外,一处理完任何 COM 对象或本机资源就释放它们。这样,其他请求就能够使用它们,并且最大限度地减少了因稍后请求垃圾回收器释放它们所引起的性能问题。
12. 在 Visual Basic .NET 或 JScript 代码中使用早期绑定
以往,开发人员喜欢使用 Visual Basic、VBScript 和 JScript 的原因之一就是它们所谓“无类型”的性质。变量不需要显式类型声明,并能够简单地通过使用来创建它们。当从一个类型到另一个类型进行分配时,转换将自动执行。不过,这种便利会大大损害应用程序的性能。
Visual Basic 现在通过使用 Option Strict 编译器指令来支持类型安全编程。为了向后兼容,默认情况下,ASP.NET 不启用该选项。但是,为了得到最佳性能,强烈建议在页中启用该选项。若要启用 Option Strict,请将 Strict 属性包括在 @ Page 指令中,或者,对于用户控件,请将该属性包括在 @ Control 指令中。下面的示例演示了如何设置该属性,并进行了四个变量调用以显示使用该属性是如何导致编译器错误的。
<%@ Page Language="VB" Strict="true" %>
<%
Dim B
Dim C As String
‘ This will cause a compiler error.
A = "Hello"
‘ This will cause a compiler error.
B = "World"
‘ This will not cause a compiler error.
C = "!!!!!!"
‘ But this will cause a compiler error.
C = 0
%>
JScript .NET 也支持无类型编程,但它不提供强制早期绑定的编译器指令。若发生下面任何一种情况,则变量是晚期绑定的:
被显式声明为 Object。
是无类型声明的类的字段。
是无显式类型声明的专用函数或方法成员,并且无法从其使用推断出类型。
最后一个差别比较复杂,因为如果 JScript .NET 编译器可以根据变量的使用情况推断出类型,它就会进行优化。在下面的示例中,变量 A 是早期绑定的,但变量 B 是晚期绑定的。
var A;
var B;
A = "Hello";
B = "World";
B = 0;
为了获得最佳的性能,当声明 JScript .NET 变量时,请为其分配一个类型。例如,var A : String。
13. 使请求管线内的所有模块尽可能高效
请求管线内的所有模块在每次请求中都有机会被运行。因此,当请求进入和离开模块时快速地触发代码至关重要,特别是在不使用模块功能的代码路径里。分别在使用及不使用模块和配置文件时执行吞吐量测试,对确定这些方法的执行速度非常有用。
14. 使用 HttpServerUtility.Transfer 方法在同一应用程序的页面间重定向
采用 Server.Transfer 语法,在页面中使用该方法可避免不必要的客户端重定向。
15. 必要时调整应用程序每个辅助进程的线程数
ASP.NET 的请求结构试图在执行请求的线程数和可用资源之间达到一种平衡。已知一个使用足够 CPU 功率的应用程序,该结构将根据可用于请求的 CPU 功率,来决定允许同时执行的请求数。这项技术称作线程门控。但是在某些条件下,线程门控算法不是很有效。通过使用与 ASP.NET Applications 性能对象关联的 Pipeline Instance Count 性能计数器,可以在 PerfMon 中监视线程门控。
当页面调用外部资源,如数据库访问或 XML Web services 请求时,页面请求通常停止并释放 CPU。如果某个请求正在等待被处理,并且线程池中有一个线程是自由的,那么这个正在等待的请求将开始被处理。遗憾的是,有时这可能导致 Web 服务器上存在大量同时处理的请求和许多正在等待的线程,而它们对服务器性能有不利影响。通常,如果门控因子是外部资源的响应时间,则让过多请求等待资源,对 Web 服务器的吞吐量并无帮助。
为缓和这种情况,可以通过更改 Machine.config 配置文件
注意 辅助线程是用来处理 ASP.NET 请求的,而 IO 线程则是用于为来自文件、数据库或 XML Web services 的数据提供服务的。
分配给这些属性的值是进程中每个 CPU 每类线程的最大数目。对于双处理器计算机,最大数是设置值的两倍。对于四处理器计算机,最大值是设置值的四倍。无论如何,对于有四个或八个 CPU 的计算机,最好更改默认值。对于有一个或两个处理器的计算机,默认值就可以,但对于有更多处理器的计算机的性能,进程中有一百或两百个线程则弊大于利。
注意 进程中有太多线程往往会降低服务器的速度,因为额外的上下文交换导致操作系统将 CPU 周期花在维护线程而不是处理请求上。
16. 适当地使用公共语言运行库的垃圾回收器和自动内存管理
小心不要给每个请求分配过多内存,因为这样垃圾回收器将必须更频繁地进行更多的工作。另外,不要让不必要的指针指向对象,因为它们将使对象保持活动状态,并且应尽量避免含 Finalize 方法的对象,因为它们在后面会导致更多的工作。特别是在 Finalize 调用中永远不要释放资源,因为资源在被垃圾回收器回收之前可能一直消耗着内存。最后这个问题经常会对 Web 服务器环境的性能造成毁灭性的打击,因为在等待 Finalize 运行时,很容易耗尽某个特定的资源。
17. 如果有大型 Web 应用程序,可考虑执行预批编译
每当发生对目录的第一次请求时都会执行批编译。如果目录中的页面没有被分析并编译,此功能会成批分析并编译目录中的所有页面,以便更好地利用磁盘和内存。如果这需要很长时间,则将快速分析并编译单个页面,以便请求能被处理。此功能带给 ASP.NET 性能上的好处,因为它将许多页面编译为单个程序集。从已加载的程序集访问一页比每页加载新的程序集要快。
批编译的缺点在于:如果服务器接收到许多对尚未编译的页面的请求,那么当 Web 服务器分析并编译它们时,性能可能较差。为解决这个问题,可以执行预批编译。为此,只需在应用程序激活之前向它请求一个页面,无论哪页均可。然后,当用户首次访问您的站点时,页面及其程序集将已被编译。
没有简单的机制可以知道批编译何时发生。需一直等到 CPU 空闲或者没有更多的编译器进程(例如 csc.exe(C# 编译器)或 vbc.exe(Visual Basic 编译器))启动。
还应尽量避免更改应用程序的 \bin 目录中的程序集。更改页面会导致重新分析和编译该页,而替换 \bin 目录中的程序集则会导致完全重新批编译该目录。
在包含许多页面的大规模站点上,更好的办法可能是根据计划替换页面或程序集的频繁程度来设计不同的目录结构。不常更改的页面可以存储在同一目录中并在特定的时间进行预批编译。经常更改的页面应在它们自己的目录中(每个目录最多几百页)以便快速编译。
Web 应用程序可以包含许多子目录。批编译发生在目录级,而不是应用程序级。
18. 不要依赖代码中的异常
因为异常大大地降低性能,所以您不应该将它们用作控制正常程序流程的方式。如果有可能检测到代码中可能导致异常的状态,请执行这种操作。不要在处理该状态之前捕获异常本身。常见的方案包括:检查 null,分配给将分析为数字值的 String 一个值,或在应用数学运算前检查特定值。下面的示例演示可能导致异常的代码以及测试是否存在某种状态的代码。两者产生相同的结果。
try
{
result = 100 / num;
}
catch (Exception e)
{
result = 0;
}
// …to this.
if (num != 0)
result = 100 / num;
else
result = 0;
19. 使用 HttpResponse.Write 方法进行字符串串联
该方法提供非常有效的缓冲和连接服务。但是,如果您正在执行广泛的连接,请使用多个 Response.Write 调用。下面示例中显示的技术比用对 Response.Write 方法的单个调用连接字符串更快。
Response.Write("a");
Response.Write(myString);
Response.Write("b");
Response.Write(myObj.ToString());
Response.Write("c");
Response.Write(myString2);
Response.Write("d");
20. 除非有特殊的原因要关闭缓冲,否则使其保持打开
禁用 Web 窗体页的缓冲会导致大量的性能开销。
21. 只在必要时保存服务器控件视图状态
自动视图状态管理是服务器控件的功能,该功能使服务器控件可以在往返过程上重新填充它们的属性值(您不需要编写任何代码)。但是,因为服务器控件的视图状态在隐藏的窗体字段中往返于服务器,所以该功能确实会对性能产生影响。您应该知道在哪些情况下视图状态会有所帮助,在哪些情况下它影响页的性能。例如,如果您将服务器控件绑定到每个往返过程上的数据,则将用从数据绑定操作获得的新值替换保存的视图状态。在这种情况下,禁用视图状态可以节省处理时间。
默认情况下,为所有服务器控件启用视图状态。若要禁用视图状态,请将控件的EnableViewState 属性设置为 false,如下面的 DataGrid 服务器控件示例所示。
<asp:datagrid EnableViewState="false" datasource="…"
runat="server"/>
您还可以使用 @ Page 指令禁用整个页的视图状态。当您不从页回发到服务器时,这将十分有用:
<%@ Page EnableViewState="false" %>
注意 @ Control 指令中也支持 EnableViewState 属性,该指令允许您控制是否为用户控件启用视图状态。
若要分析页上服务器控件使用的视图状态的数量,请(通过将 trace="true" 属性包括在 @ Page 指令中)启用该页的跟踪并查看 Control Hierarchy 表的 Viewstate 列。有关跟踪和如何启用它的信息,请参见 ASP.NET 跟踪。
22. 避免到服务器的不必要的往返过程
虽然您很可能希望尽量多地使用 Web 窗体页框架的那些节省时间和代码的功能,但在某些情况下却不宜使用 ASP.NET 服务器控件和回发事件处理。
通常,只有在检索或存储数据时,您才需要启动到服务器的往返过程。多数数据操作可在这些往返过程间的客户端上进行。例如,从 HTML 窗体验证用户输入经常可在数据提交到服务器之前在客户端进行。通常,如果不需要将信息传递到服务器以将其存储在数据库中,那么您不应该编写导致往返过程的代码。
如果您开发自定义服务器控件,请考虑让它们为支持 ECMAScript 的浏览器呈现客户端代码。通过以这种方式使用服务器控件,您可以显著地减少信息被不必要的发送到 Web 服务器的次数。
使用 Page.IsPostBack 避免对往返过程执行不必要的处理
如果您编写处理服务器控件回发处理的代码,有时可能需要在首次请求页时执行其他代码,而不是当用户发送包含在该页中的 HTML 窗体时执行的代码。根据该页是否是响应服务器控件事件生成的,使用 Page.IsPostBack 属性有条件地执行代码。例如,下面的代码演示如何创建数据库连接和命令,该命令在首次请求该页时将数据绑定到 DataGrid 服务器控件。
void Page_Load(Object sender, EventArgs e)
{
// Set up a connection and command here.
if (!Page.IsPostBack)
{
String query = "select * from Authors where FirstName like ‘%JUSTIN%’";
myCommand.Fill(ds, "Authors");
myDataGrid.DataBind();
}
}
由于每次请求时都执行 Page_Load 事件,上述代码检查 IsPostBack 属性是否设置为 false。如果是,则执行代码。如果该属性设置为 true,则不执行代码。
注意 如果不运行这种检查,回发页的行为将不更改。Page_Load 事件的代码在执行服务器控件事件之前执行,但只有服务器控件事件的结果才可能在输出页上呈现。如果不运行该检查,仍将为 Page_Load 事件和该页上的任何服务器控件事件执行处理。
23. 当不使用会话状态时禁用它
并不是所有的应用程序或页都需要针对于具体用户的会话状态,您应该对任何不需要会话状态的应用程序或页禁用会话状态。
若要禁用页的会话状态,请将 @ Page 指令中的 EnableSessionState 属性设置为 false。例如:
<%@ Page EnableSessionState="false" %>
注意 如果页需要访问会话变量,但不打算创建或修改它们,则将 @ Page 指令中的 EnableSessionState 属性设置为 ReadOnly。
还可以禁用 XML Web services 方法的会话状态。有关更多信息,请参见使用 ASP.NET 和 XML Web services 客户端创建的 XML Web services。
若要禁用应用程序的会话状态,请在应用程序 Web.config 文件的 sessionstate 配置节中将 mode 属性设置为 off。例如:
<sessionstate mode="off" />
24. 仔细选择会话状态提供程序
ASP.NET 为存储应用程序的会话数据提供了三种不同的方法:进程内会话状态、作为 Windows 服务的进程外会话状态和 SQL Server 数据库中的进程外会话状态。每种方法都有自己的优点,但进程内会话状态是迄今为止速度最快的解决方案。如果只在会话状态中存储少量易失数据,则建议您使用进程内提供程序。进程外解决方案主要用于跨多个处理器或多个计算机缩放应用程序,或者用于服务器或进程重新启动时不能丢失数据的情况。有关更多信息,请参见 ASP.NET 状态管理。
25. 不使用不必要的Server Control
ASP.net中,大量的服务器端控件方便了程序开发,但也可能带来性能的损失,因为用户每操作一次服务器端控件,就产生一次与服务器端的往返过程。因此,非必要,应当少使用Server Control。
26. ASP.NET应用程序性能测试
在对ASP.NET应用程序进行性能测试之前,应确保应用程序没有错误,而且功能正确。具体的性能测试可以采用以下工具进行:
Web Application Strees Tool (WAS)是Microsoft发布的一个免费测试工具,可以从http://webtool.rte.microsoft.com/上下载。它可以模拟成百上千个用户同时对web应用程序进行访问请求,在服务器上形成流量负载,从而达到测试的目的,可以生成平均TTFB、平均TTLB等性能汇总报告。
Application Center Test (ACT) 是一个测试工具,附带于Visual Studio.NET的企业版中,是Microsoft正式支持的web应用程序测试工具。它能够直观地生成图表结果,功能比WAS多,但不具备多个客户机同时测试的能力。
服务器操作系统"管理工具"中的"性能"计数器,可以对服务器进行监测以了解应用程序性能。
结论
对于网站开发人员来说,在编写ASP.NET应用程序时注意性能问题,养成良好的习惯,提高应用程序性能,至少可以推迟必需的硬件升级,降低网站的成本。
ADO.NET连接池
五 12th
如何实现连接池
确保你每一次的连接使用相同的连接字符串(和连接池相同);只有连接字符串相同时连接池才会工作。如果连接字符串不相同,应用程序就不会使用连接池而是创建一个新的连接。
优点
使用连接池的最主要的优点是性能。创建一个新的数据库连接所耗费的时间主要取决于网络的速度以及应用程序和数据库服务器的(网络)距离,而且这个过程通常是一个很耗时的过程。而采用数据库连接池后,数据库连接请求可以直接通过连接池满足而不需要为该请求重新连接、认证到数据库服务器,这样就节省了时间。
缺点
数据库连接池中可能存在着多个没有被使用的连接一直连接着数据库(这意味着资源的浪费)。
技巧和提示
1. 当你需要数据库连接时才去创建连接池,而不是提前建立。一旦你使用完连接立即关闭它,不要等到垃圾收集器来处理它。
2. 在关闭数据库连接前确保关闭了所有用户定义的事务。
3. 不要关闭数据库中所有的连接,至少保证连接池中有一个连接可用。如果内存和其他资源是你必须首先考虑的问题,可以关闭所有的连接,然后在下一个请求到来时创建连接池。
连接池FAQ
1. 何时创建连接池?
当第一个连接请求到来时创建连接池;连接池的建立由数据库连接的连接字符创来决定。每一个连接池都与一个不同的连接字符串相关。当一个新的连接请求到来时如果连接字符串和连接池使用的字符串相同,就从连接池取出一个连接;如果不相同,就新建一个连接池。
2. 何时关闭连接池?
当连接池中的所有连接都已经关闭时关闭连接池。
3. 当连接池中的连接都已经用完,而有新的连接请求到来时会发生什么?
当连接池已经达到它的最大连接数目时,有新的连接请求到来时,新的连接请求将放置到连接队列中。当有连接释放给连接池时,连接池将新释放的连接分配给在队列中排队的连接请求。你可以调用close和dispose将连接归还给连接池。
4. 我应该如何允许连接池?
对于.NET应用程序而言,默认为允许连接池。(这意味着你可以不必为这件事情做任何的事情)当然,如果你可以在SQLConnection对象的连接字符串中加进Pooling=true;确保你的应用程序允许连接池的使用。
5. 我应该如何禁止连接池?
ADO.NET默认为允许数据库连接池,如果你希望禁止连接池,可以使用如下的方式:
1) 使用SQLConnection对象时,往连接字符串加入如下内容:Pooling=False;
2) 使用OLEDBConnection对象时,往连接字符串加入如下内容:OLE DB Services=-4;
———————————————————————————————————————————————–
连接池
连接池是与业务对象对等的中间层部分,启动一个新的业务对象时,会检查连接池现有的连接,若有就使用它,否则就创建一新连接。包含在ADO.NET中的每个.NET数据提供程序都可实现连接池。
默认连接池是打开的,当关闭连接时,并不是真正关闭实际的数据连接,若超过默认时间(60秒)未再次使用,才会真正被关闭。
若不想存储连接?将下面的字符串添加到OLE DB连接字符串中去:OLE DB Services=-4; 若使用SqlConnection对象,添加下字符:Pooling=False;
Connection类
CreateCommand方法可节省一行代码
OleDbCommand cmd=cn.CreateCommand();
与下面两句等价:
OleDbCommand cmd=new OleDbCommand();
cmd.Connection=cn;
GetOleDbSchemaTable方法获取数据库架构信息
有两个参数schema(定要返回的架构表)和 restrictions (限制值的 Object 数组)重点是Restrictions参数数组,结构是{“TABLE_CATALOG“,“TABLE_SCHEMA“,“TABLE_NAME“,“COLUMN_NAME“},具体可参考MSDN
———————————————————————————————————————————————–
.NET框架组件数据提供程序
.NET框架组件中的数据提供程序是应用程序与数据源之间的一座桥梁。它允许你从数据源返回查询的结果,在数据源上执行命令,把数据集中的改变提交到数据源。本文包含了怎样选择最适合需求的.NET框架组件数据提供程序。
使用哪种.NET框架组件数据提供程序
为了使应用程序获得最佳的性能,需要使用最适合数据源的.NET框架组件数据提供程序。
连接到SQL Server 7.0及以上版本
当连接到SQL Server 7.0及以上版本时,为了获得最佳性能应该使用SQL Server .NET 数据提供程序。SQL Server .NET数据提供程序设计为直接访问SQL Server,没有其它附加的技术层。下图(图1)说明了访问SQL Server 7.0及以上版本的多种技术之间的差别。
图1.访问SQL Server 7.0及以上版本的连接方法
连接到ODBC数据源
名字空间中的ODBC .NET数据提供程序的结构与SQL Server和OLE DB的.NET数据提供程序相同。ODBC .NET数据提供程序使用"ODBC"前缀和标准的ODBC连接字符串。
注意:ODBC .NET数据提供程序包含在.NET框架组件1.1以上版本,包含ODBC .NET数据提供程序的名字空间是System.Data.Odbc。
使用DataReader、DataSet、DataAdapter和DataView
ADO.NET提供两个对象用于检索关系型数据并把它存储在内存中,分别是DataSet和DataReader。DataSet提供内存中关系数据的表现–包括表和次序、约束等表间的关系的完整数据集合。DataReader提供快速、只向前、只读的来自数据库的数据流。
使用DataSet时,一般使用DataAdapter(也可能是CommandBuilder)与数据源交互,用DataView对DataSet中的数据进行排序和过滤。DataSet可以被继承来建立强化类型的DataSet,用于暴露表、行、列作为强化类型对象属性。
下面的内容包含什么时候使用DataSet或DataReader,以及怎样优化访问它们所包含的数据,也包括怎样优化DataAdapter和DataView的使用(也包括CommandBuilder)。
DataSet与DataReader的对比
在设计应用程序时,决定使用DataSet还是DataReader需要考虑应用程序需要的功能。
使用DataSet是为了实现应用程序的下述功能:
l 操作结果中的多个分离的表。
l 操作来自多个源(例如来自多个数据库、XML文件和电子表格的混合数据)的数据。
l 在层之间交换数据或使用XML Web服务。与DataReader 不同,DataSet能被传递到远程客户端。
l 通过缓冲重复使用相同的行集合以提高性能(例如排序、搜索或过滤数据)。
l 每行执行大量的处理。在使用DataReader返回的行上进行扩展处理将使连接存在的时间比必要的更长,从而降低效率。
l 使用XML操作(例如XSLT转换和Xpath查询)维护数据。
在应用程序需要以下功能时使用DataReader:
l 不需要缓冲数据。
l 正在处理的结果集太大而不能全部放入内存中。
l 需要迅速一次性访问数据,采用只向前的只读的方式。
注意:当填充DataSet的时候,DataAdapter使用DataReader。因此使用DataAdapter代替DataSet获得的性能是节约了DataSet消耗的内存和组装DataSet所需要的周期。这种性能的提高大部分是有名无实的,因此你应该根据需要的功能为基础来做设计决定。
使用强类型DataSet的好处
使用DataSet的另一个好处是它能被继承用于建立强类型的DataSet。强类型DataSet的好处包括设计时的检查和强类型DataSet 的Visual Studio .NET语句填充。当你为DataSet固定了大纲或关系结构时,就能建立强类型DataSet,把行和列作为对象的属性而不是项的集合。例如,作为暴露顾客表的某一行的列名的代替,你可以暴露Customer对象的 Name属性。强类型的DataSet衍生自DataSet类,因此不会牺牲DataSet的任何功能,也就是说,强类型的DataSet也可以是远程的,并作为数据绑定控件(例如DataGrid)的数据源提供。如果不知道大纲,也能通过使用通常的DataSet获得好处,但是丧失了强类型DataSet的附加特性。
在强类型DataSet中处理空值
使用强类型DataSet时,你能给DataSet 的XML大纲定义语言(XSD)作注解以确保强类型DataSet正确的处理空(Null)的引用。空值(nullValue)注释使你能用String.Empty这个特定值代替DBNull、保持了空引用、或者产生一个异常。选择其中的哪个依赖于应用程序的内容,默认情况下遇到空引用将产生一个异常。
刷新DataSet中的数据
如果你希望使用更新后的值从服务器刷新数据集中的值,使用DataAdapter.Fill。如果主键定义在数据表上,DataAdapter.Fill基于主键匹配新行,并把服务器的数据改成已存在的行。被刷新行的RowState设置为Unchanged,即使在刷新前它被修改过。注意如果给数据表定义了主键,DataAdapter.Fill添加新行可能重复主键值。
如果希望用服务器的当前值刷新一个表,并且保持表中行的改变,你必须首选使用DataAdapter.Fill组合它,填充一个新的数据表,接着将该数据表合并(Merge)进一个数据集,并把preserveChanges值设为true。
在DataSet中搜索数据
在一个数据集中查询符合特定条件的行时,使用基于索引(index-based)的查看表将提高性能。给数据表指定主键(PrimaryKey)值时,就建立了一个索引。当为数据表建立数据视图(DataView)时也建立了索引。下面是一些使用基于索引查看的技巧:
如果查询是在数据表的主键列上进行的,使用DataTable.Rows.Find代替DataTable.Select。
查询非主键列,可以使用数据视图来提高多个数据查询的速度。当给数据视图添加排序时,将建立搜索时使用的索引。数据视图暴露了查询下层数据表的Find和FindRows方法。
如果你不是查询表的排序视图,也可以通过为数据表建立数据视图获得基于索引的查看表的好处。注意如果你执行数据上的多个查询这是唯一的好处。如果你只执行单个查询,需要建立索引的过程将因为使用索引而降低了性能。
数据视图(DataView)结构
当数据视图建立后,并且当Sort、RowFilter或RowStateFilter或者属性被修改时,数据视图为下层数据表中的数据建立索引。当建立数据视图对象时,使用把Sort、RowFilter和RowStateFilter值作为参数的数据视图构造函数。结果是建立了一次索引。建立"空"数据视图,然后设置Sort、RowFilter和RowStateFilter属性将导致至少两次建立索引。
分页
ADO.NET给了你从数据源返回什么数据的明显控制,也提供了在数据集中存储了多少数据的控制。在设计应用程序时可以考虑以下技巧:
l 避免使用DataAdapter.Fill,它使用了startRecord和maxRecords值。使用这种方式填充数据集时,数据集只填充由maxRecords参数指定的记录个数(从参数startRecord指定的记录开始),而不管返回的整个查询。这导致读取过时的"不想要的"记录,同时使用了不必要的服务器资源来返回补充记录。
l 用于在某个时候只返回一页记录的技术之一是建立一个SQL语句,该语句包含一个WHERE和ORDER BY子句,并有TOP判定。这种技术依赖于识别每个唯一行的方法。当导航到下一页的记录时,修改WHERE子句使它包含所有唯一标识比当前页标识大的记录;当导航到前面一页时,修改WHERE子句使它包含所有唯一标识比当前页标识小的记录。对于两种查询都只返回记录的TOP页的记录。当导航到前面一页时需要对记录进行降序排列,这将返回查询的末尾页(如果需要可以在显示前对记录进行重新排序)。
l 另一种技术是建立一个SQL语句包含TOP判定和嵌入的SELECT语句。这种技术不是基于唯一的识别每行的方法。使用这种技术的第一步是把页面的大小与想得到的页面数量相乘。接着把该数值传递给SQL查询的TOP判定,并按升序排序。接着把这个查询嵌入另一个查询,该查询从嵌入的查询结果中选择TOP页面大小,按降序排列。本质上返回的是嵌入的查询的末尾页面。例如,为了返回页面大小是10的查询结果的第三页,使用下面的命令:
SELECT TOP 10 * FROM (SELECT TOP 30 * FROM Customers ORDER BY Id ASC) AS Table1 ORDER BY Id DESC |
l 如果数据不是经常改变,能通过本地维护数据集里面的记录缓存来提高性能。例如,你能在本地数据集中存储10页数据,只在用户导航超出第一页或最后一页时才查询数据源检索新的数据。
使用大纲(Schema)填充数据集
当用数据填充数据集时,DataAdapter.Fill方法使用数据集的已存在的大纲并把它与Select命令(SelectCommand)返回的数据进行组合。如果数据集中没有与被填充的表匹配的表的名字,Fill方法将建立一张表。默认情况下,Fill只定义列和列的类型。
你能通过设置数据适配器的MissingSchemaAction属性来重载Fill的默认的行为。例如,要使Fill建立的表包含主键信息、唯一约束、列属性、是否允许空值、列的最大长度、只读列、自动增加列等等,只需要指定DataAdapter.MissingSchemaAction为MissingSchemaAction.AddWithKey。作为选择,你能在调用DataAdapter.Fill前调用DataAdapter.FillSchema来确保数据集被填充时大纲已经准备好了。
调用FillSchema将再次访问服务器并检索附加的大纲信息。为了提高性能,最好指定数据集的大纲,或者在调用Fill前设置数据适配器的MissingSchemaAction。
使用命令构造器(CommandBuilder)的经验
命令构造器根据数据适配器的SelectCommand属性自动生成数据适配器的InsertCommand、UpdateCommand和DeleteCommand属性(假若SelectCommand执行单个表上的选择(SELECT))。
l 命令构造器的使用应该限制在设计时或者ad-hoc情况下。需要的生成数据适配器命令属性的过程妨碍了性能。如果你预先知道INSERT/UPDATE/DELETE语句的内容,应该显式地设置它们。好的设计技巧是为INSERT/UPDATE/DELETE命令建立存储过程并明确地配置数据适配器命令属性来使用它们。
l 命令构造器使用数据适配器的SelectCommand属性来决定其它命令属性的值。如果数据适配器的SelectCommand自身改变了,一定要调用RefreshSchema来更新命令属性。
l 如果命令属性是空的(默认情况下命令属性是空的),命令构造器只为数据适配器命令属性生成一个命令。如果你明确地设置一个命令属性,命令构造器不会覆盖它。如果你希望命令构造器为一个已经设置了的命令属性生成一个命令,要把命令属性设置为空。
批处理SQL语句
很多数据库支持在一个命令执行中组合、批处理多个命令执行。例如,SQL Server允许你使用分号分隔命令。把多个命令组合成为一个减少了对服务器的访问次数,可以提高应用程序的性能。例如,你能在本地应用程序中存储所有的删除,并在数据源发布一个批处理命令调用来删除它们。
尽管它提高了性能,但是也增加了应用程序管理数据集里面数据更新的复杂性。为了保持简单性,你也许会为数据集中的每个数据表建立一个数据适配器。
使用多个表填充数据集
如果使用批处理SQL语句检索多个表并填充一个数据集,第一张表的名字使用Fill方法指定的表名,后面的表的名字是Fill方法指定的名字加上一个数字,从1开始逐渐增加。例如,如果运行下面的代码:
'Visual Basic
Dim da As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers;
SELECT * FROM Orders;", myConnection)
Dim ds As DataSet = New DataSet()
da.Fill(ds, "Customers")
//C#
SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Customers;
SELECT * FROM Orders;", myConnection);
DataSet ds = new DataSet();
da.Fill(ds, "Customers");
|
从Customers表中得到的数据放在叫"Customers"的数据表中,从Orders表中得到的数据放在"Customers1"数据表中。
你可以在数据表被填充后修改"Customers1"表的属性为"Orders"。但是接下来的填充的结果是"Customers"表被重新填充,但是"Orders"表被略过了并且建立了另一个"Customers1"表。为了避免这种情况,建立一个把"Customers1"映射到"Orders"的DataTableMapping,并且为其它的表建立映射。例如:
'Visual Basic
Dim da As SqlDataAdapter = New SqlDataAdapter("SELECT * FROM Customers;
SELECT * FROM Orders;", myConnection)
da.TableMappings.Add("Customers1", "Orders")
Dim ds As DataSet = New DataSet()
da.Fill(ds, "Customers")
//C#
SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Customers;
SELECT * FROM Orders;", myConnection);
da.TableMappings.Add("Customers1", "Orders");
DataSet ds = new DataSet();
da.Fill(ds, "Customers");
|
使用DataReader
下面是使用DataReader提高性能的一些技巧:
l 在访问任何与命令(Command)相关的输出参数前DataReader必须关闭。
l 在读完数据后就关闭DataReader。如果你正在使用的连接只返回该DataReader,在关闭DataReader后立即关闭连接。
l 另一种明确地关闭连接的方法是给ExecuteReader方法传递CommandBehavior.CloseConnection以确保当DataReader关闭时相关的连接关闭了。如果你从某个方法返回DataReader,并且没有办法控制DataReader或者相关的连接关闭的情况下特别有用。
l DataReader不能在层之间远程访问。DataReader是设计用于连接数据访问的。
l 使用类型化的存取程序(例如GetString、GetInt32等等)来访问列数据。这节省了将GetValue返回的对象作为特定类型的必要的处理。
l 在某一时刻只有一个DataReader能够打开。。在ADO中,如果你打开一个连接并请求两个使用只向前的只读游标的记录集,ADO隐性地为游标的生命周期的数据存储打开第二个不在连接池中的连接,接着隐性地关闭它。在ADO.NET中,如果你想在同一个数据存储上同时打开两个DataReader,你必须明确地建立两个连接,每个DataReader一个。通过这种方法ADO.NET给了你对连接池使用的更多控制。
l 默认情况下,DataReader在每个Read方法中把整个行载入内存中。这允许你随机访问当前行的任意列。如果随机访问是不必要的,为了提高性能,把CommandBehavior.SequentialAccess传递给ExecuteReader调用。这改变了DataReader的默认行为,只在需要时才把数据载入内存。注意CommandBehavior.SequentialAccess要求你按次序访问返回的列。也就是,一旦你读过了返回的某个列,就不能再次读取它的值了。
l 如果你结束了从DataReader中读取数据,但是仍然有大量的未读取的结果等待,那么调用Command的Cancel比调用DataReader 的Close好。调用DataReader 的Close引起它检索等待的结果并且先清空流后关闭游标。调用Command的 Cancel删除服务器上的结果,因此当DataReader关闭时,它不需要再读取结果。如果你从Command返回输出参数,则调用Cancel删除它们。如果你要读取任何输出参数,不要调用Command 的Cancel;最后调用DataReader的 Close。
二进制大对象(BLOB)
当使用DataReader检索二进制大对象时,必须给ExecuteReader方法调用传递CommandBehavior.SequentialAccess。因为DataReader的默认行为是在每个Read中把整行载入内存中,但是由于BLOB可能很大,结果可能是一个BLOB对象使用大量的内存。SequentialAccess把DataReader的行为设置为只载入必要的数据,接着你能使用GetBytes或者GetChars控制每次载入多少数据。
记住使用SequentialAccess时,你不能无序地访问DataReader返回的不同字段。也就是说,如果查询返回三个列,第三个是BLOB,并且你希望访问前两个列的数据,你必须先访问第一个列,接着在访问BLOB数据前访问第二个列。这是因为现在数据是按次序返回的,在DataReader读过它后不能再次访问。
使用命令(Command)
ADO.NET为命令执行提供了几个不同的方法,同时也为优化命令的执行提供了不同的选择。下面的技巧包括怎样选择最好的命令执行和怎样提供一个被执行命令的性能。
使用OleDbCommand的最好经验
不同的.NET框架组件数据提供程序之间的命令执行是尽可能标准的。但是,在这些数据提供程序间也有些不同。下面的一些可以调整OLE DB数据提供程序命令执行的技巧:
l 与ODBC CALL语法一起使用CommandType.Text来调用存储过程。仅仅使用CommandType.StoredProcedure生成ODBC CALL语法。
l 一定要设置OleDbParameter类型、大小(如果可用)、精度和小数位(如果参数是数值型或者十进制型)。注意如果你没有明确地提供参数信息,OleDbCommand使用每一个命令执行重新建立OLE DB参数存取程序。
使用SqlCommand的经验
使用SqlCommand执行存储过程的技巧:如果你要调用一个存储过程,为SqlCommand的 CommandType属性指定StoredProcedure的CommandType。这样就删除了在命令执行前分析命令的需求,明确地把它标识为存储过程了。
Prepare方法的使用
Command.Prepare方法能够提高数据源中重复的参数化命令的性能。Prepare指示数据源为多个调用优化特定的命令。为了更高效率地使用Prepare,你必须十分清楚数据源怎样回应Prepare调用。对于类似SQL Server 2000的数据源,命令是隐式优化的,对Prepare的调用是没有必要的,但是对于另一些数据源,例如SQL Server 7.0,Prepare效率更高。
明确地指定大纲和元数据
在ADO.NET中当用户没有指定元数据信息时,有很多对象推导这些信息。例如:
l DataAdapter.Fill方法,如果不存在的话,它在记录集中建立表和列。
l CommandBuilder,它为单个的SELECT语句生成数据适配器命令属性。
l CommandBuilder.DeriveParameters,它组合Command对象的Parameters集合。
但是每次使用这些特性时都会造成效率降低。我们推荐主要在设计时和ad-hoc应用程序中使用这些特性。在可能的情况下,明确地指定大纲和元数据,包括在数据集中定义表和列,定义数据适配器的Command属性,定义Command的Parameter信息。
ExecuteScalar和ExecuteNonQuery
如果你希望返回单个值,例如Count(*)、 Sum(Price)、或者Avg(Quantity),你可以使用Command.ExecuteScalar。ExecuteScalar返回第一行第一列的值,返回结果集是数量值。ExecuteScalar通过一步完成不仅简化了代码而且提高了性能,而这些工作在使用DataReader时将需要两个处理步骤。
当使用不返回行的SQL语句时,类似修改数据(例如插入、更新或者删除)或者只返回输出参数或值,使用ExecuteNonQuery。它通过建立一个空DataReader删除了任何必要的处理。
空值的检测
如果数据库的某张表的一个列允许空值,你不能使用某个与空值相等的参数来测试它。作为代替,需要编写一个WHERE子句来检测是否列和参数都是空值。下面的SQL语句返回LastName列与赋予@LastName的值相同的行,或者LastName 列和@LastName参数都为空的行:
SELECT * FROM Customers WHERE ((LastName = @LastName) OR (LastName IS NULL AND @LastName IS NULL)) |
把空(Null)作为参数值传递
当在命令中把空值作为参数值发送给数据库时,不能使用null(Visual Basic .NET中的Nothing)。作为代替必须使用DBNull.Value。例如:
'Visual Basic
Dim param As SqlParameter = New SqlParameter("@Name", SqlDbType.NVarChar, 20)
param.Value = DBNull.Value
//C#
SqlParameter param = new SqlParameter("@Name", SqlDbType.NVarChar, 20);
param.Value = DBNull.Value;
|
执行事务
事务模块为ADO.NET作了一些改变。在ADO中,当调用StartTransaction时,该调用后面的任何更新都被认为是该事务的一部分。但是在ADO.NET中,当调用Connection.BeginTransaction时,返回的Transaction对象必须与Command的Transaction属性关联。这种设计使你能在一个连接上执行多重事务。如果Command.Transaction属性没有设置为开始就与连接关联的Transaction,Command失败并出现异常。
使用连接
高性能的应用程序保持使用最少次数的数据源的连接,也利用了类似连接池的性能增强技术。下面的技巧帮你使用ADO.NET连接数据源时获得更好的性能。
连接池
SQL Server、OLE DB和.NET框架组件数据提供程序隐性为ODBC提供了连接池。你可以在连接字符串中指定不同的属性控制连接池的行为。
用DataAdapter优化连接
数据适配器的Fill和Update方法自动地为相关的命令属性打开特定的连接(如果它被关闭的话)。如果Fill或Update方法打开了连接,Fill或Update将在操作完成时关闭它。为了提高性能,只在必要时保持数据库连接打开,同时为多个操作减少打开和关闭连接的次数。
我们推荐如果你只执行单个的Fill或Update方法调用,你应该允许Fill或Update隐式打开和关闭连接。如果大量调用Fill或者Update,我们推荐显式打开,进行Fill或Update调用,然后显式关闭连接。
此外执行事务时,在开始事务前明确地打开连接,在完成事务后明确地关闭连接。例如:
'Visual Basic
Public Sub RunSqlTransaction(da As SqlDataAdapter,
myConnection As SqlConnection, ds As DataSet)
myConnection.Open()
Dim myTrans As SqlTransaction = myConnection.BeginTransaction()
myCommand.Transaction = myTrans
Try
da.Update(ds)
myTrans.Commit()
Console.WriteLine("Update successful.")
Catch e As Exception
Try
myTrans.Rollback()
Catch ex As SqlException
If Not myTrans.Connection Is Nothing Then
Console.WriteLine("An exception of type "
& ex.GetType().ToString() & _
" was encountered while attempting to roll back the transaction.")
End If
End Try
Console.WriteLine("An exception of type
" & e.GetType().ToString() & " was encountered.")
Console.WriteLine("Update failed.")
End Try
myConnection.Close()
End Sub
//C#
public void RunSqlTransaction(SqlDataAdapter da,
SqlConnection myConnection, DataSet ds)
{
myConnection.Open();
SqlTransaction myTrans = myConnection.BeginTransaction();
myCommand.Transaction = myTrans;
try
{
da.Update(ds);
myCommand.Transaction.Commit();
Console.WriteLine("Update successful.");
}
catch(Exception e)
{
try
{
myTrans.Rollback();
}
catch (SqlException ex)
{
if (myTrans.Connection != null)
{
Console.WriteLine("An exception of type " + ex.GetType() +
" was encountered while attempting to roll back the transaction.");
}
}
Console.WriteLine(e.ToString());
Console.WriteLine("Update failed.");
}
myConnection.Close();
}
|
经常关闭连接(Connection)和DataReader
当停止使用Connection或者DataReader对象时,明确地关闭它们。尽管无用单元收集程序最终会清除这些对象,并释放连接和其它可管理资源,但是无用单元收集只在必要时才发生。因此确保昂贵的资源明确地被释放仍然是你的职责。此外,连接如果没有被明确的释放将使它不会返回连接池。例如,如果连接池到达了最大值并且一个连接还有效,该超出范围并且没有被明确关闭的连接才返回到连接池。
注意不要在类的Finalize方法中调用Connection、DataReader、或者其它可管理对象的Close或者Dispose方法。在该方法中只释放类直接拥有的不可管理资源。如果类中没有任何不可管理资源,在类定义中不要包含Finalize方法。
在C#中使用"Using"语句
对C#程序员来说,确保经常关闭Connection和DataReader对象的一个简便方法是使用using语句。Using语句会自动调用留在Using语句范围内的被使用的对象上的Dispose,如下所示:
//C#
string connString = "Data Source=localhost;
Integrated Security=SSPI;Initial Catalog=Northwind;";
using (SqlConnection conn = new SqlConnection(connString))
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "SELECT CustomerId, CompanyName FROM Customers";
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
Console.WriteLine("{0}\t{1}", dr.GetString(0), dr.GetString(1));
}
}
|
避免访问OleDbConnection.State属性
如果连接打开了,OleDbConnection.State使本地OLE DB向DATASOURCEINFO属性集调用IDBProperties.GetProperties来获取DBPROP_CONNECTIONSTATUS属性,这可能引起重新返回数据源。换句话说,检查State属性可能花费很大。因此只在必要时才检查State属性。如果你需要经常检查该属性,你监听OleDbConnection的StateChange事件会使应用程序的性能更好。
与XML集成
ADO.NET在数据集中提供了广泛的XML集成,并且暴露了一些SQL Server 2000及以上版本所提供的XML功能。你能使用SQLXML 3.0来访问SQL Server 2000及以上版本所提供的XML功能。下面是使用XML和ADO.NET的一些技巧和信息。
数据集与XML
数据集与XML紧密结合,提供了执行下面操作的能力:
l 从XSD大纲载入数据集的大纲或者关系结构。
l 从XML载入数据集的内容。
l 当没有提供大纲时根据XML文档的内容推断数据集的大纲。
l 将数据集的大纲写成XSD大纲。
l 将数据集的内容写成XML。
l 使用数据集同步访问数据的相关表现、使用XmlDataDocument访问数据的层次表现。
注意:你能使用这种同步在数据集的数据上应用XML功能(例如Xpath查询和XSLT变换),或提供所有的关系型视图,或者在保持原XML不变的情况下提供XML文档中的数据的子集。
大纲接口
当从XML文件中载入数据集时,你能从XSD大纲中载入数据集的大纲,或者在载入数据前预先定义表和列。如果没有XSD大纲,并且你也不知道为XML文件的内容定义怎样的表和列,你能根据XML文档的结构推断大纲。
大纲推理作为迁移工具是有用的,但是由于推理过程有下面的限制,它只限于应用程序设计时使用:
l 推理大纲引入了附加的处理将降低应用程序的性能。
l 所有推理列的类型都是字符串型。
l 推理过程是不确定的。这就是说,它基于XML文件而不是预定的大纲。结果是你可能有两个XML文件,它们有相同的预定大纲,却因为它们的内容不同形成了两个完全不同的推理大纲。
为XML查询服务的SQL Server
如果你为XML查询返回SQL Server 2000结果,你能使用.NET框架组件SQL Server数据提供程序直接用SqlCommand.ExecuteXmlReader方法建立一个XmlReader。
SQLXML可管理类
在.NET框架组件中有一些类暴露了XML为SQL Server 2000提供的功能。这些类都在Microsoft.Data.SqlXml名字空间中,添加了执行Xpath查询和XML模板文件的能力,也能把XSLT转换为数据。
避免自动增加(Auto-Increment)值冲突
和许多数据源一样,DataSet允许你在添加新行时识别自动增加值的列。在DataSet中使用自动增加列时,由于数据源也有自动增加列,需要避免添加到DataSet中的本地行号与添加到数据源中的行之间的冲突。
例如,假设一个表的自动增加主键列是CustomerID。两个新客户信息添加到该表,获得的自动增加CustomerID值分别是1和2。接着只有第二个客户行给数据适配器传递的Update方法,在数据源中新添加的行接受的自动增加CustomerID值是1,与数据集中的2不匹配。当数据适配器用返回值填充表中的第二行时,由于第一个顾客行的CustomerID是1,便出现了错误。
为了避免这种情况,我们推荐当使用数据源和数据集中有自动增加列时,数据集中的该列的AutoIncrementStep设为-1,AutoIncrementSeed设为0,同时确保数据源中生成的自动增加标识值从1开始,步长为正。结果是数据集生成负的自动增加值,不会与数据源产生的正自动增加值冲突。另一种选择是使用Guid类型的列带有自动增加列,该算法产生的Guid值在数据集和数据源中永远不同。
如果你的自动增加列永远简单的作为唯一值,没有其它的意义,考虑使用Guid代替自动增加列。它们是唯一的,避免了做另外的工作处理自动增加列。
查找优化的并发性故障
因为DataSet被设计为从数据源断开,所有必须确保当多个客户端更新数据源的数据时应用程序避免冲突。
测试优化并发性错误有多种技术。一种是在表的列中包含时间戳。另一种技术是通过使用SQL语句中的WHERE条件检测来验证行中所有的源列值与数据库中的匹配。
多线程编程
ADO.NET的优化是为了提高性能、吞吐量和可伸缩性。结果是ADO.NET不锁定资源并且只能在单个线程中使用,其中一个例外是DataSet,它对多个阅读程序来说是线程安全安的。但是在写的时候必须锁定DataSet。
只在必要的时候使用COM交互操作(Interop)访问ADO
ADO.NET被设计成大量应用程序的最佳解决方案。但是,有些应用程序需要只能使用ADO对象。在这些情况下,应用程序能使用COM交互操作访问ADO。注意使用COM交互操作访问ADO的数据将极大的降低性能。设计应用程序时,在实现使用COM交互操作访问ADO这种设计前首选决定ADO.NET是否符合设计需要。
避免自动增加(Auto-Increment)值冲突
和许多数据源一样,DataSet允许你在添加新行时识别自动增加值的列。在DataSet中使用自动增加列时,由于数据源也有自动增加列,需要避免添加到DataSet中的本地行号与添加到数据源中的行之间的冲突。
例如,假设一个表的自动增加主键列是CustomerID。两个新客户信息添加到该表,获得的自动增加CustomerID值分别是1和2。接着只有第二个客户行给数据适配器传递的Update方法,在数据源中新添加的行接受的自动增加CustomerID值是1,与数据集中的2不匹配。当数据适配器用返回值填充表中的第二行时,由于第一个顾客行的CustomerID是1,便出现了错误。
为了避免这种情况,我们推荐当使用数据源和数据集中有自动增加列时,数据集中的该列的AutoIncrementStep设为-1,AutoIncrementSeed设为0,同时确保数据源中生成的自动增加标识值从1开始,步长为正。结果是数据集生成负的自动增加值,不会与数据源产生的正自动增加值冲突。另一种选择是使用Guid类型的列带有自动增加列,该算法产生的Guid值在数据集和数据源中永远不同。
如果你的自动增加列永远简单的作为唯一值,没有其它的意义,考虑使用Guid代替自动增加列。它们是唯一的,避免了做另外的工作处理自动增加列。
查找优化的并发性故障
因为DataSet被设计为从数据源断开,所有必须确保当多个客户端更新数据源的数据时应用程序避免冲突。
测试优化并发性错误有多种技术。一种是在表的列中包含时间戳。另一种技术是通过使用SQL语句中的WHERE条件检测来验证行中所有的源列值与数据库中的匹配。
多线程编程
ADO.NET的优化是为了提高性能、吞吐量和可伸缩性。结果是ADO.NET不锁定资源并且只能在单个线程中使用,其中一个例外是DataSet,它对多个阅读程序来说是线程安全安的。但是在写的时候必须锁定DataSet。
只在必要的时候使用COM交互操作(Interop)访问ADO
ADO.NET被设计成大量应用程序的最佳解决方案。但是,有些应用程序需要只能使用ADO对象。在这些情况下,应用程序能使用COM交互操作访问ADO。注意使用COM交互操作访问ADO的数据将极大的降低性能。设计应用程序时,在实现使用COM交互操作访问ADO这种设计前首选决定ADO.NET是否符合设计需要。
VSS(Visual SourceSafe)使用入门
五 12th
为了方便代码在特定语言和特定平台上进行显示,可将文件与特定字符编码建立关联。
如果使用 Visual SourceSafe 以 ANSI、UTF8 或 Unicode 格式存储文件,请注意它们各自的以下限制。
- ANSI 文件只允许使用当前代码页中支持的字符,这会限制国际使用。
- Unicode 文件无法使用共享签出、差异检查或合并功能,原因是此类文件是作为二进制文件处理的。可在国际文件中使用此格式。
- UTF8 文件在 Visual SourceSafe 中不能安全地工作,因为在签入、签出、差异检查和合并过程中该文件会被更改,而这会导致 UTF8 文件编辑器出现问题。
1 有时会出现某个文件无权 GET 的问题,重起 SERVER 端机器即可解决
2 有一次,不知因何原因(可能是病毒),Sourcesafe 的数据库访问权限变了,需要在 Windows 页面重新分配所有权
3 建议经常做 SourceSafe 备份,以便文件丢失时(Sourcesafe 大了会丢失),可以挽回,备份采用 WINDOWS 的自动备份功能即可(管理工具中有一个备份工具,排定一个计划,即可自动备份)
4 了解 sourcesafe 目录结构的方法如下:将所有内容 GET 出来, 用 TREE>*.txt(DOS命令),即可将该目录结构存储到一个文本文件中