数据库与ADO.Net


数据库与ADO.Net

8.1   数据库基本概念

数据库提供了一种将信息集合在一起的方法。数据库应用系统主要由三部分组成:数据库管理系统(DBMS),是针对所有应用的,例如ACCESS。数据库本身,按一定的结构组织在一起的相关数据。数据库应用程序,它是针对某一具体数据库应用编制的程序,用来获取,显示和更新数据库存储的数据,方便用户使用。这里讲的就是如何编写数据库应用程序。

常见的数据库管理系统有:FoxPro,Access,Oracle,SQLserver,Sybase等。数据库管理系统主要基于3种数据模型:层次模型、网状模型、关系模型。目前应用最广泛的是基于关系模型的关系数据库,以上所列数据库管理系统都是关系数据库。一个关系数据库由若干表组成,表是一组相关的数据按行排列,例如一个通讯录就是这样一个表,表中的每一列叫做一个字段,例如通讯录中的姓名,地址,电话都是字段。字段包括字段名及具体的数据,每个字段都有相应的描述信息,例如数据类型,数据宽度等。表中每一行称为一条记录。

数据库分为本地数据库和远程数据库,本地数据库一般不通过网络访问,数据库和数据库应用程序在同一计算机中,本地数据库也称为单层数据库。远程数据库通常位于远程计算机上,用户通过网络来访问远程数据库中的数据。远程数据库可以采用两层,三层或四层结构,两层结构一般采用C/S模式,即客户端和服务器模式。三层模式一般采用B/S模式,用户用浏览器访问WEB服务器,WEB服务器用CGI、ASP、PHP、JSP等技术访问数据库服务器,生成动态网页返回给用户。四层模式是将应用逻辑从Web服务器分离,在WEB服务器和数据库服务器中间增加一个应用服务器。利用ADO.Net技术可以开发数据库应用程序。设计单层或多层数据库应用程序使用ADO.Net的方法基本一致,因此,这里讨论的内容也适用于后边的Web应用程序设计。

8.2   设计连接和不连接方式数据库应用程序的基本步骤

设计一个数据库应用程序可以采用连接方式和不连接方式。所谓连接方式,是数据库应用程序运行期间,一直保持和数据库连接,数据库应用程序通过SQL语句直接对数据库操作,例如,查找记录、删除记录、修改记录。所谓不连接方式,是数据库应用程序把数据库中感兴趣的数据读入,建立一个副本,数据库应用程序对副本进行操作,必要时将修改的副本存回数据库。设计一个不连接方式数据库应用程序一般包括以下基本步骤:

(1)   创建数据库,包括若干个表,在表中添入数据(若干记录)。

(2)   使用SqlConnection或OleDbConnection类建立和数据库的连接。

(3)   使用OleDbAdapter或SqlDataAdapter类从数据库指定表中取出感兴趣的记录。

(4)   将从数据库指定表中取出的感兴趣记录做成一个新表,填充到DataSet类对象中,可填充多个表,并可在DataSet类对象中指定表和表的关系。DataSet对象建立在内存中,可以认为是数据库在内存中的一个子集。取出所有感兴趣的数据后,断开和数据库的联接。

(5)   用支持数据绑定的控件(例如DataGraid控件)显示DataSet类对象中的数据,供用户浏览、查询、修改。

(6)   及时更新DataSet中的内容,并把修改的数据存回源数据库。

设计一个连接方式数据库应用程序一般包括以下基本步骤:

(1)   建立数据库,包括若干个表,在表中添入数据(若干记录)。

(2)   使用SqlConnection或OleDbConnection类建立和数据库的连接。

(3)   使用OleDbCommand或SQLCommand类对象用SQL语句来访问数据库中的数据,直接在数据库的表中查询指定记录、增加记录、删除记录,修改记录中的数据。

以下章节将按以上步骤说明连接方式和不连接方式数据库应用程序的具体设计方法。

8.3   用ACCESS创建数据库

本例创建一个学生信息管理系统,包括两个表,表1记录学生的基本情况,包括以下字段:学号、姓名、性别。表2记录学生的学习成绩,包括以下字段:记录编号、课程名称、分数、拥有该课程成绩学生的学号。由于要记录全校所有学生的成绩,把学习成绩表字段定义为:学号、语文成绩、数学成绩、物理成绩等字段是不合适的,这样做,增加一门课程,就要增加一个字段,字段要动态增加,而且,不同专业所开设的课程也不相同,某些课程字段只是个别专业使用,这显然不合理。用Access2000程序创建数据库具体步骤如下:

(1)运行microsoft Access2000程序,出现"microsoft Access"对话框如下图,选择"空Access数据库(B)",单击"确定"按钮,打开标题为"文件新建数据库"对话框。

(2)在标题为"文件新建数据库"对话框中,添入数据库文件名:StudentI,选择保存位置和保存类型如下图。单击"创建(C)"按钮,出现"StudentI:数据库"对话框。

(3)在"StudentI:数据库"对话框中,双击"使用设计器创建数据表",出现"表1:表"对话框。在表中可以创建数据库表的字段。

(4)在"表1:表"对话框中,创建字段StudentNum,数字类型的整形,必填字段,默认值为0,标题为"学生编号"。字段StudentName,文本,字段大小8,必填字段,默认值为空,标题为"姓名"。字段StudentSex,文本,字段大小2,标题为"性别"。右击字段StudentNum,在弹出快捷菜单中单击"主键"菜单项,设置字段StudentNum为主关键字。如下图。

(5)单击Access程序菜单"文件"|"保存"菜单项,出现"另存为"对话框,在对话框中的"表名称(N)"编辑框中输入表名:Student,单击"确定"按钮。关闭"表1:表"对话框。

(6)在"StudentI:数据库"对话框左侧,选择标题为"表"的按钮,在右测可以看到Student表,双击Student表,出现"Student:表"对话框。

(7)在"Student:表"对话框中为各个字段输入数据:例如:1,张三,男;2,李四,女;3,王五,男;4,鲁豫,女。然后存盘。如下图。

