第一章 ado.net
1 ado.net架构
ado.net其实本质上是一组提供与数据库交互和操作的类库。
1、ado.net数据提供程序
数据提供程序是一组用于访问特定数据库,执行sql命令,并获取最终结果的ado.net类。Ado.net有以下几种数据库提供程序类:
(1)connectin:连接数据库
(2)command:执行sql命令和存储过程
(3)datareader:读取结果,即查询结果有很多条。
(4)dataadapter:包含以上三条命令的功能。
2、ado.net重点
(1)ado.net提供程序模型是可扩展的,即可第三方开发自定义数据提供程序。
.net4.0提供了 sqlserver提供程序,odbc提供程序,ole db提供程序,oracle提供程序(.net4.0以后不提供oralce提供程序,用oralce自已发布的odp.net提供程序)
(2)ado.net是标准化的,虽然提供了松散的模型,不同的数据类型使用不同的数据提供程序,但他们都继承于同样的接口和基类,保证了每个不同的数据提供程序以同样的方式工作并显示相同的属性和方法。所以方法名和使用方法都一样。如open(),close()等核心方法。这样可以在更换数据库后,不用重新开发程序,直接修改ado.net即可。
3、基于ado.net的类
(1)基于连接的对象:如connection,command,datareader,dataadapter类。
(2)基于内容的对象:dataset,datacolumn,datarow,datarelation类。它们完全和数据源独立。
这几种类的命令空间在system.data中。需要应用这些类的方法时,需要先导入命名空间。
如:要调用sqlserver数据库,就导入system.data.sqlclient命名空间中。
处理数据库的步骤
->连接数据库 //connectin
->初始化SQL语句
->准备Command对象
->打开连接
->执行查询
2 connection类
1、 连接字符串
Server //指定数据库服务器名和实例名
Database//指定要连接的数据库名
Uid和pwd //登录数据库服务器的帐号和密码
Integrated security=sspi //用windowsauthentication验证。
例:
stringsource=@"server=.\sqlexpress;"+"database=test;"+"uid=sa;"+"pwd=zjt71305"; //@的作用是,后面的\不作转义符,做为字符使用。,注意,引号里的分号不能少。
stringsource1=@"server=.\sqlexpress;database=test;integratedsecurity=SSPI";//也可以用这种格式。这里是用windows验证。如果是远程服务器,就要指定ip地址。
SqlConnection con=newSqlConnection(source); //新建一个sqlconnection对象,把字符串作参数初始化,就连接了数据库了。
con.Open(); //打开数据库
con.close() //关闭数据库。数据库在用的时候才开,不用就关掉,不然占用资源太大。
2、 高效的使用连接
当服务器打开,有时会忘记关闭时,会耗很多资源。
(1) try …catch….finall
try
{
Con.open()
}
Catch()
{
}
Finally
{
Con.close(); //保证在任何情况下都会关闭数据库连接。
}
(2)using //实现了disable
using (con)
{
con.Open(); //保证在任何情况下,只要退出using语句就会自动关闭数据库。
}
3 command类
三种执行命令
ExcuteNonQuery()//一般用于update,insert,delete语句的执行。返回受影响的记录数。即非查询语句执行。如果是非增删改操作返回-1.
ExcuteScalar()//该方法返回查询结果第一行第一列的值,如果没有数据,则返回NULL!适用于只返回一个值的存储过程,和用聚合函数返回值的。用于返回一个查询语句的第一行第一列的结果。
ExcuteReader()//用于返回多条记录的查询语句。
例(1) excutenonquery()
stringsource=@"server=.\sqlexpress;database=test;integrated security=SSPI";
SqlConnection con=new SqlConnection(source)
Intros; //声明返回整数的变量名。
Using(con)
{
string insert = "insert intoshopping values(100008,'啤酒',200,3.5,100004,'量大')"; //准备sql语句
SqlCommand cmd = newSqlCommand(insert, con);//把SQL语句作为一个参数传递给command类的构造函数。前面的是SQL语句,后面是连接字符串对象。准备command对象
Using(cmd) //cmd也要using起来。
{
Con.open(); //打开数据库
Int ros=Cmd.excutenonquery(); //执行SQL语句。有返回值,并赋值给ros。定义了命令,一定要执行才有用。
}
}
Console.writeline(ros);
例(2)excutescalar()
string sql = @"server=.\sqlexpress;database=loready;uid=sa;pwd=zjt71305"; //连接数据库
SqlConnection con = newSqlConnection(sql); //建立sqlconnection对象
using (con)
{
string se="select count(*) from username "; //查询语句
SqlCommand cm = newSqlCommand(se, con); //查询语句和sqlconnection对象当作参数传给sqlcommand对象的构造函数。
using (cm)
{
con.Open(); //打开数据库
object r=cm.ExecuteScalar(); //返回查询到的第一行第一列的内容。
Console.WriteLine(r); //如在using语句外面,就要先声明变量r,在里面就不必先声明。
Console.ReadKey();
}
}
例(3) excutereader() (请先阅读下面的1.4节的datareader和1.5节的参数化注入)
主要是查询多条数据。
string sql = @"server=.\sqlexpress;database=loready;uid=sa;pwd=zjt71305"; //定义连接的数据库
SqlConnection con = newSqlConnection(sql); //建立连接对象
using (con)
{
con.Open();
SqlCommand cm = newSqlCommand("dtail_age", con); //把存储过程名和连接对象传到sqlcommand中作为参数。
using (cm)
{
cm.CommandType= CommandType.StoredProcedure; //指定类型为存储过程
cm.Parameters.Add(newSqlParameter("@age",30)); //给存储过程中的参数赋值。
//SqlDataReader read= new SqlDataReader();
//read =cm.ExecuteReader(); //这两句可以用下面一句代替
SqlDataReader read =cm.ExecuteReader(); //把executereader查询到的数据赋值给sqldatareader对象。
using (read)
{
while (read.Read()) //用来遍历每一行。read.read()方法返回一个布尔类型,初始时指针在所查询数据条之前,不指向任何一条数据,然后每调用一次此方法,指针就下移一条,只要没移到最后一条之后就一直返回true。如果移到最后一条数据之后,就返回false。所以用此方法用来判断和遍历数据。
{
for(inti=0;i<read.FieldCount;i++) //read.fieldcount是指一条数据的列数。这个for语句是遍历一条数据的每一列。
{
string rd=read[i].ToString(); //把每一行的每列数据转换成字符串。
Console.WriteLine(rd);
}
Console.WriteLine();
}
Console.ReadKey();
}
1.4、 datareader类
读取查询到的结果
1、基本用法:
sqldatareader read=cmd.excutereader(); //后面是cmd.executereader(),新建一个sqldatareader实例 。
using(read)
{
read.read(); //此方法返回一个布尔类型,初始时指针在所查询数据条之前,不指向任何一条数据,然后每调用一次此方法,指针就下移一条,只要没移到最后一条之后就一直返回true。如果移到最后一条数据之后,就返回false。所以用此方法用来判断和遍历数据。
sqldatareader有好多方法和属性。
While(reader.read()) //当不是最后一条之后,所以一直返回为真,就一直循环。
{
String name=Read.getstring(0); //返回第查询到数据的第一列的值,并且会显示所有行的第一列。get方法即是获取查询后表的某一列的值,0代表第一列。以此类推。因为第一列是商品名,所以这里是string类型。有很多种GET方法,数据类型一定要与表中的类型一致。
Int number=Read.getint32(1) //显示查询数据第二列的值
}
}。
2、常用方法:
(1)GetOrdinal:获取指定列名的列序号(索引号),使用这个方法可以把经常变动的列进行固定
int name= read.GetOrdinal("name"); //通过列名来获取当前列的索引号
(2)GetName: 获取列名,参数为指定列名的序列号,返回string
string columnName= read.GetName(name);//通过列名所处的索引号来获取列名名称
(3)IsDBNull:判断当前读取的数据是否为Null,返回类型为Bool
read.IsDBNull(coContractID)?"NULL": read.GetInt32(coContractID).ToString();
(4)NextResult:当查询为批处理查询时,使用这个方法去读取下一个结果集,返回值为Bool,如果存在多个结果集,则为 true;否则为 false。
(5)Read:读取数据
3、常用属性
(1)HasRow:判断是否包含一行或多行,也就是判断有没有数据,返回类型为Bool。
(2) FieldCount:获取读取的列数,返回类型为Int。
(3)IsClosed:判断读取的数据流是否关闭。
4 sqlparameter 参数化防注入(SqlParameter类的用法)
1、常用方法和属性:
(1)属性
ParameterName:设置参数名
Value:给参数设置值
Size:设置参数字节最大大小
SqlDbType:参数在SQL中的类型
(2)方法:
(1)AddWithValue:直接增加参数名和值。
(2)Add:添加参数的类型和长度等。
(3)AddRange:添加数组参数。
2、 给命令对象添加参数法:
id =1;
string Name="lui";
string insert ="insert into TUserLogin values(@Id,@Name)";
//上条语句中直接在sql语句中写添加的参数名,不论参数类型都是如此.
(1)sqlParameter para=new SqlParameter("@Id",SqlDbType.int,4);//生成一个名字为@Id的参数,必须以@开头表示是添加的参数,并设置其类型长度,类型长度与数据库中对应字段相同。
(2)para.Value=Id;//给参数赋值,即把id这个值赋给了@id这个参数,已声明了ID值为1。
//以上两步可以合成一步如:
Sqlparameterpara=new sqlparameter(“@id”,id)//后面是直接给id变量赋值
(3)cmd.prameters.Add(para);//必须把参数变量添加到命令对象中去。
以上三步可以直接写成下面一句:
Cmd.parameters.add(newsqlparameter(“@name”,name)); //也可以把上面三步合并成一步执行
3、例:
例1,普通参数传递:
string sql = @"server=.\sqlexpress;database=loready;uid=sa;pwd=zjt71305";
SqlConnection con = newSqlConnection(sql);
using (con)
{
string insert = "insert into usernamevalues(@id,@name,@pwd,@mark)";
SqlCommand cm = newSqlCommand(insert, con);
using(cm)
{
con.Open();
//写法一:
SqlParameter par1 = newSqlParameter("@id", SqlDbType.NChar); //建立一个sqlparmeter参数对象,并把参数名和参数类型作为参数,这里的参数类型一定要与参数在数据库中的类型保持一致。
SqlParameter par2 = newSqlParameter("@name", SqlDbType.NVarChar);
SqlParameter par3 = newSqlParameter("@pwd", SqlDbType.NVarChar);
SqlParameter par4 = newSqlParameter("@mark", SqlDbType.NVarChar);
par1.Value="20150004"; //给参数赋值
par2.Value="wk";
par3.Value="123456";
par4.Value= "王凯";
cm.Parameters.Add(par1); //必须把参数对象添加到sqlmmand对象cm中去。
cm.Parameters.Add(par2);
cm.Parameters.Add(par3);
cm.Parameters.Add(par4);
//可简化写成:
//SqlParameter par1 = newSqlParameter("@id","20150004"); //建立一个sqlparmeter参数对象,并直接给参数赋值。
//SqlParameter par2 = newSqlParameter("@name","wk");
//SqlParameter par3 = newSqlParameter("@pwd","123456");
//SqlParameter par4 = newSqlParameter("@mark","王凯");
//cm.Parameters.Add(par1); //必须把参数对象添加到sqlmmand对象cm中去。
//cm.Parameters.Add(par2);
//cm.Parameters.Add(par3);
//cm.Parameters.Add(par4);
//写法二:
//SqlParameter[] par = new SqlParameter[]{
// newSqlParameter("@id",SqlDbType.NChar),
// newSqlParameter("@name",SqlDbType.NVarChar),
// newSqlParameter("@pwd",SqlDbType.NVarChar),
// newSqlParameter("@mark",SqlDbType.NVarChar)
// }; //建一个sqlparameter数组,以传多个参数。也可以一条一条的写。也可以在里面直接给参数赋值,就可以省略下面的单独赋值过程。
//par[0].Value = "20150004";
//par[1].Value = "wk";
//par[2].Value = "123456";
//par[3].Value = "王凯";
//cm.Parameters.AddRange(par);
//写法三:下面一步相当于上面三步。
//cm.Parameters.Add(newSqlParameter("@id","20150004"));
//cm.Parameters.Add(newSqlParameter("@name", "wk"));
//cm.Parameters.Add(newSqlParameter("@pwd", "123456"));
//cm.Parameters.Add(newSqlParameter("@mark", "王凯"));
object i = cm.ExecuteNonQuery(); //显示受影响的行数。
Console.WriteLine(i);
Console.ReadKey();
1.5配置字符串
1、在项目 中新增一个应用程序配置文件,增加如下XML代码。
<configuration>
<connectionStrings>
<add name="sql"connectionString=@"server=.\sqlexpress;database=test;uid=sa;pwd=zjt71305" /> <!--关键字区分大小写-->
</connectionStrings>
</configuration>
2、在项目中添加System.Configuration引用,并在主程序中引用命名空间system.confguration
3、在主程序中增加以下语句即可
string str=ConfigurationManager.ConnectionStrings["Sql"].ConnectionString;//这里的sql是在xml里定义的连接字符串的名字,可以随便取。
1.6、sqlhelp
即把ado.net的各种查询封装到类中。
classsqlhelper
{
privatestaticstringstr=ConfigurationManager.ConnectionStrings["str"].ConnectionString;
publicstaticint ExecuteNonyQuery( stringsql,CommandType comtype, paramsSqlParameter[] nums ) //加上commandtype可以选择执行的是存储过程还是普通SQL语句。
{
SqlConnection con = newSqlConnection(str);
using(con)
{
con.Open();
SqlCommand cmd = newSqlCommand(sql, con);
{
cmd.CommandType = comtype;
cmd.Parameters.AddRange(nums);
returncmd.ExecuteNonQuery();
}
}
}
publicstaticobjectExecuteScalar(string sql,CommandTypecomtype, paramsSqlParameter[]nums)
{
SqlConnection con = newSqlConnection(str);
using(con)
{
con.Open();
SqlCommand cmd = newSqlCommand(sql, con);
using (cmd)
{
cmd.CommandType = comtype;
cmd.Parameters.AddRange(nums);
return cmd.ExecuteScalar();
}
}
}
publicstaticSqlDataReader ExecuteReader(stringsql,CommandType comtype,paramsSqlParameter [] nums) //返回一个sqldatareader类型。
{
SqlConnection con = newSqlConnection(str);
//因为excutereader查询的结果是多条语句,所以数据库连接不能中断,此sqlhelper中,如加上using(con),则当返回return read后数据库会自动被dispose,而中断连接。所以此处不能加using自动dispose释放资源,要手工释放。
try
//因为excutereader执行时可能因为语句错误等原因没有结果,那么returnread时会拋异常,所以要用trycatch。而excutenonquery和excutescalar不管怎么样都会有返回值。
{
SqlCommand cmd = newSqlCommand(sql, con);
using (cmd)
{
//con.Open(); //可以不直接打开,先判断一下。
if(con.State==ConnectionState.Closed) //如果数据库没有打开,就打开数据库。
{
con.Open();
}
cmd.CommandType = comtype; //把执行的sql语句类型传进来。
cmd.Parameters.AddRange(nums); //增加参数
SqlDataReader read = cmd.ExecuteReader(CommandBehavior.CloseConnection);
//执行完read所有条目后,自动dispose,释放资源。commandbehavior的作用就是作了dispose动作。
returnread; //返回read
}
}
catch
{
con.Dispose(); //因为拋异常,数据库一直处理连接状态,所以要手工关闭数据库连接。
throw;
}
}
1.8sqldataadpeter(代替了connection的连接数据库,command的执行,sqldatareader的查执行结果,但不常用)
批量数据读取器。一次性查询一批数据出来后,存放到数据库的内存池中,而不是直接返给用户。然后用sqldataadpeter一次读一条出来,直到读完。
string sql = @"server=.\sqlexpress;database=loready;uid=sa;pwd=zjt71305"; //连接数据库string se="select count(*) from username "; //查询语句
sqldapeterdap=new sqldapeter(se,sql) //把查询语句和连接字符传给sqldapeter
using(dap)
{
Datasetds=new dastset(); //建立一个DATAset对象
Dap.fill(ds); //把查询到的结果填充到dataset对象中。
}