学习目的:通过程序访问数据库 ,ADO.NET就是一组类库,
--》connection 用来连接数据库的类
语法:首先需要一个连接字符串
-->以SQL server身份验证连接
string sqlconnection=@"Data Source=实例名服务名;Initial Catalog=数据库名;User Id=用户名;PassWord=密码";
--》以windows身份验证连接
string sqlconnection=@"Data Source=实例名服务名;Initial Catalog=数据库名;Integrated security=true";
然后需要一个连接对象
SqlConnection con=new SqlConnection(连接字符串) --connection是对硬盘的数据进行处理所以要释放资源,调用close(),dispose()方法或using()
打开连接用Open()
连接都需要Dispose()
查看连接状态用 State 连接打开会返回true,否则返回false
-->Command 用来执行SQL语句
首先需要一句SQL语句
string sql="insert 。。。。。";
然后需要一个执行对象 (也需要释放资源)
SqlCommand cmd=new SqlCommand(Sql语句)
SqlCommand需要提高SQL语句和一个连接通道(就是连接对象)
常用的三个方法
--》ExecuteNonQuery() 处理增(insert)、 删(delete/drop)、 改(update/alter),返回受影响行数,不可以处理查询
--》ExecuteScalar() 处理查询,返回首行首列的值,值返回一个值,增、删、改也可以执行但是返回的值永远是-1
--》ExcuteReader() 处理查询,返回DataReader对象
一、ADO.NET其实就是一个类库
专门用来处理数据库的类库
System.Data下还有很多命名空间
odbc
oledb
sqlClient
注:推荐《ADO.Net 2.0 技术内幕》
2、数据库(数据库管理软件)
->SQL Server 2008
->架构(dbo.Table)
->数据库
-》表
--》使用时先要连接到SQL Server
首先要连接字符串
SQL Server身份验证
server=机器名/实例名;database=数据库;uid=sa;pwd=密码
windows身份验证
Data Source=机器名/实例名;Initial Catalog=数据库名;Integrated security=true=true
3、使用ADO.Net连接的时候,需要使用一个SqlConnection的对象只起到连接数据库
-》第一步准备连接字符串
string strcon=@"Data Source=./sqlexPRess;Initial Catalog=MyName;User Id=sa;Password=1234";
->准备连接通道
引用命名空间 system.Data.sqlclient;
SqlConnection con=new SqlConnection(strcon);
->Open进行打开连接 (尽可能晚的打开,尽可能早的关闭)
-》关闭连接
Close()
释放资源
Dispose()
4、执行SQL语句
SqlCommand对象
-》首先需要一个SQL语句
-》需要一个连接对象
SqlCommand cmd=new SqlCommand(Sql语句,连接通道)
1、SqlCommand有三个常用的执行SQL语句的方法
-》ExecuteNonQuery
一般执行得到返回受影响行数的方法
-》一般处理增、删、改等操作
-》返回一个值,受影响行数,如果执行查询的SQL语句返回-1
2、 ExecuteSalar
执行查询,会返回查询结果集的第一行第一列对应的值,其他行其他列会忽略掉,一般使用聚合查询时只要得到一个结果用到
返回值是一个Object类型,需要转换(拆箱),转换时用convert,不要强转,有时候会返回字符串形式的数字,强转的话会出错,得不到结果
--》得到自动增长ID
在添加数据的时候,在values前使用 output inserted.主键字段
insert into 表名 (字段1,字段2..) output inserted.主键名 values(值1,值2....)
2、 SqlDataReader
当ExecuteReader执行的时候会通过SqlConnection连接通道连接数据库然后把SQL语句传过去,数据库里有一个SQL server执行引擎,这个引擎会解析传进来的SQL语句然后执行,
到数据库里查找数据,查找到数据之后不是一次性全都拿出来倒到内存里,这个引擎有个临时缓存,它会先拿一部分的数据到这个临时缓存里,然后等待应用程序(客户端)执行read()进行读取数据
-->HasRows()
判断是否有数据,返回一个BOOL值,不会连接数据库
-->Read()
读取查到的数据,每执行一次Read,这个指向数据的“标记”由SqlDataReader对象控制,这个“标记“就会下移一次,
如果有数据,就返回一个truename可以使用Get...方法获得对应列上的数据,如果下移以后没有数据,那么就返回一个false
注:使用get方法的时候如果用的不是object 类型接收,如果数据是null会抛异常,
获取值通过列号来获取,列号从0开始
-->GetValue(列号) 获得指定列好号对应的值
--》getint32(列号) 获得指定列号的整形形式的值
--》getstring(列号) 获得指定列号的字符串 形式的值
.......
--》还可以直接通过下标形式来获取值
SqlDataReader对象[列号]
二、注入漏洞攻击
对于用户登录的实现,提供SQL语句
--》使用字符串拼接,不安全,有漏洞,如果输入密码为:1‘ or '1'='1 这时候数据库解析SQL语句会把后面的or当做一个条件,那么’1‘=’1‘永远成立
select * from 表名 where Uid=‘{0}’ and pwd=‘{1}’
--》使用参数查询
select * from 表名 where Uid=@name and pwd=@pwd
再通过执行对象SqlCommand提供的属性parameters属性调用Add方法给变量赋值,不使用时记得清空
cmd.parameters.AddWithValue("@name",值) --这时候 1‘ or '1'='1 就会整个被当做一个值赋给pwd,不会再被解析成一个条件
ExecuteReader的执行
public static class SQLHelper { //连接字符串,readonly--》读取进来就不可改变 private static readonly string sqlcon = ConfigurationManager.ConnectionStrings["sql"].ConnectionString; /// <summary> /// 连接SQL语句,返回受影响行数 /// </summary> /// <param name="sql">要执行的T-SQL语句</param> /// <param name="par">SQL语句的参数</param> /// <returns>受影响行数</returns> public static int ExecuteNonQuery(string sql, params SqlParameter[] par) { if (sqlcon == null) { throw new Exception("没有连接字符串"); } using (SqlConnection con = new SqlConnection(sqlcon)) { using (SqlCommand cmd = new SqlCommand(sql, con)) { if (con.State == System.Data.ConnectionState.Closed ) { con.Open(); } if (par!=null) { cmd.Parameters.AddRange(par); } return cmd.ExecuteNonQuery(); } } } /// <summary> /// 执行查询,返回执行查询的结果集的第一行第一列 /// </summary> /// <param name="sql">要执行的T-SQL语句</param> /// <param name="par">T-SQL语句里的参数</param> /// <returns></returns> public static object ExcuteScalar(string sql, params SqlParameter[] par) { using (SqlConnection con = new SqlConnection(sqlcon)) { using (SqlCommand cmd = new SqlCommand(sql, con)) { if (par!=null) { cmd.Parameters.AddRange(par); } if (con.State == System.Data.ConnectionState.Closed ) { con.Open(); } return cmd.ExecuteScalar(); } } } public static SqlDataReader ExecuteReader(string sql, params SqlParameter[] par) { SqlConnection con = new SqlConnection(sqlcon); using (SqlCommand cmd = new SqlCommand(sql, con)) { if (par!=null) { cmd.Parameters.AddRange(par); } if (con.State == System.Data.ConnectionState.Closed ) { con.Open(); } return cmd.ExecuteReader(System.Data.CommandBehavior .CloseConnection); } } public static DataTable ExecuteDataTable(string sql, params SqlParameter[] par) { using (SqlDataAdapter ada = new SqlDataAdapter(sql, sqlcon)) { //SqlDataAdapter内部hui 创建yige SqlCommand对象, //直接通过SqlDataAdapter的selectCommand属性就可以调到 if (par!=null) { ada.SelectCommand.Parameters.AddRange(par); } DataTable ta = new DataTable(); ada.Fill(ta); return ta; } } }
--=======================SQLHelper实现省市联动案例===================================
private void Form1_Load(object sender, EventArgs e) { string ssql = "select proid,proName from promary "; using (SqlDataReader reader = SQLHelper.ExecuteReader(ssql)) { if (reader.HasRows) { while (reader.Read()) { Area temp = new Area(); temp.AreaId = reader.GetInt32(0); temp.AreaName = reader.GetString(1); comboBox1.Items.Add(temp); } } } comboBox1.SelectedIndex = 0; } private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { comboBox2.Items.Clear(); int r = ((Area)comboBox1.SelectedItem).AreaId; string sql = "select cityName from city where proid=@pid"; using (SqlDataReader reader = SQLHelper.ExecuteReader(sql, new SqlParameter("@pid", r))) { if (reader.HasRows) { while (reader.Read()) { Area shi = new Area(); shi.AreaName = reader.GetString(0); comboBox2.Items.Add(shi); } } } comboBox2.SelectedIndex = 0; } }// 封装一个类 把数据库表里的每一行的数据都看成是这个类的一个对象 class Area { public int AreaId { get; set; } public string AreaName { get; set; } public override string ToString() { return AreaName; } }
一、SQLHelper
实际上就是你自己封装的方法,专门用来执行增删改查等操作
没有SQLHelper之前反反复复的写
--》使用连接对象、命令对象、读取器等,都是重复的代码
--》实际上自己封装成方法即可,但是由于数据库的操作都一样,因此可以将其封装成类库进行调用
1)SqlParameter
当SqlParameter的第二个参数是数字时,需要考虑是哪一个重载,常用的有两个
--》一个是object Value
--》一个是sqlDbType 是一个枚举,由于枚举本身就是个数字,如果第二个参数直接传个数字,那么这个数字和枚举就冲突了,可能会出错,为了避免出错当第二个参数是数字的时候要转换成object类型
SqlParameter par= new SqlParameter("@num", SqlDbType.Int);
par.Value =0;
二、Case函数
需要在哪里控制显示就在谁的前面加case
两个版本
-->等价于switch-case结构
case 字段
when 值 then 替换值,
when 值 then 替换值
...
else 替换值
end
--》if-else if结构
case
when 表达式 then 值
when 表达式 then 值
else 值
end
select
name 单号,
case
when [money]>0 then [money]
else 0
end as 收入,
case
when [money]<0 then abs( [money])
else 0
end as 支出
from FTable
三、子查询
就是将查出来的结果集,作为一个数据源 (就是在一个结果集的基础上再做其他的查询)
结果集就是查询出来具有满足一些特定的格式的结果
结果集的特征
--》单值结果集 就是只有一行一列的结果集
--》行结果集 顾名思义就是只有一行,可以有多列。或者只有一列,可以有多行
--》表结果集 就是查询出来的整张表有多行多列
--查询某个班级的所有学生
select * from TStudent where classid IN(select classId from TClass where cName='.net学院' and cDescription='就业班')
-- 查询某些学生的成绩
select * from TScore where scoreid in (select scoreid from TStudent WHERE sName ='安半青')
--快速实现删除多个学生
delete from TStudent where classid in (select classId from TClass where cName='C++学院' and cdescription='基础班')
--查询学生表中最高分与最低分和平均分
select
(select max(math) from TsCore)as 最高分,
(select min(math) from TsCore)as 最低分,
(select AVG(math) from TsCore)as 平均分
select * from (select studentid from TStudent where studentId between 1 and 5)
use MyName
go
select * from dbo.LobinTable
select top 5 * from MyStudent where Fid not in(select top (5*2) Fid from MyStudent )
一、case 两种语法
switch-case 结构
---》 case 字段
when 值 then 显示的值
when 值 then 现实的值
else 显示的值
end
if-else if
--> case
when 表达式 then 现实的值
when 表达式 then 显示的值
else 显示的值
end
2、子查询就是将结果集作为数据源
select 字段
3、联合
union
-->将两个结果集缝到一起
二、连接 Join
将两张表或多张表做为数据源
语法:
内连接,两张表中,如果有没有数据的记录(行),则不显示
select 字段 from //这里不建议用* 你不需要的信息显也示出来 ,这里可以通过下面给表起的别名 table1.字段 来显示要显示的列
表1 as table1
inner Join
表2 as table2
on table1.外键=table2.主键 (迪卡尔积:table1的外键分别会连接table2的每一个主键,把两个键相等的都连接起来)
select t1.studentId,t1.sName,t1.sAge,t1.sGender,t2.cName,t2.cDescription from
TStudent as t1
inner join
TClass as t2
on t1.classid=t2.classId
--------------案例------------------ 内连接如果某条记录的外键是空的或者这个记录的外键没有在主键表上,那么这个记录就不会被显示出来
4 韦天磊 74 1 .Net学院 就业班
32 童凡霜 79 0 .Net学院 就业班
42 惠尔蝶 30 0 .Net学院 就业班
44 夏侯哲瀚 88 1 .Net学院 就业班
49 訾烨伟 64 1 .Net学院 就业班
52 巴诗双 73 0 .Net学院 就业班
102 仲孙冰巧 58 0 .Net学院 就业班
114 曾雅柔 93 0 .Net学院 就业班
136 任炎彬 30 1 .Net学院 就业班
181 杨天佑 76 1 .Net学院 就业班
230 姜元枫 29 0 .Net学院 就业班
左外连接 left join
以左边的表为主,如果左边的表的外键是空的或者是主键表上没有这个记录的值,那么对应的右边的表(主键表)的数据就是空的
select t1.studentId,t1.sName,t1.sAge,t1.sGender,t2.cName,t2.cDescription from
TStudent as t1
left join
TClass as t2
on t1.classid=t2.classId
------------案例------------
1001 李四 20 1 2012-06-11 11:14:39.833 0 NULL NULL NULL NULL NULL
980 扈绮琴 7 0 2012-06-09 19:43:00.873 0 980 1 1 .Net学院 就业班
944 胥易蓉 17 0 2012-06-09 19:43:00.490 0 944 1 1 .Net学院 就业班
954 万文昊 67 1 2012-06-09 19:43:00.603 0 954 1 1 .Net学院 就业班
956 郤伟宸 96 1 2012-06-09 19:43:00.620 0 956 1 1 .Net学院 就业班
962 劳博超 89 1 2012-06-09 19:43:00.673 0 962 1 1 .Net学院 就业班
964 陶烨伟 44 1 2012-06-09 19:43:00.690 0 964 1 1 .Net学院 就业班
865 吕煜城 93 1 2012-06-09 19:42:59.773 0 865 1 1 .Net学院 就业班
884 茹翠风 51 0 2012-06-09 19:42:59.947 0 884 1 1 .Net学院 就业班
904 辛修洁 67 1 2012-06-09 19:43:00.130 0 904 1 1 .Net学院 就业班
右外连接 right join
一右边的表为主,如果左边的表的记录外键是空的或者是主键表上没有这个记录的值,那么对应的左边的表(外键表)的数据就是空的
select * from
TStudent as t1
right join
TClass as t2
on t1.classId =t2.classId
-------------------案例------------------
576 丁南莲 86 0 2012-06-09 19:42:56.890 0 576 14 14 Web学院 基础班
585 慕容迎梦 46 0 2012-06-09 19:42:56.973 0 585 14 14 Web学院 基础班
527 袁靖琪 67 1 2012-06-09 19:42:56.360 0 527 14 14 Web学院 基础班
524 宓鹏飞 97 1 2012-06-09 19:42:56.293 0 524 14 14 Web学院 基础班
545 于凌翠 47 0 2012-06-09 19:42:56.590 0 545 14 14 Web学院 基础班
609 竺志泽 15 1 2012-06-09 19:42:57.260 0 609 14 14 Web学院 基础班
638 莘以云 50 0 2012-06-09 19:42:57.530 0 638 14 14 Web学院 基础班
680 万俟晓博 23 1 2012-06-09 19:42:57.950 0 680 14 14 Web学院 基础班
NULL NULL NULL NULL NULL NULL NULL NULL 15 Web学院 黑马班
NULL NULL NULL NULL NULL NULL NULL NULL 16 狗屁学院 白马班
多表连接
select * from
TStudent as t1
right join
TClass as t2
inner join
TScore as t3
on t1.classId =t2.classId
inner join
......
可以一直练下去
-----------------------案例----------------------------
select t1.studentId,t1.sName,t1.sAge,t1.sGender,t2.cName,t2.cDescription,t3.chinese,t3.english,t3.math from
TStudent as t1
inner join
TClass as t2
on t1.classId =t2.classId
inner join
TScore as t3
on t1.scoreId =t3.scoreId
1 章夏槐 9 0 java学院 黑马班 69 132 99
3 符梦琪 50 0 .Net学院 基础班 148 85 50
4 韦天磊 74 1 .Net学院 就业班 14 33 134
5 璩伟祺 32 1 Java学院 就业班 144 43 121
6 滑烨磊 1 1 Java学院 就业班 73 130 103
7 柴傲柏 36 0 C++学院 就业班 98 8 57
8 梅天荷 14 0 Web学院 就业班 96 43 99
9 左雅彤 91 0 C++学院 就业班 88 80 44
10 东方香寒 17 0 Java学院 黑马班 32 146 11
12 麹博涛 42 1 .Net学院 黑马班 30 142 114
新闻热点
疑难解答