(8)同样方法建立表Score,记录所有学生学习成绩。包括记录编号字段ScoreID,自动编号,主关键字;课程名称字段ClassName,文本,字段大小26,必填字段,默认值为空;分数字段Score,字节类型,必填字段,默认值为0;拥有该课程成绩学生的学号字段StudentNum,数字类型的整形,必填字段,默认值为空。增加若干数据。

(9)   退出microsoft Access2000程序。

8.4   结构化查询语言SQL

数据库应用程序通过SQL(Structed Query Language,结构化查询语言)来访问数据库中的数据,使用SQL语句可以在数据库的表中查询指定记录、增加记录、删除记录,修改记录中的数据。几乎所有的数据库都支持SQL语言,编写数据库应用程序必须学习SQL语言。这里只介绍最基本的SQL语句,读者还应更深入的学习SQL语言。

8.4.1   Select语句

Select语句是最常用的SQL语句,可以从数据库的表中获得满足一些条件的记录集。常见的Select语句如下:

l select * from student

从student表中选择所有字段的所有记录。

l select StudentNum,StudentName from student

从Student表中选择字段StudentNum和字段StudentName的所有记录

l select * from score where StudentNum=1

从score表中查找学号StudentNum=1同学的所有课程的成绩。

8.4.2   Insert语句

用于向数据库表中插入一个新记录。例如,向表student中插入一个新纪录的语句如下:

Insert student(StudentNum,StudentName,StudentSex)Value(5,"田七","男")

8.4.3   Delete语句

用于删除数据库表中的一个记录。例如,删除student表中学号为1的学生,语句如下:

Delete From student where StudentNum=1

8.4.4   Update语句

数据库的Student表中学号为1的学生名字修改为"陈七":

Update Student Set StudentName="陈七" Where StudentNum=1。

8.5   连接数据库(SqlConnection和OleDbConnection类)

如果连接微软的Sql Server7.0及以后版本数据库,使用SqlConnection类建立连接效率较高。而连接其它支持ODBC的数据库,必须使用OleDbConnection类。使用SqlConnection类必须引用如下命名空间:

Using System.Data;

using System.Data.SqlClient;

使用OleDbConnection类必须引用如下命名空间:

Using System.Data;

using System.Data.OleDb;

使用SqlConnection类建立连接的例子如下:

string txtConn="DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;";

SqlConnection conn=new SqlConnection(txtConn);//建立连接

其中DATABASE为数据库名称,这里为Northwind,必须安装微软Sql Server数据库系统,并安装自带的数据库例子Northwind,才能使用。UID为用户名,PWD为密码,Northwind数据库安装后的用户名为sa,密码为空。SERVER为所使用的数据库服务器,这里数据库服务器和数据库应用程序在同一台计算机中,因此为localhost,中文意义是本地主机。

使用OleDbConnection类建立连接的例子如下:

string txtConn=//将作为OleDbConnection类对象conn的属性ConnectionString的值

"Provider=Microsoft.Jet.OLEDB.4.0;DataSource=D:\\VC#\\studentI.mdb";

OleDbConnection conn=new OleDbConnection(txtConn);//建立数据库连接

Provider为所使用的数据库驱动程序,DataSource为数据库的位置。也可以使用Visual Studio.Net建立连接,见例子8_10B。方法Open()和Close(),打开和关闭数据库连接。

8.6   OleDbCommand和SQLCommand类

建立连接后,ADO.Net可以通过OleDbCommand或SQLCommand类对象用SQL语句来访问数据库中的数据,在数据库的表中查询指定记录、增加记录、删除记录、修改记录中的数据。例如建立一个OleDbCommand和SQLCommand类查询对象方法如下:

string sCommand="SELECT * FROM student";

如果使用OleDbConnection类建立的连接,使用OleDbCommand类对象。

OleDbCommand Command1=new OleDbCommand(sCommand,conn);

如果使用SqlConnection类建立的连接,使用SQLCommand类对象。

SQLCommand Command1=new SQLCommand(sCommand,conn);//conn为建立的数据库连接

可以使用方法ExecuteNonQuery、ExecuteReader执行OleDbCommand和SQLCommand类中的SQL语句,具体使用方法见例子e8_6和例子e8_14A。

例子e8_6:采用连接方式的数据库应用程序例子。有时,数据库应用程序使用连接方式可能更方便一些,例如,用户的注册信息应该立即存到数据库表中。下边的例子模拟用户注册,首先请用户输入个人信息,单击注册按钮,用SQL语句把数据存到StudentI数据库的Student表中。具体步骤如下:

(1)新建项目。放三个Label控件到窗体,属性Text分别修改为:学号、姓名、性别。

(2)放三个TextBox控件到窗体,属性Text都修改为空字符串。属性Name为textBox1的TextBox控件输入学号,textBox2输入学生姓名,textBox3输入学生性别。

(3)在Form1.cs文件头部引入命名空间using System.Data.OleDb;

(4)为Form1类增加变量:OleDbConnection conn;OleDbCommand da;

(5)在窗体中增加一个标题为"增加记录"的按钮,界面如下图。按钮单击事件处理函数如下:

private void button1_Click(object sender, System.EventArgs e)

{   if(textBox1.Text==""||textBox2.Text==""||textBox3.Text=="")

{   MessageBox.Show("所有项都必须填写!");

return;

}//为保证程序运行,数据库文件studentI.mdb必须在文件夹D:\\vc#中

string txt1=

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\vc#\\studentI.mdb";

string txt2=

"Insert Into Student(StudentNum,StudentName,StudentSex) Values('";

txt2+=textBox1.Text + "' , '";

txt2+=textBox2.Text + "' , '";

txt2+=textBox3.Text+"')";//最后结果要保证在TextBox中输入的内容被单引号括住

conn=new OleDbConnection(txt1);

conn.Open();//打开数据库连接

da=new OleDbCommand(txt2,conn);

da.ExecuteNonQuery();//执行SQL语句

textBox1.Text="";

textBox2.Text="";

textBox3.Text="";

conn.Close();//关闭数据库连接

}

(6)运行,输入学号,姓名,性别,单击"增加记录"按钮,察看数据库,可以看到增加了一个记录。请读者增加删除一个记录,修改一个记录的功能。

8.7   OleDbAdapter和SqlDataAdapter类

