450 likes | 565 Views
非连接环境下的应用程序. SQL Server 2000. SQL Server 6.5. Categories. Products. Customers. Orders. SqlDataAdapter. OleDbDataAdapter. 数据集. Categories. Products. Employees. Customers. Orders. XmlDataDocument. XML 文档. XML Web Service. 数据集.
E N D
非连接环境下的应用程序 SQL Server 2000 SQL Server 6.5 Categories Products Customers Orders SqlDataAdapter OleDbDataAdapter 数据集 Categories Products Employees Customers Orders XmlDataDocument XML 文档 XML Web Service
数据集 • 数据集在断开缓存中存储数据。数据集的结构类似于关系数据库的结构;它公开表、行和列的分层对象模型。另外,它包含为数据集定义的约束和关系。 注意 如果想要在断开与数据源的连接时使用一组表和行,则使用数据集。对于设计数据访问,使用数据集并非总是最佳的解决方案。。 数据集的基本组成部分通过标准编程构造: • DataSet 类包含数据表的 Tables 集合和 DataRelation 对象的 Relations 集合。 • DataTable 类包含表行的 Rows 集合、数据列的 Columns 集合和数据关系的 ChildRelations 和 ParentRelations 集合。 • DataRow 类包含 RowState 属性,该属性的值指示自数据表首次从数据库加载后,行是否已更改以及是如何更改的。RowState 属性的可能值包括 Deleted、Modified、New和 Unchanged。
存储过程 连接 DataSet、DataTable 和 DataColumn 的概念 DataSet DataTable DataTable 数据列 数据库 数据表 数据行 数据关联 约束 数据源 服务器
数据集、架构和 XML ADO.NET 数据集是以 XML 形式表示的数据视图,是一种数据关系视图。在 Visual Studio 和 .NET Framework 中,XML 是存储和传输各种数据时所用的格式。 因此,数据集与 XML 有密切关系。数据集和 XML 之间的这种关系使数据集有以下功能: • 数据集的结构(表、列、关系和约束)可在 XML 架构中定义。XML 架构是 W3C(万维网联合会)的基于标准的格式,用于定义 XML 数据的结构。数据集可以使用 ReadXmlSchema 和 WriteXmlSchema 方法读写存储结构化信息的架构。如果无架构可用,数据集可以从通过关系方法结构化的 XML 文档中的数据推导(通过其 InferXmlSchema 方法)出一个。 • 可以生成一个数据集类,在此类中并入架构信息以将其数据结构(如表和列)定义为类成员。 • 可以使用数据集的 ReadXML 方法将 XML 文档或流读入数据集,使用数据集的 WriteXML 方法将数据集以 XML 格式写出。因为 XML 是不同应用程序之间的标准数据交换格式,这意味着可以加载其他应用程序发送的包含 XML 格式信息的数据集。同样,数据集可以将其数据集写出为 XML 流或文档,以与其他应用程序共享或只是将其存储为标准格式。 • 可以创建数据集内容的 XML 视图(XMLDataDocument 对象),然后用关系方法(通过数据集)或 XML 方法查看和操作数据。这两种视图在更改时自动同步。
创建数据集 • DataSet构造函数 public DataSet(); public DataSet(string); protected DataSet(SerializationInfo, StreamingContext); 参数: string dataSetName: DataSet 的名称。 SerializationInfo info:将对象序列化或反序列化所需的数据。 StreamingContext context:给定序列化流的源和目的地。 可以通过调用 DataSet构造函数来创建 DataSet的实例。 例 DataSet myDataSet = new DataSet(); DataSet custDS = new DataSet("CustomerOrders");
数据集的大小写敏感性 • 在数据集中,默认情况下表和列的名称不区分大小写,即数据集中名为“Customers”的表也可能是指“customers”。这符合包括 SQL Server 在内的许多数据库的命名规则,即数据元素的名称无法通过大小写区分。 注意 与数据集不同,XML 文档区分大小写,因此架构中定义的数据元素的名称区分大小写。例如,架构协议允许要包含的架构定义名为“Customers”的表和名为“customers”的另一个不同的表。这在架构用于生成数据集类时会导致名称冲突。不过,大小写敏感性可以成为决定数据在数据集中的解释方法的因素。例如,在数据集表中筛选数据时,根据比较是否区分大小写,搜索判据可能返回不同的结果。通过设置数据集的 CaseSensitive 属性,可以控制筛选、搜索和排序是否区分大小写。默认情况下,数据集中的所有表都继承此属性的值。(对于每个单独的表可以重写此属性。)
DataSet属性 • CaseSensitive: 获取或设置一个值,该值指示 DataTable对象中的字符串比较是否区分大小写。 • Container:(从 MarshalByValueComponent继承)获取组件的容器。 • DataSetName:获取或设置当前 DataSet的名称。 • DefaultViewManager:获取 DataSet所包含的数据的自定义视图,以允许使用自定义的 DataViewManager 进行筛选、搜索和导航。 • DesignMode:(从 MarshalByValueComponent继承)获取指示组件当前是否处于设计模式的值。 • EnforceConstraints:获取或设置一个值,该值指示在尝试执行任何更新操作时是否遵循约束规则。 • ExtendedProperties:获取与 DataSet相关的自定义用户信息的集合。 • HasErrors:获取一个值,指示在此 DataSet中的任何 DataTable对象中是否存在错误。 • Locale:获取或设置用于比较表中字符串的区域设置信息。 • Namespace:获取或设置 DataSet的命名空间。 • Prefix:获取或设置一个 XML 前缀,该前缀是 DataSet的命名空间的别名。 • Relations:获取用于将表链接起来并允许从父表浏览到子表的关系的集合。 • Site:获取或设置 DataSet的 System.ComponentModel.ISite。 • Tables:获取包含在 DataSet中的表的集合。
DataSet方法 • AcceptChanges:提交自加载此 DataSet或上次调用 AcceptChanges 以来对 DataSet: 进行的所有更改 • Clear:通过移除所有表中的所有行来清除任何数据的 DataSet • Clone:复制 DataSet的结构,包括所有 DataTable 架构、关系和约束。不复制任何数据 • Copy:复制 DataSet 的结构和数据 • GetChanges:获取 DataSet的副本,该副本包含自上次加载以来或自调用 AcceptChanges:以来对该数据集进行的所有更改 • GetXml:返回存储在 DataSet中的数据的 XML 表示形式 • GetXmlSchema:返回存储在 DataSet中的数据的 XML 表示形式的 XSD 架构 • Merge:将指定的 DataSet、DataTable或 DataRow对象的数组合并到当前的 DataSet 或 DataTable 中 • ReadXml:将 XML 架构和数据读入 DataSet • ReadXmlSchema:将 XML 架构读入 DataSet • Reset:将 DataSet重置为其初始状态。子类应重写 Reset,以便将 DataSet 还原到其原始状态
AcceptChanges方法 DataSet myDataSet; myDataSet = new DataSet(); // …………. DataTable t; t = myDataSet.Tables["Suppliers"]; // 创建一个新数据行. DataRow myRow; myRow = t.NewRow(); myRow["CompanyID"] = "NWTRADECO"; myRow["CompanyName"] = "NortWest Trade Company"; // 将新行加入数据表中. t.Rows.Add( myRow ); // 调用AcceptChanges方法,数据集中所以对象 接受更改. myDataSet.AcceptChanges();
Clear方法 private void ClearDataSet(DataSet myDataSet){ // 打印出表的行数. foreach(DataTable t in myDataSet.Tables){ Console.WriteLine(t.TableName + "Rows.Count = " + t.Rows.Count.ToString()); } // 清除表中所有行. myDataSet.Clear(); // 再次打印行数. foreach(DataTable t in myDataSet.Tables){ Console.WriteLine(t.TableName + "Rows.Count = " + t.Rows.Count.ToString()); } }
Clone方法: private void GetClone(DataSet myDataSet){ // 对原数据集克隆. DataSet cloneSet; cloneSet = myDataSet.Clone(); // 其他操作代码. } Copy方法: private void CopyDataSet(DataSet myDataSet){ // 建立拷贝对象. DataSet copyDataSet; copyDataSet = myDataSet.Copy(); // 其他代码. }
GetXml、GetXmlSchema方法 private static void DemonstrateGetXml() { // 创建一个数据集,数据集有一个含有两列的表. DataSet ds = new DataSet("myDataSet"); DataTable t = ds.Tables.Add("Items"); t.Columns.Add("id", typeof(int)); t.Columns.Add("Item", typeof(string)); // 增加十行. DataRow r; for(int i = 0; i <10;i++) { r = t.NewRow(); r["id"]= i; r["Item"]= "Item" + i; t.Rows.Add(r); } // 将数据集中的内容以 XML形式显示. Console.WriteLine( ds.GetXml() ); // 以 XML形式显示数据集的构架. Console.WriteLine( ds.GetXmlSchema() ); }
DataSet对象事件 • Disposed:(从 MarshalByValueComponent继承)添加事件处理程序以侦听组件上的 Disposed 事件。 • MergeFailed:当Merge方法发生异常时发生。 事件使用: DataSet ds = new DataSet("myDataSet"); ……………… ds.MergeFailed += new MergeFailedEventHandler( Merge_Failed ); ……………… private static void Merge_Failed( object sender, MergeFailedEventArgs e ) { Console.WriteLine( "Merge_Failed Event: '{0}'", e.Conflict ); }
DataTable • DataTable是 ADO.NET 库中的核心对象。 • 当访问 DataTable对象时,注意它们是按条件区分大小写的。例如,如果一个 DataTable被命名为“mydatatable”,另一个被命名为“Mydatatable”,则用于搜索其中一个表的字符串被认为是区分大小写的。但是,如果“mydatatable”存在而“Mydatatable”不存在,则认为该搜索字符串不区分大小写。 • 如果正在以编程方式创建 DataTable,则必须先通过将 DataColumn对象添加到 DataColumnCollection(通过 Columns属性访问)中来定义其架构 • 若要向 DataTable中添加行,必须先使用 NewRow方法返回新的 DataRow对象。DataTable可存储的最大行数是 16,777,216
创建DataTable • DataTable 表示一个内存内关系数据的表,可以独立创建和使用,也可以由其他 .NET Framework 对象使用,最常见的情况是作为 DataSet 的成员使用。 • DataTable 对象可通过使用 DataTable 构造函数来创建,或者可通过将构造函数参数传递到 DataSet 的 Tables 属性的 Add 方法(它是一个 DataTableCollection)来创建。 • DataTable 对象可通过使用 DataAdapter 对象的 Fill 方法或 FillSchema 方法在 DataSet 内创建,或者可使用 DataSet 的 ReadXml、ReadXmlSchema 或 InferXmlSchema 方法从预定义的或推断的 XML 架构中创建。请注意,将一个 DataTable 作为成员添加到一个 DataSet 的 Tables 集合中后,不能再将其添加到任何其他 DataSet 的表集合中。 • 最初创建 DataTable 时,它是没有架构(结构)的。要定义表的架构,必须创建 DataColumn 对象并将其添加到表的 Columns 集合中。也可以为表定义主键列,并且可以创建 Constraint 对象并将其添加到表的 Constraints 集合中。在为 DataTable 定义了架构之后,可通过将 DataRow 对象添加到表的 Rows 集合中来将数据行添加到表。 • 创建 DataTable 时,不需要为 TableName 属性提供值,可以在其他时间指定属性,或者将其保留为空。但是,在将一个没有 TableName 值的表添加到 DataSet 中时,该表会得到一个从“Table”(表示 Table0)开始递增的默认名称 TableN。 注意 建议在提供 TableName 值时避免使用“Table”或“TableN”的命名约定,因为那样提供的名称可能与 DataSet 中现有的默认表名称冲突。如果提供的名称已经存在,将引发异常。
创建DataTable • 以下示例创建 DataTable 对象的实例,并为其指定名称“Customers”。 DataTable workTable = new DataTable("Customers"); • 以下示例创建 DataTable 实例,方法是:将其添加到 DataSet 的 Tables 集合中。 DataSet custDS = new DataSet(); DataTable custTable = custDS.Tables.Add("CustTable");
创建DataTable 例:通过DataColumn和 DataRow创建数据表 DataTable myDataTable = new DataTable(“myDataTable"); DataColumn myDataColumn; DataRow myDataRow; // Create first column and add to the DataTable. myDataColumn = new DataColumn(); myDataColumn.DataType= System.Type.GetType("System.Int32"); myDataColumn.ColumnName = "ChildID"; myDataColumn.AutoIncrement = true; myDataColumn.Caption = "ID"; myDataColumn.ReadOnly = true; myDataColumn.Unique = true; // Add the column to the DataColumnCollection. myDataTable.Columns.Add(myDataColumn); myDataSet.Tables.Add(myDataTable); // Create three sets of DataRow objects, five rows each, and add to DataTable. for(int i = 0; i <= 4; i ++){ myDataRow = myDataTable.NewRow(); myDataRow["childID"] = i; myDataTable.Rows.Add(myDataRow);}
DataTable属性 • CaseSensitive:指示表中的字符串比较是否区分大小写。 • Columns:获取属于该表的列的集合。 • Constraints获取由该表维护的约束的集合。 • DataSet:获取该表所属的 DataSet。 • PrimaryKey:获取或设置充当数据表主键的列的数组 • Rows:获取属于该表的行的集合。 • TableName:获取或设置 DataTable的名称。
DataTable方法 • AcceptChanges提交自上次调用 AcceptChanges 以来对该表进行的所有更改。 • BeginInit初始化。在运行时发生。 • BeginLoadData在加载数据时关闭通知、索引维护和约束。 • Clear清除所有数据的 DataTable。 • Clone克隆 DataTable 的结构,包括所有 DataTable架构和约束。 • Compute计算用来传递筛选条件的当前行上的给定表达式。 • Copy复制该 DataTable的结构和数据。 • EndInit结束初始化。此初始化在运行时发生。 • EndLoadData在加载数据后打开通知、索引维护和约束。 • Equals(从 Object继承) 已重载。确定两个 Object实例是否相等。
DataTable方法 • GetChanges已重载。获取 DataTable 的副本,该副本包含自上次加载以来或自调用 AcceptChanges以来对该数据集进行的所有更改。 • GetErrors获取包含错误的 DataRow对象的数组。 • GetType(从 Object继承) 获取当前实例的 Type。 • ImportRow将 DataRow复制到 DataTable中,保留任何属性设置以及初始值和当前值。 • LoadDataRow查找和更新特定行。如果找不到任何匹配行,则使用给定值创建新行。 • NewRow创建与该表具有相同架构的新 DataRow。 • RejectChanges回滚自该表加载以来或上次调用 AcceptChanges以来对该表进行的所有更改。 • Reset将 DataTable重置为其初始状态。 • Select已重载。获取 DataRow对象的数组。
DataTable对象事件 • ColumnChanged:在 DataRow 中指定的 DataColumn 的值被更改后发生。 • ColumnChanging:在 DataRow 中指定的 DataColumn 的值发生更改时发生。 • Disposed:(从 MarshalByValueComponent继承)添加事件处理程序以侦听组件上的 Disposed事件。 • RowChanged:在成功更改 DataRow之后发生。 • RowChanging:在 DataRow正在更改时发生。 • RowDeleted:在表中的行已被删除后发生。 • RowDeleting:在表中的行要被删除之前发生。
使用DataTable对象事件 例:创建 4 个事件:OnColumnChanged、OnColumnChanging、OnRowChanged 和 OnRowChanging。这些事件中的每一个都在列或行更改时发生 workTable.ColumnChanged += new DataColumnChangeEventHandler(OnColumnChanged); workTable.ColumnChanging += new DataColumnChangeEventHandler(OnColumnChanging); workTable.RowChanged += new DataRowChangeEventHandler(OnRowChanged); workTable.RowChanging += new DataRowChangeEventHandler(OnRowChanging);
使用DataTable对象事件 protected static void OnColumnChanged(object sender, DataColumnChangeEventArgs args) { Console.Write(" ColumnChanged: "); Console.Write(args.Column.ColumnName + " changed to '" + args.ProposedValue + "'\n"); } protected static void OnColumnChanging(object sender, DataColumnChangeEventArgs args) { Console.Write("ColumnChanging: "); Console.Write(args.Column.ColumnName + " equals '" + args.Row[args.Column] +"', changing to '" + args.ProposedValue + "'\n"); } protected static void OnRowChanging(object sender, DataRowChangeEventArgs args) { if (args.Action != DataRowAction.Nothing) Console.WriteLine(" RowChanging: Action = " + args.Action + ", CustID = " + args.Row["CustID"]); } protected static void OnRowChanged(object sender, DataRowChangeEventArgs args) { if (args.Action != DataRowAction.Nothing) Console.WriteLine(" RowChanged: Action = " + args.Action + ", CustID = " + args.Row["CustID"]); }
DataColumn • DataColumn 构造函数 public DataColumn(); public DataColumn(string); public DataColumn(string, Type); public DataColumn(string, Type, string); public DataColumn(string, Type, string, MappingType); 参数: • columnName:一个字符串,它表示要创建的列的名称。如果设置为空引用(Visual Basic 中为 Nothing)或空字符串 (""),则当添加到列集合中时,将提供一个默认名称。 • dataType:支持的 DataType。 • Expr: 用于创建该列的表达式。 • Type:MappingType 值之一。
例:显示如何使用 DataColumn 构造函数的一个重载版本 private void CreateComputedColumn(DataTable myTable) { System.Type myDataType; myDataType = System.Type.GetType("System.Decimal"); string strExpr; // “Price” 列的值乘以 “Quantity”列的值得到 “Total” 列. strExpr = "Price * Quantity"; // 创建列. DataColumn myColumn = new DataColumn("Total", myDataType, strExpr, MappingType.Attribute); // 设置其他属性. myColumn.AutoIncrement = false; myColumn.ReadOnly = true; // 将列加入到一个数据表对象的数据列集合(DataColumnCollection). DataSet1.Tables["OrderDetails"].Columns.Add(myColumn); }
DataColumn 属性 • Caption获取或设置列的标题。 • ColumnName 获取或设置 DataColumnCollection中的列的名称。 • DataType获取或设置存储在列中的数据的类型。 • DefaultValue 在创建新行时获取或设置列的默认值。 • Expression获取或设置表达式,用于筛选行、计算列中的值或创建聚合列。 • ExtendedProperties获取与 DataColumn 相关的自定义用户信息的集合。 • MaxLength获取或设置文本列的最大长度。 • Namespace 获取或设置 DataColumn的命名空间。 • Ordinal 获取列在 DataColumnCollection集合中的位置。 • Prefix获取或设置一个 XML 前缀,该前缀是 DataTable的命名空间的别名。 • ReadOnly 获取或设置一个值,指示一旦向表中添加了行,列是否还允许更改。 • Site(从 MarshalByValueComponent继承)获取或设置组件的位置。 • Table 获取列所属的 DataTable。 • Unique获取或设置一个值,指示列的每一行中的值是否必须是唯一的。
DataColumn 方法 • Dispose:(从 MarshalByValueComponent继承)已重载。释放由 MarshalByValueComponent 使用的资源。 • Equals:(从 Object继承) 已重载。确定两个 Object 实例是否相等。 • GetHashCode:(从 Object继承) 用作特定类型的哈希函数,适合在哈希算法和数据结构(如哈希表)中使用。 • GetService:(从 MarshalByValueComponent继承)获取 IServiceProvider 的实施者。 • GetType:(从 Object继承) 获取当前实例的 Type。 • ToString:已重写。获取列的 Expression(如果存在的话)。
DataRow • DataRow 和 DataColumn 对象是 DataTable 的主要组件。使用 DataRow 对象及其属性和方法检索、评估、插入、删除和更新 DataTable 中的值。 • 若要创建新的 DataRow,使用 DataTable 对象的 NewRow方法。创建新的 DataRow 之后,使用 Add方法将新的 DataRow 添加到 DataRowCollection 中。最后,调用 DataTable 对象的 AcceptChanges 方法以确认是否已添加。 • 可通过调用 DataRowCollection 的 Remove方法或调用 DataRow 对象的 Delete方法,从 DataRowCollection 中删除 DataRow。Remove 方法将行从集合中移除。与此相反,Delete 标记要移除的 DataRow。在调用 AcceptChanges 方法时发生实际移除。通过调用 Delete,可在实际删除行之前以编程方式检查哪些行被标记为移除。
DataRow 属性 • HasErrors:获取一个值,该值指示某行是否有错。 • Item:已重载。获取或设置存储在指定列中的数据。在 C# 中,该属性为 DataRow类的索引器。 • ItemArray:通过数组获取或设置此行的所有值。 • RowError:获取或设置行的自定义错误说明。 • RowState :获取该行与它和 DataRowCollection的关系相关的当前状态。 • Table:获取该行拥有其架构的 DataTable。
DataRow 属性 • Table:获取该行拥有其架构的 DataTable private void GetTable(DataRow myRow){ // 获取数据行所在的数据表 DataTable myTable = myRow.Table; // 打印表中每一列的数据类型 foreach(DataColumn dc in myTable.Columns){ Console.WriteLine(dc.DataType); } }
DataRow 方法 • AcceptChanges:提交自上次调用 AcceptChanges 以来对该行进行的所有更改。 • BeginEdit:对 DataRow对象开始编辑操作。 • CancelEdit: 取消对该行的当前编辑。 • ClearErrors :清除该行的错误,包括 RowError 和用 SetColumnError设置的错误。 • Delete:删除 DataRow。 • EndEdit :终止发生在该行的编辑。 • Equals:(从 Object 继承) 已重载。确定两个 Object实例是否相等。 • GetChildRows: 已重载。获取 DataRow的子行。 • GetColumnError: 已重载。获取列的错误说明。 • GetColumnsInError :获取包含错误的列的数组。 • GetParentRow:已重载。获取 DataRow的父行。 • GetParentRows:已重载。获取 DataRow 的父行。 • GetType:(从 Object 继承) 获取当前实例的 Type。 • HasVersion :获取一个值,该值指示指定版本是否存在。 • IsNull:已重载。获取一个值,该值指示指定列是否包含空值。 • RejectChanges:拒绝自上次调用 AcceptChanges 以来对该行进行的所有更改。 • SetColumnError:已重载。为列设置错误说明。
BeginEdit方法 • 使用 BeginEdit方法将 DataRow置于编辑模式。在该模式中,事件被临时挂起,以便允许用户在不触发验证规则的情况下对多行进行多处更改。例如,如果需要确保总数列的值等于行中借贷列的值,则可以将每一行都置入编辑模式,以便在用户尝试提交值之前挂起对行值的验证。 • BeginEdit方法在用户更改数据绑定控件的值时被隐式调用;EndEdit方法在调用 DataTable对象的 AcceptChanges方法时被隐式调用。当处于该编辑模式时,DataRow存储原始值和新建议值的表示形式。因此,只要尚未调用 EndEdit方法,就可以通过传递 Item 属性的 version参数的 DataRowVersion.Original或 DataRowVersion.Proposed来检索原始版本或建议版本。此时,还可通过调用 CancelEdit方法取消任何编辑。 • 若要查看行中是否包含原始值或建议值,请调用 HasVersion方法。
foreach(DataRow myRow in t.Rows){ myRow.BeginEdit(); myRow[0]=(int) myRow[0]+10; Console.Write("\t Original \t" + myRow[0, DataRowVersion.Original]); Console.Write("\t Proposed \t" + myRow[0,DataRowVersion.Proposed] + "\n"); } Console.WriteLine("\n"); // 接受更改 t.AcceptChanges(); // 在调用 BeginEdit后修改两行的值 t.Rows[0].BeginEdit(); t.Rows[1].BeginEdit(); t.Rows[0][0]= 100; t.Rows[1][0]=100; try{ // 调用 EndEdit. t.Rows[0].EndEdit(); t.Rows[1].EndEdit(); } catch(Exception e){ // 处理异常和返回值. System.Diagnostics.EventLog log = new System.Diagnostics.EventLog(); log.Source = "My Application"; log.WriteEntry(e.ToString()); Console.WriteLine("Exception of type {0} occurred.", e.GetType()); }
// 创建一个表,有两列,十行. DataTable myTable = new DataTable("myTable"); //创建列 DataColumn c1 = new DataColumn("id",Type.GetType("System.Int32")); c1.AutoIncrement=true; DataColumn c2 = new DataColumn("item", Type.GetType("System.String")); myTable.Columns.Add(c1); myTable.Columns.Add(c2); // 添加十行. DataRow newRow; for(int i = 0; i <10; i++){ newRow = myTable.NewRow(); newRow["item"] = "Item " + i; myTable.Rows.Add(newRow); } myTable.AcceptChanges(); // 建立表的数据视图. DataRowCollection rc = myTable.Rows; rc[0].Delete(); rc[2].Delete(); myTable.AcceptChanges(); }
填充数据集 • 数据集是容器,因此需要用数据填充它。填充数据集时,将引发各种事件,应用约束检查,等等。 可以用多种方法填充数据集: • 调用数据适配器的 Fill方法。这导致适配器执行 SQL 语句或存储过程,然后将结果填充到数据集中的表中。如果数据集包含多个表,每个表可能有单独的数据适配器,因此必须分别调用每个适配器的 Fill方法。 • 通过创建 DataRow对象并将它们添加到表的 Rows集合,手动填充数据集中的表。(只能在运行时执行此操作,无法在设计时设置 Rows集合。)有关更多信息,请参见将数据添至表中。 • 将 XML 文档或流读入数据集。 • 合并(复制)另一个数据集的内容。如果应用程序从不同的来源(例如,不同的 XML Web services)获取数据集,但是需要将它们合并为一个数据集,该方案会很有用。
填充数据集 调用DataAdapter对象的Fill方法,将结果返回到DataSet中 例: string strcon,strsql; strcon="Data Source=(local);"+"database=Northwind;"+"Integrated Security=sspi;"; strsql="SELECT orderID, CustomerID,EmployeeID,OrderDate FROM Orders"; SqlDataAdapter da=new SqlDataAdapter(strsql,strcon); DataSet ds=new DataSet(); da.Fill(ds,"Orders");
数据集中的记录位置和导航 • 因为数据集是完全断开的数据容器,所以数据集(与 ADO 记录集不同)不需要或不支持当前记录的概念。相反,数据集中的所有记录都可用。 • 由于没有当前记录,因此就没有指向当前记录的特定属性,也没有从一个记录移动到另一个记录的方法或属性。(比较而言,ADO 记录集支持绝对记录位置和从一个记录移动到另一个记录的方法。)可以访问数据集中以对象形式出现的各个表;每个表公开一个行集合。可以像处理任何集合那样处理行集合,通过集合的索引访问行,或者用编程语言通过集合特定的语句来访问行。 注意 如果将 Windows 窗体中的控件绑定到数据集,则可以使用窗体的绑定结构简化对个别记录的访问。
相关表和 DataRelation 对象 如果数据集中有多个表,这些表中的信息可能是相关的。数据集没有这些关系的继承 知识,因此为了使用相关表中的数据,可以创建 DataRelation 对象来描述数据集中表 之间的关系。可使用 DataRelation对象以编程方式获取父记录的相关子记录和从子记 录获取父记录。 例如,顾客和订单数据,如 Northwind 数据库中的情形。“Customers”表可能包含如下记录: CustomerID CompanyName City ALFKI Alfreds Futterkiste Berlin ANTON Antonio Moreno Taquerias Mexico D.F. AROUT Around the Horn London 数据集也可能包含另一个含有订单信息的表。“Orders”表包含外键列形式的 Customer ID。 只选择“Orders”表中的某些列,可能类似于以下内容: OrderId CustomerID OrderDate • ALFKI 10/03/1997 10702 ALFKI 10/13/1997 • ANTON 11/27/1996 • ANTON 4/15/1997 因为每个顾客可以有一个以上的订单,所以在顾客和订单之间存在一对多关系。在上 表中,顾客 ALFKI 有两个订单。可以用 DataRelation对象从子表或父表获取相关记录。 例如,当使用描述顾客 ANTON 的记录时,可以获取描述该顾客的订单的记录集合。同 样,如果使用描述订单号 10507 的记录,则可以使用 DataRelation对象获取描述此订单的顾客 (ANTON) 的记录。
约束 • 与大多数数据库一样,数据集也支持约束,作为一种确保数据完整性的方法。约束是在表中插入、更新或删除行时应用的规则。可以定义两种类型的约束: • 唯一约束,检查列中的新值在表中是否是唯一的。 • 外键约束,定义当主表中的记录被更新或删除时相关子记录应如何更新的规则。 • 在数据集中,约束与单个表(外键约束)或列(唯一约束,即保证列值具有唯一性的约束)关联。约束作为类型 UniqueConstraint或 ForeignKeyConstraint的对象实现。然后它们被添加到表的 Constraints 集合。另外,也可以通过只是将数据列的 Unique 属性设置为 true来指定唯一约束。 • 数据集本身支持布尔型 EnforceConstraints 属性,该属性指定是否强制约束。默认情况下,该属性设置为 true。不过,有时暂时关闭约束很有用。最常见的情形是当更改记录过程中所采用的方式将暂时导致无效状态时。完成更改(并由此返回有效状态)后,可以重新启用约束。 • 在 Visual Studio 中,定义数据集时会隐式创建约束。通过将主键添加到数据集,即会为主键列隐式创建一个唯一约束。通过将其他列的 Unique 属性设置为 true,可以为它们指定唯一约束。 • 通过在数据集中创建 DataRelation对象来创建外键约束。除了允许以编程方式获取有关相关记录的信息外,DataRelation对象还允许定义外键约束规则。
数据访问策略建议 • ADO.NET 假定一个用于数据访问的模型:在其中打开一个连接,获取数据或执行操作,然后关闭该连接。ADO.NET 为使用此模型提供两个基本的策略。 • 一个模型是在数据集中存储数据,这是断开与数据源的连接时可以使用的记录的内存中缓存。若要使用一个数据集,可以创建该数据集的实例,然后使用数据适配器从数据源填充它。然后可以使用数据集内的数据,例如,通过将控件绑定到数据集成员。 • 另一个策略是直接对数据库执行操作。在此模型中,可使用包含 SQL 语句或对存储过程的引用的数据命令对象。然后可以打开一个连接,执行命令以执行操作,接着关闭连接。如果该命令返回结果集(即如果该命令执行 Select 语句),则可以使用数据读取器获取数据,数据读取器的功能类似于高效的只读游标。数据读取器然后作为数据绑定的来源。每一策略都具有特定的优点,应基于数据访问要求选择策略。
将数据存储在数据集内 Visual Studio .NET 应用程序中数据访问的常见模型是在数据集中存储数据并使用数据适配器读取和写入数据库中的数据。数据集模型的优越性有: • 使用多个表 一个数据集可以包含多个结果表,它将这些表作为离散对象维护。可以单独使用这些表或作为父子表在它们之间导航。 • 操作来自多个源的数据 数据集内的表可表示来自多个不同源的数据,例如来自不同数据库、XML 文件、电子表格等的数据,都可出现在同一个数据集中。数据在数据集内以后,可以操作数据并以同种格式关联数据,就好像它们来自单个源。 • 在分布式应用程序中的层间移动数据 通过在数据集内保存数据,可以方便地将它在应用程序的表示层、业务层和数据层之间移动。 • 与其他应用程序进行数据交换 数据集提供一种功能强大的数据交换方式,它可以与应用程序的其他组件以及其他应用程序交换数据。数据集包含对许多功能的广泛支持,如将数据序列化为 XML 和读写 XML 架构。 • 数据绑定 如果正在使用窗体,将控件绑定到数据集内的数据通常比执行命令后以编程方式将数据值加载到控件方便。 • 维护记录以供重复使用 通过数据集,无需再次查询数据库即可重复使用相同的记录。使用数据集功能,可以对记录进行筛选和排序,并且可以将数据集用作数据源(如果正在分页)。 • 便于编程 当使用数据集时,可以生成一个将其结构表示为对象的类文件(例如,数据集内的 Customers 表可以作为 dataset.Customers 对象访问)。这使得用它编程更容易、更清楚也更不易出错,并且受到智能感知、“数据适配器配置向导”等 Visual Studio 工具的支持。
直接执行数据库操作 • 还可以直接与数据库交互。在此模型中,可使用包含 SQL 语句或对存储过程的引用的数据命令对象。然后可以执行命令以执行该操作。如果该命令返回结果集(即如果该命令执行 Select 语句),则可以使用数据读取器获取数据,数据读取器的功能类似于高效的只读游标。 • 安全说明 当使用 CommandType 属性设置为 Text的数据命令时,请对从客户端发送过来的信息进行仔细检查,然后再将它传递给数据库。恶意用户可能会试图发送(插入)修改过的或其他 SQL 语句,以获得未经授权的访问或破坏数据库。在将用户输入内容传输到数据库之前,应始终确认这些信息是有效的。如果可能的话,请始终使用参数化查询或存储过程,这是最佳措施。 直接执行数据库操作具有特定的优点,这些优点包括: • 额外功能 如前所述,有一些操作只能通过执行数据命令完成,如执行 DDL 命令。 • 对执行的更多的控制 通过使用命令和数据读取器(如果正读取数据),可以对如何和何时执行 SQL 语句或存储过程以及哪些将成为结果或返回值进行更多的控制。 • 更少的系统开销 通过直接在数据库中读写,可以不必在数据集内存储数据。由于数据集需要内存,因此可以减少应用程序中的一些系统开销。当打算只使用数据一次(如在 Web 页中显示搜索结果)时尤其如此。在这种情况下,显示数据时可能不需要创建和填充数据集这一步。 • 某些情况下编程更少 在少数情况下(尤其是 Web 应用程序),保存数据集状态需要额外编程。例如,在“Web 窗体”页中,每个往返过程都重新创建页面;除非添加编程来保存和还原数据集,否则每个往返过程也都会放弃并重新创建数据集。如果使用数据读取器直接从数据库读取,则可以避免管理数据集所需的额外步骤。
访问数据建议 Web 窗体 • 通常是使用数据命令;若要获取数据,则使用数据读取器。因为每次 Web 窗体页进行往返过程时都重新创建该页及其控件和组件,所以每次都创建并填充数据集通常是效率低下的,除非还想要在往返过程间将数据集放入缓存。 在以下情况下使用数据集: • 想要使用多个单独的表或来自不同数据源的表。 • 正与其他应用程序或诸如 XML Web services 之类的组件交换数据。 • 需要通过从数据库获取的每一记录进行全面的处理。如果使用数据命令和数据读取器,则一边读取每一记录一边处理它可能导致连接长期保持打开状态,这可能影响应用程序的性能和可缩放性。 • 如果数据处理涉及相互依赖的记录(例如,在相关表中查找信息)。 • 如果想要执行 XML 操作,例如数据上的 XSLT 转换。 • 如果喜欢数据集所提供的简便的编程方式。
访问数据建议 XML Web services • XML Web services 是 ASP.NET Web 应用程序,因此使用与 Web 窗体页相同的模型:每次对其进行调用时创建和放弃 XML Web services。这暗示 XML Web services 的数据访问模型大体上与用于 Web 窗体的数据访问模型相同。但是,XML Web services 通常是中间层对象,并且其主要用途通常是与 Web 上的其他应用程序交换数据。 在以下情况下使用数据集: • XML Web services 发送和接收数据;例如,将数据作为方法的返回值发送并将数据作为方法参数接收。这在 XML Web services 中是基本选择;即使出于其他原因可以考虑使用数据命令,但与其他组件的数据交换几乎始终意味着应使用数据集。 • 出于上面列出的适合于 Web 窗体的任何原因。 • 在以下情况下请使用数据命令(并在适当时使用数据读取器): • XML Web services 正检索标量值。 • XML Web services 正执行非查询操作,例如 DDL 命令。 • XML Web services 正调用存储过程以在数据库内执行逻辑。
访问数据建议 Windows 窗体 • 一般而言,在 Windows 窗体中使用数据集。Windows 窗体通常用于胖客户端,在其中每一用户操作不创建和放弃窗体(及其数据),这与 Web 窗体相同。Windows 窗体应用程序传统上还提供有益于维护记录缓存(例如逐一在窗体中显示记录)的数据访问方案。 具体而言,在以下情况下请使用数据集: • 如果正重复使用相同的记录,例如允许用户在记录间导航。 • 如果正使用 Windows 窗体数据绑定结构,该结构是为使用数据集而专门设计的。 • 出于在上面的 Web 窗体下列出的其他任何原因。 在以下情况下请使用数据命令(并在适当时使用数据读取器): • 如果正从数据库获取标量值 • 如果正执行非查询操作,如 DDL 命令。 • 如果正在获取只读数据以显示在窗体中,例如,创建报表。另需注意的是,如果不需要在访问数据后保持数据可用,则使用数据命令。