数据访问技术
一、Ado.net介绍
Ado.net是数据访问技术的统称。在C#中,我们主要通过Ado.net技术来实现程序和数据库的交互。
ADO.NET主要5大对象:
1.1 Connection:连接池对象,用来与数据库建立连接。
里面包含:SqlConnection,OledbConnection,OdbcConnection,OracleConnection
SqlConnection对象用于连接Sql Server数据库
OledbConnection对象用于连接Access数据库
OracleConnection对象用于连接Oracle数据库
OdbcConnection对象用于连接ODBC数据源
同理,下面的Command,DataReader,DataAdapter对象也分别对应不同的数据库,提供了这样4种类型的对象。
1.2 Command:命令对象,用来执行sql命令并返回结果。同理我们针对sql server数据库时,需要使用SqlCommand对象。其他类似。
1.3 DataReader:数据读取流,用来逐行读取查询语句返回的结果集。(执行select语句时使用)
1.4 DataAdapter:数据适配器,用来将查询语句的结果集填充到内存中。(执行select语句时使用)
1.5 DataSet:数据集,用来存储数据的容器。其内部结构类似于数据库,可以看成是虚拟的数据库,由多个表组成。表中由数据行和列组成。通常执行查询语句时,为了方便访问查询语句的结果集。会使用DataAdapter对象将结果填充到DataSet中。方便我们在程序中对数据进行操作。
二、下面我们以操作Sql Server数据库为例,把经典5步及容易犯的错误标注一下:
首先需要引用命名空间:System.Data.SqlClient;
//首先确定要执行的sql语句,实际上无外乎4种,添加、修改、删除、查询
string sql="Insert/Update/Delete/select";
注:一般在写sql语句的过程中,对于刚接触的同学,建议先在sql server工具中编写语句,确定语法正确后,在将语句拷贝到程序中。另外切记不要掉单引号。不管是添加、修改、删除、查询时,凡是语句中包含字符串或者日期类型的数据,必须给数据加上单引号。如:insert into users(name,pwd,age,birthday) values(‘张三’,’123’,20,’2012-2-10’),其他数据类型的数据可以不加单引号。
操作数据库的五个步骤:
1.1 创建连接池对象
SqlConnection conn=new SqlConnection("server=数据库所在机器ip地址;database=数据库名;uid=登录用户名;pwd=登录密码");
注:在编写连接字符串时,连接本机数据库时,服务器ip地址可以使用.,写法为:
Server=.;database=数据库名;uid=用户名;pwd=密码
另外也可以使用windows身份验证,即不需要指定用户名和密码,写法为:
server=.; database=数据库名;Integrated Security=true
1.2 打开连接池对象
conn.Open();
注:必须打开连接池对象后,才能执行命令操作,程序运行时,如果在这句代码处报错,通常只有一种可能,就是连接字符串错误。请根据错误信息仔细检查连接字符串。
1.3 创建命令对象
SqlCommand cmd=new SqlCommand(sql,conn);
1.4 执行命令操作(执行语句并返回相应结果的过程)
cmd.ExecuteNonQuery();
注:该方法专用于执行添加、修改、删除的SQL语句,返回增删改语句执行成功的行数。通常判断返回的行数大于0,则操作成功,否则失败
cmd.ExecuteScalar();
注:该方法适用于查询语句,但只会返回查询语句结果集中首行首列的数据,且返回后需要进行类型转换。
cmd.ExecuteReader();
注:该方法适用于查询语句,结果集为多行多列时。但返回的并不是结果集,返回的是DataReader对象。需要使用该对象的Read()方法逐行去读取结果集中的数据
在程序运行时,如果在这句代码处报错,那错误的原因也只有一种可能,就是SQL语句错了。请好好检查SQL语句,如果检查不出来,建议调试跟踪出具体的sql语句,然后放在sql server工具中,让工具告诉你哪里错了。
1.5 关闭连接池对象
conn.Close();
注:切记一定要关闭,在C# 中,默认能够使用的连接池对象为100个,也就是说如果每次创建连接池对象并且打开后,都不关闭的话,该连接池对象没有真正销毁,一直被占用着。到了100个后,将无法再创建新的连接池对象。将无法操作数据库。
三、示例参考
一般在多个窗体中都需要操作同一个数据库,每次都需要去编写连接字符串,这样代码重复性比较高,而且后期数据库密码更改后,维护起来比较麻烦。所以通常会创建一个类,在类中定义公共静态变量来保存连接字符串。在窗体中通过类名.变量名来读取。通常类名约定为DBHelper,在类中编写如下代码:
Class DBHelper
{
Public static string ConnStr=” server=数据库所在机器ip地址;database=数据库名;uid=登录用户名;pwd=登录密码”
}
1、执行添加、修改、删除语句时。
string sql="Insert/Update/Delete ";
1)、创建连接池对象
SqlConnection conn=new SqlConnection(DBHelper.ConnStr); //读取DBHelper类中的连接字符串
2)、打开连接池对象
conn.Open();
3)、创建命令对象
SqlCommand cmd=new SqlCommand(sql,conn);
4)、执行命令操作(执行语句并返回相应结果的过程)
int rows=cmd.ExecuteNonQuery();
5)、关闭连接池对象
conn.Close();
if(rows>0)//根据返回的执行成功的行数进行判断,如果大于0,代表添加/修改/删除成功,否则失败
{
MessageBox.Show(“操作成功!”);
}
else
{
MessageBox.Show(“操作失败!”);
}
2、执行查询语句时
2.1当查询语句返回结果为一个数据时,即单行单列的值。比如:
Select count(*) from 表名或者是Select name from 表名 where id=值
这样一类的语句,通常返回结果只有一个数据时。
string sql="Select …";
1)、创建连接池对象
SqlConnection conn=new SqlConnection(DBHelper.ConnStr);
2)、打开连接池对象
conn.Open();
3)、创建命令对象
SqlCommand cmd=new SqlCommand(sql,conn);
4)、执行命令操作(执行语句并返回相应结果的过程)
Object obj=cmd.ExecuteScalar();
注意:该方法的返回类型为object类型,目前还没学习这个类型,但我们可以将这个类型理解为一种通用类型,但在使用时,需要进行类型转换。也就是说根据你查询语句的返回结果,如果返回的是int类型,那就需要转换为int类型;如果为字符串那就转换为字符串类型。
5)、关闭连接池对象
conn.Close();
//对返回值进行类型转换,一般在转换前,建议判断是否为null。代码参考如:
If(obj!=null)
{
//类型转换,如果是int,则
Int a=Convert.ToInt32(obj);
//如果是string,则
String a=obj.ToString(); //以此类推。所以需要根据select 语句返回的结果来确定这里该转换的目标类型
}
2.2查询多行多列的结果时,可以使用两种方式:
一:使用DataReader对象一行一行读取结果集中的数据
DataReader对象的特点:
1、只进、只读的数据读取流
2、用来逐行读取查询语句结果集中的数据。
3、在读取期间,连接池对象必须保持打开状态。
注:该对象只是负责读取数据,本身并不包括数据
Read():读取下一行数据,如果有数据,返回true,否则返回false
Close():读取完后,关闭对象。
使用范例:
string sql="Select …";
1)、创建连接池对象
SqlConnection conn=new SqlConnection(DBHelper.ConnStr);
2)、打开连接池对象
conn.Open();
3)、创建命令对象
SqlCommand cmd=new SqlCommand(sql,conn);
4)、执行操作
//返回数据读取流
SqlDataReader reader= cmd.ExecuteReader();
//判断读取流是否为null
if (reader != null)
{
//逐行读取结果集中的每一行数据
while (reader.Read())
{
//根据字段名读取reader中某字段的值,并转换为字符串
string loginid = reader["id"].ToString();
}
//关闭DataReader对象
reader.Close();
}
conn.Close();
二、使用DataAdapter将结果集中地数据一次性的放在数据容器DataSet中,方便以后读取。
DataAdapter:数据适配器,主要用来将结果集填充到DataSet中
DataSet:数据容器,就像虚拟的数据库一样,由多个数据表组成。
使用范例:
1、创建连接池对象
SqlConnection conn=new SqlConnection(DBHelper.ConnStr);
2、打开连接池对象
conn.Open();
3、创建命令对象
SqlCommand cmd=new SqlCommand(sql,conn);
4、执行命令操作(执行语句并返回相应结果的过程)
//创建数据适配器来读取cmd对象的返回结果集
SqlDataAdapter da=new SqlDataAdapter(cmd);
//创建容器
DataSet ds=new Dataset();
//将数据放在容器中
da.Fill(ds);
5、关闭连接池对象
conn.Close();
结束语:实际上操作数据库,其中有几步总是不变的:创建连接池、打开连接池、创建命令对象、关闭连接池,这几步写法基本是固定死的。真正在变的就2块:要执行的sql语句,和执行的操作。执行的操作主要为2大块,要么是增加、修改、删除,都统一使用ExecuteNonQuery方法;要么是查询,查询时有三种处理方式,返回结果为一个数据时,直接使用ExecuteScalar方法;当返回结果比较多时,可以使用ExecuteReader方法,也可以使用DataAdapter配合DataSet。大家可以根据自己的习惯去取舍。