OleDbAdapter或SqlDataAdapter类包括如下属性:SelectCommand、InsertCommand、DeleteCommand、UpdateCommand和TableMappings,可以赋值为相应的SQL语句,实现对数据库中的数据的选择,插入,更新,删除等功能。这两个类隐藏了OleDbCommand或SQLCommand类操作数据库的细节,方便使用。在不连接方式数据库应用程序中,一般使用这两个类的方法Fill()和Update()填充和更新DataSet类对象,具体例子参见以后章节。如果使用OleDbConnection类建立连接,建立OleDbAdapter对象语句如下:

string txtConn=

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\VC#\\studentI.mdb";

OleDbConnection conn=new OleDbConnection(txtConn);//建立数据库连接

string txtCommand="SELECT * FROM student";//要执行的SQL语句

OleDbDataAdapter da=new OleDbDataAdapter(txtCommand,conn);

请读者写出使用SqlConnection类连接微软的Sql Server2000数据库,建立SqlDataAdapter类对象的语句,以得到Northwind数据库表Employees的所有记录数据。

8.8   DataSet类对象

数据集DataSet是从数据库检索的记录的缓存。使用OleDbAdapter或SqlDataAdapter类从数据库指定表中取出感兴趣的记录,将这些感兴趣的记录集合做成一个新表,填充到DataSet类对象中。可在DataSet类对象中填充多个表,并可在DataSet类对象中指定表和表的关系,以及指定对表包含数据的约束信息。DataSet对象被建立在内存中,可以认为是数据库在内存中的一个子数据库。DataSet对象只在获取或更新数据时保持和数据库连接,其它时间都是断开的,使数据库可以自由执行其它任务。尽管数据集是作为从数据库获取的数据的缓存,但数据集与数据库之间没有任何实际关系。

8.8.1   使用DataSet类的必要性

在传统的数据库应用程序中,必须建立与数据库的连接,并在数据库应用程序运行过程中保持连接状态。出于各种原因,该方法在许多数据库应用程序中是不实用的。

l 一般情况下,一个数据库只可以维持少量的并发连接。维持过多并发连接将降低数据库的总体性能,增加数据库应用程序的访问时间。保持四个用户的连接应该可以接受,但同时连接100个用户可能就不行了。同时访问Web数据库的访问者可能非常多,例如大型网上商店,所有访问都保持连接是不现实的。

l 在Web应用程序中,浏览器从服务器请求网页,服务器发送该页后,服务器就不再与浏览器有任何连接,直到下一次请求为止。在这种情况下,维持打开的数据库连接是不可行的,因为没有办法知道在浏览器端数据使用者是否还将对数据库访问。

l 如果数据库应用程序的多个控件需对数据库数据操作,则多个控件都必须和数据库建立连接,或者为这些控件设计一种方式以相互传递数据。这使问题变得复杂。

出于以上这些理由,ADO.Net数据库访问被设计为以不连接的数据模型为基础,应用程序只在获取或更新数据时保持连接,其它时间都是断开的。由于数据库并未被大部分时间空闲的连接占用,所以它可以为更多用户服务。除此以外,ADO.Net允许将DataSet中存储的数据用XML标记语言描述,使异构数据库的数据交换成为可能。这也是采用DataSet的一个重要原因,这方面的论述参见第12章。

8.8.2   使用DataSet类对象

使用OleDbAdapter类填充DataSet对象例子如下:

string txtConn=

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\VC#\\studentI.mdb";

OleDbConnection conn=new OleDbConnection(txtConn);//建立数据库连接对象

string txtCommand="SELECT * FROM student";//SQL语句

OleDbDataAdapter da=new OleDbDataAdapter(txtCommand,conn);

DataSet MyDataSet=new DataSet();//建立DataSet对象MyDataSet

da.Fill(MyDataSet,"MyTable");//将da数据做为表填充到MyDataSet中,表名为MyTable

使用OleDbAdapter类把DataSet类对象中修改的数据存回源数据库的例子如下:

if(MyDataSet.HasChanges())//检查DataSet是否有改动

da.Update(MyDataSet);//更新数据库

下边说明如何在DataSet类对象中修改数据。一般情况下,并不直接使用这些方法修改DataSet类对象中数据,而是采用支持数据绑定的控件(例如DataGraid控件)显示、浏览、查询、修改DataSet类对象中的数据。数据绑定的控件隐藏了具体修改数据的代码。

l 在指定表中添加新记录:

DataRow dr=MyDataSet.Tables["Student"].NewRow();//建立表Student的新记录

dr["StudentNum"]=4;//新记录StudentNum字段的值为4

dr["StudentName"]="鲁豫";//新记录StudentName字段的值为"鲁豫"

dr["StudentSex"]="女";//新记录StudentSex字段的值为"女"

l 修改Student表中第0个记录的"StudentName"字段的值为"田歌"

MyDataSet.Tables["Student"].Rows[0]["StudentName"]="田歌";

l 删除Student表中第0个记录

MyDataSet.Tables["Student"].Rows[0].Delete();

l 恢复数据

if(MyDataSet.HasErros)

MyDataSet.RejectChanges();

8.8.3  为DataSet对象中的表指定主键、建立关系

为DataSet对象中的表指定主键、建立关系,可以保证数据的完整性,例如,主键取值不能重复(例如,定义学号位主键,学号不能重复),不能删除主表中的数据(例如某个学生),而不删除另一个表中和其有关的数据(例如另一个表中的学生成绩)等等。

l 设置表的主键:(其中MyDataSet是DataSet类对象)

DataColumn[] pKey=new DataColumn[1];

pKey[0]=MyDataSet.Tables["Student"].Columns["StudentNum"];

MyDataSet.Tables["Student"].PrimaryKey=pKey;

l 建立两个表的主从关系:(MyDataSet是DataSet类对象,主从关系意义见8.13节)

MyDataSet.Relations.Add("NewRelation",//关系的名称

MyDataSet.Tables["Student"].Columns["StudentNum"],//该关系的父列

MyDataSet.Tables["Score"].Columns["StudentNum"]);//该关系的子列

8.9   DataGrid控件和数据绑定概念

DataGrid控件用来按行和列格式显示DataSet对象中指定数据表的数据。其常用的属性和方法如下:

