数据库连接 目标 : 熟练掌握 connection,command, DataReader, DataSet 类进行数据库连接. 重点 : 数据读取器, 和数据集的使用. 难点 : 数据集数据的填充. 一 ADO.net 概述 ADO.NET 是新一代 Microsoft ActiveX 数据对象 (ADO), 它是一种应用程序编程界面 (API), 可用来创建分布式的数据共享应用程序 尽管 ADO.NET 保留了以前的 ADO 模型的一些主要概念, 但其功能已大大增强, 可用来访问来自各种数据源的结构化数据 ADO.NET 使用 XML 在程序之间或者与 Web 页交换数据 可在需要连接到 传送 检索 操纵和更新任何符合 OLE DB 数据源 ( 如 Microsoft SQL Server) 数据的客户应用程序中使用 ADO.NET 应用程序还可使用 OLE DB 访问以非关系格式存储的数据, 如 Microsoft Excel 目前对管理信息系统的开发设计主要有 C/S 和 B/S 两种结构, 下面对两种结构进行一下简单的比较 [2] 运用 C/S 结构, 采用 PB Delphi 或 VB 等技术来开发 操作系统采用 Windows2000, 数据库软件使用 Oracle 数据库,C/S 又称 Client/Server 或客户 / 服务器模式 服务器通常采用高性能的 PC 工
作站或小型机, 并采用大型数据库系统, 如 Oracle, Sybase, Informix 或 SQL Server 客户端需要安装专用的客户端软件 C/S 结构的数据库管理系统, 如图 2.1 所示 图 2.1 C/S 结构图即一般用户在客户端上操作时, 客户端向服务器端数据库提出请求 这时, 服务器发出响应 ; 客户端收到响应后, 开始执行任务 数据库管理员在服务器端上利用管理平台管理和维护数据库 B/S 是 Browser/Server 的缩写, 客户机上只要安装一个浏览器 (Browser), 如 Netscape Navigator 或 Internet Explorer,mxhon, 服务器安装 Oracle,Sybase, Informix 或 SQL Server 等数据库 浏览器通过 Web Server 同数据库进行数据交互 B/S 结构原理如图 2.2 所示, 多数页面都是通过 ASP 脚本程序直接访问数据库和文件系统, 有部分 ASP 程序通过组件 ( 上传组件 ) 访问数据库和文件系统 ASP 页面 ASP 页面 上传组件 文件系统 数据库
图 2.2 B/S 结构系统工作原理图 下面讨论 ADO.net 的一些特性 : 与 ADO 的相似点创建 ADO.net 是为了满足当今应用程序发展的需要 同时, 它还必须尽量与 ADO 保持相似, 以便使目前的 ADO 编程人员不会感到难以从 ADO 迁移到 ADO.net ADO.net 与.net 框架完全集成, 因此对 ADO 编程人员来说, 不会感到十分陌生 使用数据集 (DataSet) 数据集是 ADO.net 的一个重要组件 数据集是数据库在内存中的一个副本 它包含许多表, 这些表反过来又与数据库中的表和视图进行通信 它位于内存中, 与数据库之间没有活动连接 可将数据集描述为数据库数据的一个非连接快照 这种结构提高了可伸缩性, 因为只有需要读取或写入数据库时才使用数据集 XML 支持 XML 如今正在成为一种事实标准 ADO.net 在很基础的层次支持 XML.net 和 ADO.net 中的 XML 类的框架具有相同的结构 交互式提问 ADO 和 ADO.net 有哪些相同点和不同点? ADO.NET 是对 ADO 的改进 快速了解 ADO.NET 优点的一种途径就是对比它和 ADO 的功能
功能 ADO ADO.net 内存驻留的数据表示多个表间的关系 使用 RecordSet 对象, 看起来像一个表 需要使用 JOIN 查询将多个数据库表中的数据组合到单个结果表中 使用 DataSet 对象, 该对象可包含一个或多个由 DataTable 对象表示的表 支持 DataRelation 对象, 该对象可将一个 DataTable 对象中的行与另一个 DataTable 对象中的行关联起来 数据访问 顺序扫描数据集行 使用导航范例实现对表中数据行的非顺序访问 根据关系从一个表的数据行导航到另一个表的对应行 非连接访问 由记录集提供, 但通常支持由 Connection 对象表示的连接访问 通过调用 OLE DB 提供程序与数据库进行通信 通过对 DataSetCommand 对象的标准调用与数据库进行通信, DataSetCommand 对象与 OLE DB 提供程序通信 ( 或有时直接与数据库管理系统提供的 API 通信 ) 可编程能力使用 Connection 对象使用 XML 的严格类型化
传输说明数据源和基 础数据结构的命令 编程特性 数据是自描述 的, 因为代码项的名称与 在层或组件之间共享非连接数据穿越防火墙传 使用 COM 封送处理传输非连接的记录集 此方法仅支持 COM 标准定义的那些数据类型 需要类型转换, 会占用系统资源 有问题, 因为防火墙 代码所解决的 现实世界 问题相对应 基础数据结构 ( 如表 行 ) 不显示, 因而使代码更容易读取和写入 用 XML 文件传输数据集 XML 格式对数据类型没有限制, 也不要求进行类型转换 支持, 因为 ADO.NET 的 输数据 通常被配置为阻止系 DataSet 对象使用基于 可伸缩性 统级请求, 如 COM 封送处理 持续时间很长的数据库锁和活动数据库连接竞争有限的数据库资源 HTML 的 XML, 可穿越防火墙 对数据库数据的非连接访问无需长时间保留数据库锁或活动数据库连接, 因此减轻了对有限的数据库
资源的竞争 一个数据提供的程序包含四个主要对象 : Connection 对象 : 用于连接数据源. Command 对象 : 对数据源执行命令. DataReader 对象 : 在只读和只进的连接模式下从数据源读取数据. DataAdataper 对象 : 从数据源读取数据并且使用读取的数据填充数据集 DataSet 对象. 10.5 数据库操作 数据库操作的主要是执行命令 ( 如插入, 更新或删除记录 ) 和读取数据. 10.5.1 连接要访问数据库, 首先必须与数据库建立连接 ado.net 提供的 Connection 对象, 用于建立与特定数据库的连接. 例如 : 建立 sql server 服务器上 xsgl 数据库建立连接的代码如下 : string cnstr= Password=sa;Persist Security Info=True; User ID=sa; + Initial Catalog=xsgl;Data Source=B402 ;// 服务器名称. SqlConnection cn=new SqlConnection( ); cn. ConnectionString=cnStr; cn.open(); 注意 :ConnectionString 属性是 Connection 对象最重要的一个属性, 他用来指定与数据库建立连接时使用的连接串, 连接串包含有源数据库的名称和建立初始连接所需的其他参数, 例如用户名和密码这些信息.
连接串的基本格式是包括一系列由分号分隔的关键字 / 值对. 等号 (=) 连接各个关键字以及其值. 关键字不区分大小写下面介绍一种获得数据库连接串的简单方法 : (1) 首先创建一个文本文件, 将其扩展名改为 udl ; (2) 双击该文件图标, 打开如图所示的数据库连接对话框
(3) 在提供程序里选择某个提供者, 单击下一步按扭 (4) 选项卡中输入数据库名称, 用户名, 密码等信息, 单击测试连接, 看是否成功 (5) 如果测试成功, 关闭该对话框, 使用记事本再次打开该文件, 其中包含有连接串的信息 注意 : 由于 SqlConnection 对象是专门针对 SQLServer 数据库的, 他的连接串中步允许指定 Provider 属性, 因此, 对于通过上述方法获得的连接串, 需要去掉 Provider=SQLOLEDB.1, 这才是正确的连接串, 对于其他的数据提供程序 Connection 对象, 比如 : OleDbConnection 对象, 则不存在这个问题 在设置了正确的连接串以后, 通过 Connection 对象的 Open()
方法即可打开连接, 打开连接后, 就可以对数据库使用各种命令, 例如进行查询, 插入, 删除, 或更新数据的操作 完成操作后, 需要使用 Connection 对象的 Close() 方法关闭连接 关闭连接是必要的, 因为大多数数据源只支持有限数目的打开的连接, 并且打开的连接占用宝贵的系统资源 还可以直接通过 Connection 类的构造函数来指定连接串, 例如 : 下面的代码与上面的代码具有完全相同的效果 string cnstr= Password=sa;Persist Security Info=True; User ID=sa; + Initial Catalog=xsgl;Data Source=cz ;// 服务器名称. SqlConnection cn=new SqlConnection(cnStr); cn.open(); 10.5.2 命令 ( 还没使用数据集 ) ADO.NET 提供两种使用数据的基本方式 : (1) 使用数据集 (2) 直接对数据库进行操作在数据集模型中, 创建要使用的记录放在内存的存储区中, 通过使用数据适配器加载该存储区, 操作数据, 然后可以选择使用数据适配器将更改写回数据库. 还可以直接对数据库进行处理. 在此模型中, 使用 SQL 语句和存储过程的名称配置数据命令对象 Command, 然后执行命令. 如果该命令返回一个结果集, 则可以使用数据库读取器对象获取某些数据.
在某些情况下不能使用数据集. 例如 : 如果想要创建诸如表之类的数据库元素, 则必须使用命令对象. 命令对象包含对可直接执行的 SQL 语句或存储过程的引用. 命令对象是 SqlCommand 类以及其他类似类的实例, SqlCommand 类进行优化以便用于 SQL Server7.0 或更高版本. 使用命令对象有两个步骤, 首先是构造命令对象, 然后是执行命令. 1 构造命令对象在构造命令对象过程中需要指定该命令对象使用的连接, 命令文本和命令类型等信息 如下所示 : string cnstr= Password=sa;Persist Security Info=True; User ID=sa; + Initial Catalog=xsgl;Data Source=cz ; SqlConnection cn=new Connection(cnStr ); //cn 连接对象 cn.open(); SqlCommand cmd=new SqlCommand(); //cmd 命令对象 cmd.connection=cn; cmd. CommandText= SELECT * FROM STU ; 该段代码要执行的命令是从 stu 学生表中选择所有行的数据. Command 对象的重要属性. CommandText 获取或设置要对数据源执行的 SQL 语句或存储 过程. CommandTimeout 获取或设置在终止执行命令的尝试并生成错误
的等待时间. CommandType 获取或设置一个值, 该值指示如何解释 CommandText 属性. Connection 获取或设置该命令对象使用的连接 (connectiong) 对象请注意 : 命令对象的 CommandText 属性既可以是 SQL 语句, 也可能是存储过程名, 那么这里就有一个问题, 命令对象如何如何区分给 CommandText 属性赋的值 ( 类型当然是字符串 ) 是 SQL 语句, 还是存储过程名呢? 在默认的情况下. CommandText 属性的值被理解为 SQL 语句, 当然也可以通过设置 CommandType 的值来指示如何表示 CommandText 属性. 我们是通过 CommandType 的枚举来表示. 例如 : storedprocedure 指示 CommandText 属性的值为存储 过程名称. Text 指示 CommandText 属性的值为 SQL 命令 ( 默认 ) 也可以直接通过 Command 类的构造函数来指定命令对象所使用的连接对象和命令文本比如对上面的代码做一下修改. string cnstr= Password=sa;Persist Security Info=True; User ID=sa; + Initial Catalog=xsgl;Data Source=cz ; SqlConnection cn=new SqlConnection(cnStr ); cn.open();
SqlCommand cmd=new SqlCommand( SELECT * FROM STU,cn); 2 执行命令 命令对象构造完成以后, 就可以执行命令对数据库进行操作了. 命令对象所提供的用于执行命令的方法有很多种, 具体使用那种方法取决于命令的执行结果返回什么样的数据. 下面介绍命令对象的重要方法 : Cancel ExecuteNonQuery 用于试图取消命令的执行 对连接执行的 SQL 语句并返回受影响的行 数. ExecuteReader 执行查询并将查询查询结果返回到数据读取 器 (DataReader) 中. ExecuteScalar 执行查询, 并返回查询所返回的结果集中第 一行的第一列. ExecuteXmlReader 执行查询, 并将查询结果返回到一个 XmlReader 对象中. 下面举几个例子, 对这几种方法的使用 : ExecuteNonQuery() 方法一般用于执行 UPDATE,INSERT,DELETE 等非查询语句. string cnstr= Password=sa;Persist Security Info=True; User
ID=sa; + Initial Catalog=xsgl;Data Source=cz ; SqlConnection cn=new Connection(cnStr ); cn.open(); string sqlstr= update stu set 姓名 = john where 姓名 = bill ; SqlCommand cmd=new SqlCommand(sqlStr,cn); cmd. ExecuteNonQuery(); cn.close(); ExecuteNonQuery() 方法的返回值是一个整数, 代表操作所影响的行数. ExecuteReader() 方法用于执行查询操作, 他返回一个 DataReader 对象, 通过该对象可以可以读取所得到的数据. 下一节将和同学们讨论 DataReader 类的对象. 请看下面的代码 : string cnstr= "Password=sa;Persist Security Info=True; User ID=sa;"+"Initial Catalog=xsgl;Data Source=417-52"; SqlConnection cn=new SqlConnection(cnStr); cn.open(); SqlCommand cmd=new SqlCommand("SELECT * FROM STU",cn); SqlDataReader Dr=cmd. ExecuteReader(); while(dr.read()) String name=dr[" 姓名 "].ToString(); Console.WriteLine(name); Dr.Close(); cn.close(); 这段代码是将 stu 表中读取全部数据, 并将姓名字段 的数据全部输出到控制台上. 在许多情况下 : 需要从 SQL 语句返回一个结果, 例如客户表中记录 的个数, 当前服务器的时间等,ExecuteScalar() 方法就适用于这种情
况 下面的代码就是读取数据库中表 Customers 的记录的个数, 并把它输出到控制台上 using System; using System.Data.SqlClient; using System.Data; namespace ConsoleApplication1 /// <summary> /// Class1 的摘要说明 /// </summary> class Class1 /// <summary> /// 应用程序的主入口点 /// </summary> [STAThread] static void Main(string[] args) string cnstr="password=sa;persist Security Info=True;User ID=sa;"+"Initial Catalog=Northwind;Data Source=772F1959E31B442"; SqlConnection cn=new SqlConnection(cnStr);
cn.open(); string sqlstr="select count(*) from Customers"; SqlCommand cmd=new SqlCommand(sqlStr,cn); object count=cmd.executescalar(); //ExecuteScalar() 方法返回值类型是 object, 根据具体需要可以将他转化为合适的类型 Console.WriteLine(count.ToString()); cn.close(); 运行结果 : 10.5.3 数据读取器 DataReader 是从一个数据源中选择某些数据最简单的方法. DataReader 类没有构造函数, 所以不能直接实例化他, 需要从 Command 对象中返回一个 DataReader 实例, 具体是通过他们的 ExcuteReader 方法, 下面的代码是将 stu 表中读取数据并将姓名, 学号的所有数据输出到文本框中.
请看下面的代码 : string cnstr= "Password=sa;Persist Security Info=True; User ID=sa;"+"Initial Catalog=xsgl;Data Source=FCFB3F021B7B4E7";// 请根据 Sql Server 的配置, 指定连接串中的用户名和密码 SqlConnection cn=new SqlConnection(cnStr ); cn.open(); SqlCommand cmd=new SqlCommand("SELECT * FROM stu",cn); SqlDataReader dr=cmd.executereader();// 通过该方法返回 SqlDataReader 一个实例 dr while(dr.read()) textbox1.text+=dr[0].tostring()+"\t"+dr[1].tostring()+"\t"+dr[2 ].ToString()+"\t";
dr.close(); cn.close(); 说明 :DataReader 是一个只向前的连接光标, 即只能沿着一个方向遍历记录, 在此过程中数据库一直保持打开状态, 否则不能通过 DataReader 读取数据. 在完成数据读取后, 需要调用 Close() 方法关闭 DataReader. 如果创建 DataReader 对象时, 使用的是 ExecuteReader() 方法的另一个重载, 就会自动关闭 DataReader 的底层连接, 不需要显示的调用 Connection 对象的 Close() 方法关闭他. 代码如下请看 : SqlDataReadermyDataReader=cmd.ExecuteReader(CommandBehavior. CloseConnection); DataReader 的 Read() 方法用于读取数据, 每执行一次该语句, DataReader 就向前读取一行数据, 就遇到末尾, 就返回末尾 false, 否则返回 true. DataReader 类有一个索引符, 可以使用常见的数组语法访问任何字段, 使用这种方法既可以通过指定数据列的名称, 也可以通过指定数据列的编号来访问特定列的值, 第一列的编号是 0, 第二列的值是 1 依此类推 例如 : Object value1=mydatareader[ CategoryId ]; Object value1=mydatareader[0]; 说明 : 假如 CategoryId 列是第一列, 则上面两条语句的功能是完全相同的, 只是后者的速度更快一些
除了通过索引符访问数据外,DataReader 类还有一组类型安全的访问方法可以用于读取指定列的值 这里介绍一下 : 这些方法都是以 Get 开头的, 并且他们的名称具有自我解释性 例如 :GetInt32(),GetString() 等 这些方法都带有一个整形的参数, 用于指定要读取列的编号 int id= mydatareader. GetInt32(0); string name= mydatareader. GetString(1); 10.6 数据集 (DataSet) ADO.net 相对于 ADO 最显著的变化就是数据集了,DataSet 是一个数据脱机容器, 可以形象地描述为内存中地数据库, 数据集的结构类似于关系数据库的结构, 他公开表, 行和列的分层模型. 另外他还包含约束和关系对象等. 10.6.1 数据集的介绍 数据集是有一组数据表组成的, 数据表类似于数据库中的表, 每个数据表都有一些数据列和数据行. 除了定义数据外, 还可以在数据集中定义表之间的连接, 来表示表之间的关系, 通常为主从关系. 例如一张订单表和订单明细表之间就是主从关系, 订单表中的一条记录可能关联到订单明细表中的多条记录, 下面是数据集的类层次结构. System. Data DataSet DataTable DataColumn Constraint
其中 DataSet 代表数据集,DataTable 代表的是数据表,DataColumn 代表数据列,DataRow 代表行,Constraint 代表的是约束,DataRelation 代表的是表之间的主从关系. 数据集的基本组成部分具体说明如下 : DataSet 类包含数据表的 Tables 集合和 DataRelation 对象的 relations 集合. DataTable 类包含数据行 Rows 集合, 数据列的 Columns 的集合和数据关系的集合 DataRow 类包含 RowState 属性, 该属性的值指示自数据表首次从数据库加载后, 行是否以更改以及如何更改的. DataState 属性可能值包括 Delete,Modified,New, 和 Unchanged. 10.6.2 填充数据集将外部数据源数据加载到数据集中的过程称为填充数据集, 有两种方式 : 1 使用数据适配器 2 把 XML 读入数据集
1 使用数据适配器 (DataAdapter) 不能通过前面我们介绍的 Command 对象填充数据集, 将数据从数据库加载到数据集的过程需要使用到数据适配器 那么数据适配器是 ADO.Net 数据提供程序的一个部分 数据适配器就好像一个桥梁, 用于在数据源和数据集之间交换数据 数据集数据适配器数据源 使用数据适配器, 就可以读取, 添加, 更新和删除数据源中的记录, 为指定每种操作的进行方式, 适配器支持四个属性 SelectCommand: 指定某个命令对象以便从数据存储区检索行 InsertCommand: 指定某命令对象以便向数据存储区插入行 UpdateCommand: 指定某命令对象以便修改数据存储区中的行 DeleteCommand: 指定某命令对象以便从数据存储区删除行. 请看下面的代码, 他的功能是将 stu 中的 stuname 字段全部输出到控制台. using System; using System.Data.SqlClient; using System.Data;
namespace ConsoleApplication2 class Class1 static void Main(string[] args) string cnstr = "Password=sa;Persist Security Info=True;User ID=sa;" + "Initial Catalog=xsgl;Data Source=cz"; SqlConnection cn = new SqlConnection(cnStr); cn.open(); string sqlstr = "SELECT * FROM stu"; SqlCommand cmd = new SqlCommand(sqlStr, cn); SqlDataAdapter mydataadapter = new SqlDataAdapter(); mydataadapter.selectcommand = cmd; DataSet ds = new DataSet(); mydataadapter.fill(ds); //Fill 方法是用于把数据源 stu 表中的行添加到数据集中. foreach(datarow dr in ds.tables[0].rows) // dr 是循环变量, ds.tables[0].rows 表明获取数据集 ds 对象中要查询的表的行的集合 Console.WriteLine(dr["stuName"].ToString());
cn.close(); Console.ReadLine(); 注意 : 将 Categories 表的架构和数据添加到数据集 ds 中, 并创建一个名为 Table ( 注意不是原始表名 stu ) 的表 (DataTable). 可以通过以下语句获得对表的引用 : DataTable dt=ds.table[0]; 或者 : DataTable dt=ds.table[ Table ]; 还可以使用 Fill() 方法的另一个重载来指定 DataSet 中要填充的表的名称 例如 : mydataadapter.fill(ds, MyTable ); 如果指定的表不存在, 则在 DataSet 中以指定名称创建一个新表 Fill() 方法使用 select 语句从数据源中检索数据 与 select 命令关联的 Connection 对象必须有效, 但不需要将其打开 如果调用 Fill 之前 Connection 对象处于关闭的状态, 则 Fill() 方法会自动将其打开以检索数据, 执行完成之后再将其关闭, 如果在调用 Fill 之前连接已经打开, 他将保持打开状态 也可以通过 DataAdapter 类的构造函数来指定所用的 Connection 对象和 select 语句, 下面的代码的功能与上面的代码的功能完全相同
using System.Data.SqlClient; using System.Data; namespace ConsoleApplication2 class Class1 static void Main(string[] args) string cnstr = "Password=sa;Persist Security Info=True;User ID=sa;" + "Initial Catalog=xsgl;Data Source=cz"; SqlConnection cn = new SqlConnection(cnStr); cn.open(); string sqlstr = "SELECT * FROM stu"; SqlDataAdapter mydataadapter=new SqlDataAdapter(sqlStr,cn); DataSet ds = new DataSet(); mydataadapter.fill(ds); //Fill 方法是用于把数据源 stu 表中的行添加到数据集中. foreach(datarow dr in ds.tables[0].rows) // dr 是循环变量, ds.tables[0].rows 表明获取数据集 ds 对象中要查询的表的行的集合 Console.WriteLine(dr["stuName"].ToString());
cn.close(); Console.ReadLine(); Fill() 方法可以将表的架构和数据同时填充到数据集中, 如果只想填 充表的结构, 而不填充数据可以使用 FillSchema() 方法 数据集的更新 通过数据集更新数据源是一个包含两个步骤的过程 第一步 : 使用新信息 ( 新记录, 已更改的记录或已删除的记录 ) 更新数据集 第二步 : 将更改从数据集发送到初始数据源 也就是说, 更新数据集的过程不会同时将更改直接写入基础数据源, 因为数据集和数据源是断开连接的, 所以必须显示执行这一步 为了完成这一步, 通常会调用曾用来填充数据集的同一个数据适配器的 Update() 方法 当数据填充了数据之后, 在将其发送回数据源或另一个进程或应用 程序之前, 通常会执行某种类型的数据操作, 由于数据集中的每个记 录都由一个 DataRow 对象来表示, 所以对数据集的更改通过更新和
删除个别行来完成, 另外, 通过将新的 DataRow 对象添加到 DataTable 对象的 Row 集合中, 可以将新记录插入数据集 1 插入行为了在数据集中添加新的记录, 必须创建一个数据行并将其添加到数据表的 Rows 集合中 下面的过程详细给大家说明如何将新行插入到数据集的 DataTable 对象中 分三步 : (1) 调用数据表的 NewRow 方法来新建一个空记录 该记录将从数据表的 DataColumnCollection 继承其列结构 DataRow mydatarow=ds.tables[0].newrow(); (2) 更新该行, 就像他是现有记录一样 MyDataRow[ CategoryId ]= 99 ; MyDataRow[ CategoryName ]= drink ; 或者 MyDataRow[0]= 99 ; MyDataRow[1]= drink ; (3) 通过调用 Rows 集合的 Add 方法将新记录添加到表中 ds.tables[0].rows.add(mydatarow); 2 更新现有行为了编辑数据集中的现有的记录, 需要访问特定行中特定列的数据 下面的示例显示如何使用表, 行和列集合索引访问数据值, 以更新数据集对象 ds 中第一个表第五个记录前两列中的数据
ds.tables[0].row[4][0]= 88 ; ds.tables[0].row[4][1]= meat ; 3 删除行要从数据表中删除记录, 可以调用数据行的 Delete 方法 该方法并不实际移除记录, 而只是将记录标记为删除 下面的示例显示如何调用 Delete() 方法将数据集 ds 的第一个表的第二行标记为已删除 : ds.tables[0],row[1],delete(); 上面的插入行, 更新或删除行操作仅仅是数据集更新两步操作中的第一步, 即更新数据集, 此时, 数据集中的数据相对于他初次加载时已经有了变化, 但在数据源中的数据并没有发生变化, 要用已修改的数据集更新数据源, 还需要调用数据适配器 Update() 方法 在讨论 Update() 方法的使用之前, 需要阐明的是用自己修改的数据集更新数据源的本质是一个批处理更新 对数据集进行插入, 更新, 或删除等操作时, 往往涉及对多个行的修改. 例如, 插入一个新行, 更改了第二行的数据, 并且删除了第四行和第五行, 这种操作就涉及了对四个行的修改. 在更新数据源的时候, 会对目标数据集的行从头到尾的循环, 只要发现被更改的行, 就会发出适当的更新命令 (INSERT,DELETE 或 UPDATE). 批处理更新. 因此在调用数据适配器的 UPDATE() 方法前, 要确保为数据适配器的 InsertCommand,DeleteCommand 属性和 UpdateCommand 属性指
定了正确的命令对象, 对于更新和删除现有行, 将分别使用到为 UpdateCommand 属性和 DeleteCommand 属性指定的命令对象. 但是自定义 InsertCommand,DeleteCommand 属性和 UpdateCommand 属性通常比较繁锁.NET 提供了命令生成器可以通过数据适配器的 SelectCommand 属性自动设置 InsertCommand,DeleteCommand 属性和 UpdateCommand 属性. 命令生成器是一个特定于数据提供程序的类, 他工作在数据适配器对象之上, 并且自动设置 InsertCommand,DeleteCommand 属性和 UpdateCommand 属性. 命令生成器首先运行 InsertCommand, 收集有关所涉及表和列的足够信息, 然后会创建更新命令. 实际的命令创建在命令生成器类构造函数中进行. 代码如下 : SqlCommandBuilder cb=new SqlCommandBuilder(myDataAdapter); 使用命令生成器, 必须满足两个要求. 首先, 必须为 SelectCommand 属性设置一个有效的命令对象,SelectCommand 必须指向一个有效的查询语句. 用语批处理更新的有效查询是返回主键列的查询. 另外, 该查询不包括计算的列, 也不得引用多个表. 如果希望查看生成器代码, 则可以调用命令生成器的 GetInsertCommand,GetUpDateCommand 和 GetDeleteCommand 方法. 例如 : 下面的代码就是使用数据库的示例. 数据集的非查询操作 using System;
using System.Data; using System.Data.SqlClient; namespace ConsoleApplication3 /// <summary> /// Class1 的摘要说明 /// </summary> class Class1 /// <summary> /// 应用程序的主入口点 /// </summary> [STAThread] static void Main(string[] args) string cnstr = "Password=sa;Persist Security Info=True;User ID=sa;" + "Initial Catalog=xsgl;Data Source=FCFB3F021B7B4E7"; SqlConnection cn = new SqlConnection(cnStr); cn.open(); string sqlstr = "SELECT * FROM stu";
SqlCommand cmd = new SqlCommand(sqlStr, cn); SqlDataAdapter mydataadapter = new SqlDataAdapter(); mydataadapter.selectcommand = cmd; // 自动生成用于数据集更新的命令 SqlCommandBuilder custcb = new SqlCommandBuilder(myDataAdapter); /* 命令生成器, 工作在适配器对象之上, 并自动设置, 插入, 删除, 更新属性, 命令生成器首先运行 selectcommand, 然后收集相关需要操作的表, 然后就会创建更新命令, 注意 : 要执行批处理更新是返回主键列的查询 */ // 填充数据集 DataSet ds = new DataSet(); mydataadapter.fill(ds); // 修改数据集 DataRow mydatarow = ds.tables[0].newrow();// 调用数据表的 NewRow 方法创建一个空记录 mydatarow["id"] = "5"; mydatarow["name"] = " 王嫱 "; mydatarow["age"] = "35"; ds.tables[0].rows.add(mydatarow);// 插入一行新的记录 ds.tables[0].rows[1][0] = "10"; ds.tables[0].rows[1][1] = "piter";
ds.tables[0].rows[1][2] = "100"; ds.tables[0].rows[2].delete(); // 用更改后的数据集更新数据库 mydataadapter.update(ds); cn.close(); 注意 : 进行更新是数据只能以每个表为基础进行提交, 如果调用 Update() 方法是没有指定表名, 则使用 Table 这个默认的表名, 如果表名不存在, 则会产生异常. 这里大家可以使用 UpDate() 方法的另一个重载, 来明确指定要更新的表的名称. 例如 :mydataadapter.update(ds, mytable ); Datagrid 控件在上一节中, 我们介绍了如何将数据从数据源填充到数据集对象中, 并且给出了显示数据的编程方法. 例如 : 通过一个循环语句将数据表中某列的所有数据显示在控制台上.
在 Windows 窗体编程中. 显示数据最好的方式是通过 Datagrid 控件, 使用他只需简单几行代就能够一非常友好的形式全面的把数据展示给用户. Datagrid 控件控见是一个全新的控件, 专门为,NET 编写, 这个控件功能非常强大, 不仅可以用于显示数据还可以通过他编辑数据. 另外, Datagrid 控件还允许用户非常自由灵活的设置他的外观样式. 一, 显示数据. Datagrid 控件的常见用途是显示数据集中的单个数据表, 但是, 该控见也可以用来显示多个不相关的表, 或多个相关的表 数据的显示形式会自动根据数据源进行调整. 单个表 : 该表的数据显示在一个网格中. 多个不相关的表 : 网格可以显示一个树视图, 用户可以通过浏览树视图找到想要显示的表. 多个相关的表 : 指定让网格显示父表. 父表中记录允许用户定位到相关的子行. 1 显示单个表首先我们通过一个简单的示例来看一哈 Datagrid 控件的风采 在窗体上放置一个按钮控件和一个 Datagrid 控件 Datagrid 控件示单个表
private void button1_click(object sender, System.EventArgs e) string cnstr = "Password=sa;Persist Security Info=True;User ID=sa;" + "Initial Catalog=xsgl;Data Source=T03"; SqlConnection cn = new SqlConnection(cnStr); string sqlstr = "SELECT * FROM stu"; SqlDataAdapter mydataadapter = new SqlDataAdapter(sqlStr, cn); DataSet ds = new DataSet(); mydataadapter.fill(ds,"stu"); // 将数据集绑定到 DataGrid 控件上 datagrid1.setdatabinding(ds,"stu"); /*SetDataBinding() 方法有两个参数, 第一个参数用于设置数据源, 有效的数据源可以是 DataSet,DataTable, 一维数组等, 第二个参数用于设置数据成员, 既 DataMember 属性, 如果不需要显示的传递一个数据成员就要传递一个空的字符串 (" ") */
显示多个不相关的表 使用 SetDataBinding() 方法时不指定 DataMember 属性, 也就是说将第二个参数设置为空字符串, 则网格中会显示一个树视图, 罗列出该数据记集中的所有表, 用户可以通过在树视图中单击表名显示相应表的数据 private void button1_click(object sender, System.EventArgs e) string cnstr = "Password=qq;Persist Security Info=True;User ID=sa;" + "Initial Catalog=Northwind;Data Source=CHQHAO"; SqlConnection cn = new SqlConnection(cnStr); string sqlstr = "SELECT * FROM Customers"; SqlDataAdapter mydataadapter = new SqlDataAdapter(sqlStr, cn); DataSet ds = new DataSet(); mydataadapter.fill(ds,"customers"); sqlstr = "SELECT * FROM Orders"; mydataadapter = new SqlDataAdapter(sqlStr, cn); mydataadapter.fill(ds,"orders"); // 将数据集绑定到 DataGrid 控件上 datagrid1.setdatabinding(ds,"");
DataGrid 控见保存更改操作 : 首先声明成员变量 private SqlDataAdapter mydataadapter; private DataSet ds; private void button1_click(object sender, System.EventArgs e) string cnstr = "Password=qq;Persist Security Info=True;User ID=sa;" + "Initial Catalog=Northwind;Data Source=CHQHAO"; SqlConnection cn = new SqlConnection(cnStr); string sqlstr = "SELECT * FROM Employees"; mydataadapter = new SqlDataAdapter(sqlStr, cn); SqlCommandBuilder cb = new SqlCommandBuilder(myDataAdapter); ds = new DataSet();
mydataadapter.fill(ds, "Employees"); // 将数据集中的 Customers 表绑定到 DataGrid 控件上 datagrid1.setdatabinding(ds,"employees"); private void button2_click(object sender, System.EventArgs e) mydataadapter.update(ds, "Employees"); MessageBox.Show(" 保存成功!");