l  属性DataSource:用来指定要显示的数据表所在的数据集DataSet对象。

l  属性DataMember:用来指定在数据集DataSet对象中要显示的数据表的名字。当这两个属性被正确设定,DataGrid控件将以网格形式正确显示指定数据表。

l  属性CaptionText:获取或设置DataGrid控件标题的文本

l  属性CaptionVisible:该值指示DataGrid控件的标题是否可见。

l  属性TableStyles:可以编辑修改DataGrid控件的外观,具体例子见后边例子。

l  属性CurrentRowIndex:获取或设置DataGrid控件中当前选定行的索引号。

l  属性Item:索引指示器定义:object this[int rowIndex,int columnIndex],例如,DataGraid控件属性Name=grid,得到第2行第3列数据用如下语句:

object ob=grid[2][3];

l 属性AllowSorting:指示是否可以通过单击列标头对网格进行重新排序。

l 属性ReadOnly:获取或设置网格控件是否处于只读模式。

l 方法Select(Int32):选择参数指定行,参数为行号。

当DataGraid控件的属性DataSource和DataMember被正确设定,DataGraid控件将以网格形式正确显示DataSet对象中相应数据表。DataGraid控件中的数据被修改后,DataSet对象中相应数据表中的数据也被修改。这种关系叫做数据绑定。数据绑定有两个要点:第一,支持数据绑定的控件能按绑定的数据源正确显示数据源的数据,第二,在支持数据绑定控件中被修改的数据能被正确写回数据源,这里的数据源一般是数据集DataSet对象中的一个表或者是表中的一个字段。许多控件都支持数据绑定。

8.10     不连接数据库应用程序的完整的例子

例e8_10A:显示数据库studentI中的student表的所有记录。

(1)  新建项目。在Form1.cs文件头部增加语句using System.Data.OleDb;

(2)  放置控件DataGrid到主窗体,属性Name=dataGrid1。

(3)  为Form1类增加变量:OleDbConnection conn;OleDbDataAdapter da;DataSet ds;

(4)  为Form1类增加一个方法:

private void OnLoadData()

{   string txtConn=//注意,D:\\vc#\\studentI.mdb必须存在

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\vc#\\studentI.mdb";

conn=new OleDbConnection(txtConn);

string txtCommand="SELECT StudentName, StudentNum, StudentSex FROM Student";

da=new OleDbDataAdapter(txtCommand,conn);

ds=new DataSet();

da.Fill(ds,"Student");

dataGrid1.DataSource=ds;

dataGrid1.DataMember="Student";

}

(5)  在Form1类构造函数中增加语句:

OnLoadData();

(6)  运行,可以看到表Student中的信息。运行效果如图8.10A。                               图8.10A

e8_10B使用VS.Net连接数据库StudentI并显示Student表中的所有记录,具体步骤如下:

(1)  新建项目。从"工具箱"的"数据"选项卡页中,将OleDbConnection控件拖到窗体上,其属性Name=OleDbConnection1。选中控件oleDbConnection1,在属性窗口中单击其属性ConnectionString后边的下拉列表的箭头,在下拉列表中选择"新建连接",打开"数据链接属性"对话框(图8.10B),对话框有4个选项卡:提供程序、连接、高级、所有。选择"提供程序"选项卡页,选择OLE DB提供程序为:Microsoft.Jet.OLEDB.4.0 OLEDB Provider。如连接微软的SQL Server数据库,选择Microsoft OLE DB Provider for SQL Server。单击"下一步"按钮,显示"连接"选项卡页如图8.10C。标题"1.选择或输入数据库名称(D)"下有一编辑框,单击这个编辑框后标题为"…"按钮,打开"选择文件"对话框,选择数据库文件StudentI.mdb。按图8.10C那样,在用户名称中输入ACCESS数据库默认用户名Admin,选中"空白密码"多选框。单击"测试连接"按钮,应出现"测试连接成功"对话框。按"确定"按钮退出"数据链接属性"对话框。

图8.10B

图8.10C

(2)  在窗体中放置控件DataGrid控件,其属性Name=dataGrid1。

(3)  单击VS.Net菜单"视图"|"服务器资源管理器"菜单项,打开"服务器资源管理器"窗口如图8.10D,可以看到新建的"数据连接",单击"数据连接"前加号,展开"数据连接",再展开"表",可以看到数据库中的所有表名。拖Student表到控件DataGrid中,将自动增加控件oleDbDataAdapter1到窗体。

(4)  选中oleDbDataAdapter1,单击VS.Net菜单"数据"|"生成数据集…"菜单项,打开"生成数据集"对话框(图8.10E),选择默认值。按"确定"按钮退出。自动增加数据集DataSet类对象dataSet11。

图8.10D

图8.10E

(5)  修改DataGrid1属性DataSource= dataSet11,属性Datamember=Student,Student为表名。此时在DataGrid1中可看到表的表头。

(6)  在构造函数中增加语句如下:

oleDbDataAdapter1.Fill(dataSet11);

(7)  运行,可以在控件DataGrid1中看到表Student的内容。效果如图8.10A。

(8)  将DataGrid1控件中显示的字段名改为中文。选中控件DataGrid1,在属性窗口单击其属性TableStyles后的标题为"…"的按钮,打开"DataGridTableStyle集合编辑器"对话框(图8.10F)。

(9)  在8.10F对话框图中,单击"添加"按钮,增加一个dataGridTableStyle对象。在右侧属性列表中,从属性MapingName右侧的下拉列表中选择Student表。单击属性GridColumnStyles后标题为"…"的按钮,打开"DataGridTextBoxColumn集合编辑器"对话框(图8.10G),单击该对话框中"添加"按钮,增加一个dataGridTextBoxColumn对象。修改HeadText属性为:学号,从属性MapingName的下拉列表中选择Student表的StudentNum字段。按此办法,再增加两个dataGridTextBoxColumn对象,修改HeadText属性分别为:学生姓名、性别,属性MapingName分别为:StudentName、StudentSex。

(10)运行,可以在控件DataGrid1中看到的字段名为中文。运行效果见图8.10H。

图8.10F

图8.10G

图8.10H

8.11     删除记录和保存修改的数据到源数据库

(11)用DataGrid1控件已可以修改数据库表数据,增加记录。在窗体中增加标题为"删除"的按钮,单击此按钮,将删除DataGrid1控件中选定行。按钮单击事件处理函数如下:

private void button1_Click(object sender, System.EventArgs e)

{   int x;

x=dataGrid1.CurrentRowIndex;//DataGrid中当前选定行号

dataSet11.Tables["Student"].Rows[x].Delete();//删除Student表的第x条记录

}

(12)运行,选中控件DataGrid中某行,单击按钮可以删除此行。由于排序等原因,控件DataGrid中显示的dataSet11中表的记录顺序可能和dataSet11中表的记录的实际顺序不一致,因此用此方法删除数据可能出错。因此修改按钮单击事件处理函数如下:

private void button1_Click(object sender, System.EventArgs e)

{   int x;

object z;

x=dataGrid1.CurrentRowIndex;//DataGrid中当前选定行号

z=dataGrid1[x,0];//DataGrid中当前选定行的第0列数据

DataRow foundRow;//定义记录类变量

object[] findTheseVals = new object[1];

findTheseVals[0] = z;

foundRow = dataSet11.Tables["Student"].Rows.Find(findTheseVals);

if(foundRow != null)

foundRow.Delete();

}

(13)为了保存修改的数据到源数据库,增加一个标题为"保存数据"的按钮,单击此按钮后,将保存修改的数据到源数据库。为按钮增加单击事件处理函数如下:

private void button2_Click(object sender, System.EventArgs e)

{   if(dataSet11.HasChanges())//在退出程序时,也应用此函数检查,提醒用户是否存盘

oleDbDataAdapter1.Update(dataSet11);

}

(14)运行,增加一个记录,单击标题为"保存数据"的按钮后,关闭程序,再打开,可以看到新增的记录被显示,说明新增记录已被存到源数据库。

8.12     其它数据绑定控件

例子e8_12:本例用TextBox控件显示Student表,具体步骤如下:

(1)  新建项目。将3个Label控件放到窗体上,属性Text分别为:学号、姓名、性别。

(2)  放三个TextBox控件到窗体,属性Text都修改为空。TextBox1输入学号,TextBox2输入学生姓名,TextBox3输入学生性别。

(3)  从"工具箱"的"数据"选项卡中,将OleDbDataAdapter对象拖到主窗体上。"数据适配器配置向导"对话框自动打开(未给出图),帮助程序员创建数据库连接和适配器。单击"下一步"按钮,出现对话框如图8.12A。可以从控件ComboBox的下拉列表中选择已有的数据库连接,也可单击标题为"新建连接(C)…"按钮,新建数据库连接。本例选择已有的数据库连接如图8.12A。

图8.12A

(4)  单击图8.12A 中"下一步"按钮,出现对话框(未给出图)。在对话框中,选择标题为"使用 SQL 语句(S)"的单选按钮。单击"下一步"按钮,出现对话框图8.12B。

图8.12B

(5)  单击图8.12B中"查询生成器"按钮,出现标题为"添加表"对话框(图8.12C)。

图8.12C

(6)  在图8.12C中选择Student表,单击"添加"按钮,关闭图8.12C对话框。出现标题为"查询生成器"对话框(图8.12D)。在对话框最上部选择3个字段名称前的多选框如图,将自动增加SQL语句。单击"确定"按钮,将在图8.12B的编辑框中增加如下SQL语句:

SELECT  StudentName, StudentNum, StudentSex  FROM  Student

单击图8.12B中的"下一步"按钮,出现对话框列出所作的选择。单击"完成"按钮退出。可以看到新增的OleDbConnection对象,并已配置好设置。

图8.12D

(7)  选中组件oleDbDataAdapter1,单击VS.Net集成环境菜单"数据"|"生成数据集"菜单项。打开"生成数据集"对话框(图8.10E),选择默认值。按"确定"按钮退出。自动增加数据集DataSet对象dataSet11。单击VS.Net菜单"文件"|"全部保存"菜单项,存所有文件。

(8)  在属性窗口中,选中textBox1控件的属性DataBindings,单击属性前边+号展开,选中Text属性,从其下拉列表中选择dataSet11 - Student.StudentNum。同样办法textBox2为dataSet11 - Student.StudentName,textBox3为dataSet11 - Student.StudentSex。

(9)  在构造函数中增加语句如下:

dataSet11.Clear();

oleDbDataAdapter1.Fill(dataSet11);

(10)运行,可以看到第一个学生情况。现增加移动记录功能,以显示不同学生情况。

(11)为Form1类增加变量:BindingManagerBase Navigator;该类负责移动数据库表的指针。

(12)在构造函数中增加语句如下,该语句指定Navigator管理哪个表的记录指针。

Navigator=this.BindingContext[dataSet11,"Student"];

(13)放置4个Button控件到窗体,属性Text分别为:第一记录、下一记录、前一记录、最后记录。各个按钮的单击事件处理函数如下:

private void button1_Click(object sender, System.EventArgs e)

{   Navigator.Position=0;//第一记录

}

private void button2_Click(object sender, System.EventArgs e)

{   if(Navigator.Position!=Navigator.Count-1)

Navigator.Position+=1;//下一记录

}

private void button3_Click(object sender, System.EventArgs e)

{   if(Navigator.Position!=0)

Navigator.Position-=1;//前一记录

}

private void button4_Click(object sender, System.EventArgs e)

{   Navigator.Position=Navigator.Count-1;//最后记录

}

(14)运行,可以看到第一个学生情况。单击4个按钮可以移动记录。运行效果如下图。

8.13     建立主从关系表

在显示数据库StudentI的Student和Score表数据时,希望在Student表选中某个学生时,Score表只显示此学生的成绩,两个表的这种关系叫做主从关系。现在实现这两个表的主从关系。具体步骤如下:

(1)  新建项目。从"工具箱"的"数据"选项卡中,将OleDbDataAdapter对象拖到窗体上。"数据适配器配置向导"对话框自动打开,帮助程序员创建数据库连接和适配器。按照例子e8_12中步骤(4)到(7)配置OleDbDataAdapter对象。

(2)  将第二个 OleDbDataAdapter 对象拖到窗体上。"数据适配器配置向导"对话框再次自动打开。重复第(1)步所做的工作,其中有以下差异:

l 在数据适配器配置向导第二个对话框中,选择上次所使用的同一连接。

l 创建下列 SQL 语句来访问Score表:SELECT Score.* FROM Score

(3)  选中组件oleDbDataAdapter1,单击VS.Net菜单"数据"|"生成数据集"菜单项。打开"生成数据集"对话框(图8.13B),按图中那样选择,在"选择要添加到数据集中的表"下面的列表中,确保选中了Student和Score两个表。 选中"将此数据集添加到设计器"多选框,然后单击"确定"按钮。单击VS.Net菜单"文件"|"全部保存",存所有文件。

(4)  VS.Net集成环境自动生成数据集类(DataSet1)和定义该数据集的架构文件(DataSet1.xsd)。在"解决方案资源管理器"(图8.13A)中可看到这个架构文件。双击这个架构文件。"XML 设计器"被打开(图8.13C),显示数据集内的两个表。

(5)  从"工具箱"的"XML架构"选项卡中,将 Relation 组件拖到Score表(子表)上。"编辑关系"对话框打开(图8.13D),其中带有从这两个表中带来的默认值。做如下修改:父元素设置为Student表,子元素设置为Score表,键字段和外键字段               图8.13A              都为StudentNum。其它不修改选默认值。单击"确定"按钮,关闭"编辑关系"对话框。在"XML 设计器"中,这两个表之间显示一个关系图标。如果需要更改关系设置,则可以右击相应的关系,从快捷菜单中选择"编辑关系"。

(6)  保存该架构并关闭XML设计器。此时设置全部完成,可以向窗体添加显示数据的控件了。

(7)  返回Form1窗体。放置 DataGrid 控件到主窗体,属性Name=dataGrid1,属性RowHeadersVisable=false。在"属性"窗口中,将 DataSource 属性设置为 dataSet11,将 DataMember属性设置为Student。

(8)  放置 DataGrid 控件到主窗体,属性Name=dataGrid2。将DataSource 属性设置为 dataSet11,DataMember属性设置为Student.StudentScore,这个值代表了两个表的主从关系,保证了网格dataGrid2只显示dataGrid1表中被选中学生的学习成绩。

(9)  在Form1类构造函数中增加语句如下:

dataSet11.Clear();

oleDbDataAdapter1.Fill(dataSet11);

oleDbDataAdapter2.Fill(dataSet11);

(10)运行,可以看到两个DataGrid 控件,dataGrid1显示学生情况表,dataGrid2显示dataGrid1表中被选中的学生的成绩。在dataGrid1表中选择不同学生,dataGrid2显示相应学生的成绩。运行效果如图8.13E。

图8.13B

图8.13C

图8.13D

图8.13E

8.14   OleDbDataReader和SqlDataReader类

很多情况下,仅仅让用户浏览一些数据,并不允许修改数据。如果使用DataSet类对象显示大量的只读数据,由于DataSet类对象是数据库在内存中的一个子数据库,将占用较多内存空间,降低计算机的性能。使用OleDbDataReader和SqlDataReader类对象可以克服这个缺点。这两个类可以从数据库表中顺序读出数据,作为只读数据流,并不把读出的数据保存到内存中,减少计算机系统的开销。常用的属性、方法如下:

l  属性FieldCount:获取当前记录的列数,表的字段数。

l  方法Close:关闭OleDbDataReader或SqlDataReader类对象。

l  方法Read:读一个记录,指针下移,指向下一个记录。

l  方法GetInt16、GetString、GetByte等:在执行方法Read后,得到参数指定列的数据,注意要和列的相应字段的数据类型匹配。这些方法只有1个参数,表示第几个字段。

例子e8_14A:下面用一个例子介绍OleDbDataReader类的使用方法,该例用DataReader类读出数据,用ListView控件显示。具体步骤如下:

(1)  新建项目。增加语句using System.Data.OleDb;

(2)  放置视图控件ListView到窗体,属性View=Detail。点击属性Column右侧标题为"…"的按钮,在弹出的"ColumnHeader集合编辑器"对话框中添加3个列头,属性Text分别为:学生学号、学生姓名、学生性别。(参见例子e6_4_2)

(3)  为Form1类增加变量:OleDbConnection conn; OleDbCommand da; OleDbDataReader dr;

(4)  为Form1类增加一个方法:

private void OnLoadData()

{   string txtConn="Provider=Microsoft.Jet.OLEDB.4.0;

Data Source=D:\\VC#\\studentI.mdb";

conn=new OleDbConnection(txtConn);

string txtCommand="SELECT * FROM Student";

da=new OleDbCommand(txtCommand,conn);

conn.Open();

dr=da.ExecuteReader();//注意只能用此方法得到OleDbDataReader类对象

while (dr.Read())//读1个记录,返回false,所有记录已被读出

{   ListViewItem lvi;

string[] s=new String[]//注意读出每个字段的方法

{dr.GetInt16(0).ToString(),dr.GetString(1),dr.GetString(2)};

lvi=new ListViewItem(s);

listView1.Items.Add(lvi);

}

dr.Close();

conn.Close();

}

(5)  在构造函数中增加语句:OnLoadData();

(6)  运行,可以看到表Student中的信息。运行效果如上图。

8.15   DataView类

将感兴趣的数据取出,放到DataSet类对象中,在内存中为数据库建立一个子数据库。经常要对子数据库中的数据进行分析,例如,查找指定学号的学生,查找某课程不及格的所有学生名单等。这些工作可以用DataView类实现。DataView类常用属性和方法如下:

l  属性AllowDelete:该值指示是否允许删除DataView类对象中的数据。

l  属性AllowEdit:该值指示是否允许编辑DataView类对象中的数据。

l  属性AllowNew:该值指示是否可用 AddNew 方法为DataView类对象添加新记录。

l  属性Count:获取 DataView 中记录的数量。

l  属性RowFilter:定义筛选表达式,决定表中的哪些记录在 DataView 中显示。如有多个筛选条件,可以使用and、or或like操作数。

l  属性Sort:排序表达式。例如对DataView类对象dw,StudentNum字段排序表达式为:dw.Sort="StudentNum",数据绑定后,将按对StudentNum字段排序。默认为升序排序,如希望降序排序可以采用如下格式:dw.Sort="StudentNum DESC"。也可以对多个字段排序,例如希望首先按StudentNum字段排序,再按StudentName字段排序可以采用如下格式:dw.Sort="StudentNum DESC, StudentName"。

l  构造函数public DataView(DataTable table):建立指定的表的DataView类对象。

例子e8_15:下面用一个例子介绍DataView类的使用方法,该例首先读出StudentI数据库中的Student表的所有记录,存到DataSet类对象中,用DataGrid显示。然后,查找所有男同学,存到DataView类对象中,用另一个DataGrid控件显示。具体步骤如下:

(1)  新建项目。在Form1.cs文件头部增加语句using System.Data.OleDb;

(2)  添加两个DataGrid控件到主窗体,属性Name分别为dataGrid1、dataGrid2。

(3)  为Form1类增加变量:OleDbConnection conn;OleDbDataAdapter da;DataSet ds; DataView dw;

(4)  为Form1类增加一个方法:

private void OnLoadData()

{   string txtConn=//注意,D:\\vc#\\studentI.mdb必须存在

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\vc#\\studentI.mdb";

conn=new OleDbConnection(txtConn);

string txtCommand="SELECT StudentName, StudentNum, StudentSex FROM Student";

da=new OleDbDataAdapter(txtCommand,conn);

ds=new DataSet();

da.Fill(ds,"Student");

dataGrid1.DataSource=ds;

dataGrid1.DataMember="Student";

dw=new DataView(ds.Tables["Student"]);

dw.RowFilter= "StudentSex='男'";

dataGrid2.DataSource=dw;

}

(7)  在构造函数中增加语句:OnLoadData();

(8)  运行,可以看到dataGrid2中只显示所有的男同学。运行效果如右图。

8.16     参数化查询及存储过程

如果一个SQL查询语句要多次使用,但每次使用时查询条件不相同,可以使用参数化查询。所谓参数化查询就是在SQL查询语句的查询条件中定义一个变量,每次使用时把希望查询的条件赋值给这个变量,执行查询,得到查询结果。例如,查询学生情况表中的男同学或女同学,见下例:

(1)  新建项目。在Form1.cs文件头部增加语句using System.Data.OleDb;

(2)  添加控件DataGrid到主窗体,属性Name=dataGrid1。

(3)  为Form1类增加变量:OleDbConnection conn;OleDbDataAdapter da;DataSet ds;

(4)  在构造函数中增加语句:

string txtConn=//注意,D:\\vc#\\studentI.mdb必须存在

"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\vc#\\studentI.mdb";

conn=new OleDbConnection(txtConn);

string txtCommand="SELECT * FROM Student WHERE StudentSex=@Sex";//Sex是参数

da=new OleDbDataAdapter(txtCommand,conn);

da.SelectCommand.Parameters.Add(new SqlParameter("@Sex",SqlDbType.NvarChar,2);

da.SelectCommand.Parameters["@Sex"].Value="男";

ds=new DataSet();

da.Fill(ds,"Student");

dataGrid1.DataSource=ds;

dataGrid1.DataMember="Student";

(5)  放ComboBox控件到窗体中,属性Name=comboBox1,在属性窗口中,单击Items属性右侧标题为"…"的按钮,打开"字符串集合编辑器"对话框,在其中输入2项:男、女。增加SelectedIndexChenged事件处理函数如下:

private void comboBox1_SelectedIndexChanged(object sender, System.EventArgs e)

{     da.SelectCommand.Parameters["@Sex"].Value=comboBox1.Text;

ds.Clear();

da.Fill(ds,"Student");

dataGrid1.DataSource=ds;

dataGrid1.DataMember="Student";

}

(6)  运行,在dataGrid1中显示所有男同学。从ComboBox控件中选择男或女,在dataGrid1中可以看到按所作选择,显示所有男同学或女同学。

存储过程是在数据库系统中预先定义的SQL语句的集合,数据库应用程序可以直接调用这些存储过程,加快运行速度。微软SQL Server数据库自带数据库例子Northwind 中有一存储过程:Ten Most Expensive Products,使用这个存储过程代码如下:

string txtConn="DATABASE=Northwind;SERVER=localhost;UID=sa;PWD=;";

SqlConnection conn = new SqlConnection(txtConn);

SqlDataAdapter da = new SqlDataAdapter("Ten Most Expensive Products",conn);

da.SelectCommand.CommandType=CommandType.StoreProcedure;//默认值为Text

ds=new DataSet();

da.Fill(ds," MyProducts");

8.17     DataTable类

可以用程序建立一个数据表,为表增加字段、填充数据并用数据绑定控件显示,见下例:

(1)  新建项目。增加语句using System.Data.OleDb;

(2)  添加控件DataGrid到主窗体,属性Name=dataGrid1。

(3)  为Form1类增加DataTable类变量:DataTable dt;

(4)  为Form1类增加一个方法:

private void OnLoadData()

{   dt = new DataTable();//建立DataTable类对象

DataRow dr;//建立记录类变量

dt.Columns.Add(new DataColumn("IntegerValue", typeof(Int32)));//增加字段

dt.Columns.Add(new DataColumn("StringValue", typeof(string)));

dt.Columns.Add(new DataColumn("DateTimeValue", typeof(DateTime)));

dt.Columns.Add(new DataColumn("BoolValue", typeof(bool)));

for (int i=0;i<2;i++)//增加两个记录

{   dr = dt.NewRow();

dr[0] = i;

dr[1] = "项" + i.ToString();

dr[2] = DateTime.Now;

dr[3] = (i % 2 != 0) ? true : false;

dt.Rows.Add(dr);

}

dataGrid1.DataSource = new DataView(dt);//数据绑定

}

(5)  在构造函数中增加语句:OnLoadData();

(6)  运行,在dataGrid1中可以看到表中的信息。

习题

(1)      为e8_6例子增加如下功能:删除指定学号记录、增加一个记录等。

(2)      写出建立SqlAdapter类对象的语句。

(3)      在网格控件中,对选定的列进行排序的方法。(用DataView类的sort属性或见图8.12D)

(4)      分别修改网格控件的AlternatingBackColor和BackColor属性为不同颜色,看一下效果。

(5)      用DataGrid控件显示学生信息Student表,为每个字段增加排序功能。

(6)      放置控件ComboBox到窗体,控件的下拉列表和数据库StudentI的Student表的StudentNum和StudentName字段绑定。

(7)      将8.15节的例子改为查找学号在2到4之间的学生。

(8)      用DataGrid控件显示微软SQL Swever数据库系统所带的数据库例子NorthWind中的Employees表的所有记录的数据。

(9)      为8.12节的例子增加删除记录,修改记录和保存修改的功能。

(10)   用ACCESS创建销售管理数据库,一个表记录每笔销售,另一个表记录库存,请定义每个表的字段。创建一个实用的销售管理数据库应用程序。

(11)   退出不连接数据库应用程序,如何实现提示用户保存对数据库所做的修改。

15数据库与ADO.Net的更多相关文章

  1. windows 系统如何安装 mysql 8.0.15 数据库?

    windows 系统如何安装 mysql 8.0.15 数据库? 1. 下载安装包 下载地址:https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0. ...

  2. 从头开始学习数据库及ADO.NET——竹子整理

    目前为止,学习编程一年有余,写过管理系统,写过商城,写过桌面,接触的多了,乱七八糟的点太多,一堆前段框架,后台类库,纷纷杂杂,更新迭代之快也是令人咋舌.于是我就在想,作为一名程序员,哪些内容是实打实的 ...

  3. 数据库和ado连接语句的使用总结

    基本的sql语句 创建数据库:CREATE DATABASE database-name 删除数据库:drop database dbname 创建表:create table tabname(字段属 ...

  4. 读书笔记——数据库的ADO开发总结

    基本上是对 ADO+开发指南.pdf 的摘抄和总结,以及个人心得. 文章末尾有<ADO+开发指南.pdf>的资源下载,附带个人批注. --------------------------- ...

  5. 快速批量导入庞大数据到SQL SERVER数据库(ADO.NET)

    原文地址:http://www.cnblogs.com/chenxizhang/archive/2008/11/11/1331060.html 如果你需要在程序中批量插入成千上万行的数据,你会怎么编写 ...

  6. C#中简单操作SQLserver数据库(ADO.NET的简单应用)

    本篇文章以 ADO.NET 访问SQL SERVER 数据库为例, 其中需用System.Data.SqlClient; 数据库连接字符串写法为:server=数据源(服务器名称);uid=用户名;p ...

  7. 数据库之ADO

    ADO是一种跨多种语言的数据库访问技术. 在MFC里面微软公司将这些函数封装为以下几个类. 在VS2013版本的MFC中,这些类是如下定义的. CDaoDatabase Class:https://m ...

  8. 数据库和ADO

    数据库语言 数据库的简易流程(数据库客户端软件和数据库服务软件的执行流程) 主键的概念 如何创建主键 如何创建外键 主外键关系的概念以及使用 数据库的主要类型 数据库的主要数据类型 使用SQL语句来创 ...

  9. MySQL7.5.15数据库配置主从服务器实现双机热备实例教程

    环境说明 程序在:Web服务器192.168.0.57上面 数据库在:MySQL服务器192.168.0.67上面 实现目的:增加一台MySQL备份服务器(192.168.0.68),做为MySQL服 ...

随机推荐

  1. aapt的常用命令

    1. 列出apk包的内容 aapt l[ist] [-v] [-a] file.{zip,jar,apk} -v 以table形式列出来 -a 详细列出内容 例如:aapt l <你的apk文件 ...

  2. Spring配置事务的五种方式

    Java事务的类型有三种: JDBC事务. 可以将多个 SQL 语句结合到一个事务中.JDBC 事务的一个缺点是事务的范围局限于一个数据库连接.一个 JDBC 事务不能跨越多个数据库 JTA(Java ...

  3. 【HDU 2167】 Pebbles

    [题目链接] 点击打开链接 [算法] 状压DP 先搜出一行符合的情况,然后,f[i][j]表示第i行,状态为j,能够取得的最大值,DP即可 [代码] #include<bits/stdc++.h ...

  4. openpyxl操作excel

    [转] openpyxl库可以读写xlsx格式的文件,对于xls旧格式的文件只能用xlrd读,xlwt写来完成了. python有很多模块都是用来操作excel的,比如xlrd,xlwt,pyExce ...

  5. [转]python的find()方法

    描述 Python find() 方法检测字符串中是否包含子字符串 str ,如果指定 beg(开始) 和 end(结束) 范围,则检查是否包含在指定范围内,如果包含子字符串返回开始的索引值,否则返回 ...

  6. 【184】FileZilla 搭建 FTP 及访问

    参考:FileZilla 下载中心 参考:使用FileZilla Server轻松搭建个人FTP服务器 建好后,Windows 访问:Windows徽标键+R打开运行窗口,输入ftp://*** ,* ...

  7. 微型ORM:PetaPoco 学习资料整理

    github地址:https://github.com/CollaboratingPlatypus/PetaPoco petapoco 实体中字段去掉关联(类似于EF中的NotMap) 微型ORM:P ...

  8. HDU 5916 Harmonic Value Description (构造)

    题意:给你 n 和 m,求一个1-n的排列,使得∑gcd(Ai,Ai+1) 恰为第  m 小. 析:可以想到最小的就是相邻都互质,然后依次,第 m 小就可以有一个是gcd为 k,然后其他的为1喽. 那 ...

  9. Pycharm的安装教学

    Python环境搭建—安利Python小白的Python和Pycharm安装详细教程 人生苦短,我用Python.众所周知,Python目前越来越火,学习Python的小伙伴也越来越多.最近看到群里的 ...

  10. JavaScript 编程艺术-第4章(JavaScript美术馆)代码

    功      能:在同一个网页上切换显示不同的图片与文本(*亲测可用) 使用属性: a) document.getElementById(" ") ——返回一个与给定的id属性值的 ...