1、C#对 SQL 数据库操作总结 要对数据库进行查增删改操作,先要连接数据库,然后通过 command 类中相应方法或 Dataset 数据集中相应方法来完成对数据库的有关操作 一、创建数据库连接 (SqlConnection 类) 步骤: (1)定义连接字符串 (2)创建 SqlConnection 对象 1. 两种用户登录连接字串( Windwos 用户, SQL 数据库用户) string connString = “Data Source=HP;Initial Catalog=Xk;Integrated Security=True“;/windows 用户连接数据库字符串 string
2、connString =“Data Source=HP;Initial Catalog=xk;User ID=SA; PassWord=“;/SQL 用户连接字符串 2.创建 SqlConnection 对象 方法一: SqlConnection conn = new SqlConnection(connString); /带连接字符串实例化 SqlConnection 方法二: SqlConnection conn = new SqlConnection(); /实例化 SqlConnection conn.ConnectionString=connString; /把连接 字符串赋给 co
3、nn 对象的 ConnectionString 属性 3.打开连接 conn.open(); 4.关闭连接 conn.close(); 5创建连接例子 : string connString = “Data Source=HP;Initial Catalog=Xk;Integrated Security=True“;/windows 用户连接数据库字符串 SqlConnection conn = new SqlConnection(connString); /带连接字符串实例化 SqlConnection conn.open(); 二、 Sqlcommand 类操作数据库 使用 Command
4、 步骤: (1)创建数据库连接 (2)定义 SQL 语句 (3)创建 Command 对象 (4)执行命令 1、 command 类的构造方法 command 类的常用构造 方法有下面三种,使用不同的构造方法,创建对象的内容也有所不同 构造方法 说明 SqlCommand() 不带参数的构造函数 SqlCommand(string commandText) 带命令字 串的构造函数 SqlCommand(string commandText,SqlConnection mySqlConnection) 带命令字串及连接字串的构造函数 2、 command 类的主要成员 属 性 说 明 Conne
5、ction Command 对象使用的数据库连接 CommandType 设置如何解释 CommandText 值(即设置 CommandText 所代表的含义)。有三个选项( StoredProcedure 存储过程名, TableDirect 表名, Text SQL 文本命令),默认为 Text。 CommandText 执行的 SQL 语句 方法 说明 ExecuteNonQuery 执行不返回行的语句,如 SELECT,UPDATE,DELETE ExecuteReader 返回 DataReader 对象 ExecuteScalar 返回单个值,如执行 COUNT(*) 3、下 面
6、 举一些例子,学习过程中要举一返三 (1)SqlCommand()构造函 数、 ExecuteScalar 方法,查询学生人数 string connString = “Data Source=HP;Initial Catalog=Xk;Integrated Security=True“;/windows 用户连接数据库字串 SqlConnection conn = new SqlConnection(connString); /带连接字符串实例化 SqlConnection conn.open(); string SQLstring = “SELECT count(*) from Stude
7、nt“; SqlCommand command = new SqlCommand(); command.Connection = conn; command.CommandText = SQLstring; int num = (int)command.ExecuteScalar(); /执行 SQLsrting 查询语句,返回学生人数,注意要进行数据转换 (2) SqlCommand (String)构造函 、 ExecuteReader 方法读取学生信息 string connString = “Data Source=HP;Initial Catalog=Xk;Integrated Se
8、curity=True“;/windows 用户连接数据库字串 SqlConnection conn = new SqlConnection(connString); /带连接字符串实例化 SqlConnection conn.open(); string strQuery = “SELECT StuName,Sex ,BirthDay FROM dbo.Student“; SqlCommand command = new SqlCommand(strQuery); command.Connection = sqlConn; / 执行查询 SqlDataReader dataReader =
9、command.ExecuteReader(); string StuName = “” ; / 班级名称 string Sex=“” ; string BirthDay=“” ; / 循环读出所有的年级名,并添加到年级列表框中 while (dataReader.Read() StuName= (string)dataReader0;/读取第一单元的值 Sex = (string)dataReader1; /读取第二单元的值 BirthDay=(string)dataReader2; /读取第三单元的值 cboClass.Items.Add(className); dataReader.Cl
10、ose(); (3) 使用 SqlCommand (String, SqlConnection)构造函 数 、 ExecuteNonQuery 命令,插入修改删除记录 string connString = “Data Source=HP;Initial Catalog=Xk;Integrated Security=True“;/windows 用户连接数据库字串 SqlConnection conn = new SqlConnection(connString); /带连接字符串实例化 SqlConnection conn.open(); / strQuery 字符串可以用 insert 、
11、 updata、 delete 命令完成插改删功能。 string strQuery = “insert into student values(“01000061”,”20010005”,”张小明 ”,”男 ”,1982-01-01,”D053E238”); SqlCommand command = new SqlCommand(strQuery, connString); int logint=commnad.executNoQuery(); if (logint0) messagebox.show(“插入成功! ”); else messagebox.show(“插入不成功! ”); 三
12、、 DataSet 操作数据库 DataSet 类是 ADO.NET 中最核心的成员之一,也是各种开发基于 .Net 平台程序语言开发数据库应用程序最常接触的类。 在从数据库完成数据抽取后, DataSet 就是数据的存放地 ,它是各种数据源中的数据在计算机内存中映射成的缓存,所以 在脱机状态下,也能对 DataSet 中的数据表进行操作。 1 创建一个 DataSet 对象 a) 可以指定一个数据集的名称 b) 如果不指定名称,则默认被设为 “NewDataSet“ DataSet 数据集对象 = new DataSet(“数据集的名称字符串 “); 2 使用 DataAdapter 对象填
13、充数据集 (1) 创建 SqlDataAdapter 对象 SqlDataAdapter 对象名 = new SqlDataAdapter(查询用 sql 语句 , 数据库连接 ); (2) 填充 DataSet DataAdapter 对象 . Fill(数据集对象 , “数据表名称字符串 “); (3). 具体例子 string cnnstring = “Data Source=HP;Initial Catalog=Xk;Integrated Security=True“; SqlConnection sqlcnn = new SqlConnection(cnnstring); strin
14、g SQLsting = “select * from student “; da1 = new SqlDataAdapter(SQLsting, cnnstring); ds1= new DataSet(); da1.Fill(ds1, “student“); 注: sqlcnn 对象不需要 open 打开, 直接由 da1Fill 方法填充。 3 DataSet 数据集数据的编辑(增删改) DataSet 数据集一般是与数据控件绑定使用, 来 达到显示、修改、插入、删除数据记录。 但 只是对 DataSet 数据集做了插、删、改 。 并没有对数据库中的数据进行 插、删、改, 可以 通过 D
15、ataAdapter 对象操作 DataSet 实现更新数据库 DataAdapter 是通过其 Update 方法实现以 DataSet 中数据来更新数据库的。当 DataSet 实例中包含数据发生更改后,此时调用 Update 方法, DataAdapter 将分析已作出的更改并执行相应的命令( INSERT、 UPDATE 或 DELETE),并以此命令来更新数据库中的数据。如果 DataSet 中的 DataTable 是映射到单个数据库表或从单个数据库表生成,则可以利用 CommandBuilder 对象自动生成 DataAdapter 的 DeleteCommand、 Insert
16、Command 和 UpdateCommand。 SqlCommandBuilder mycbd = new SqlCommandBuilder(da1); /自动生成插删改命令 da1.Update(ds1.Tables“student“); 但上述命令只对单表数据集更新方便,对多表数据集不能操作。对于多表数据集的插、删、改操作,用 sqlcommand类来完成 (见 二、 Sqlcommand 类操作数据库 。 ) 4 DataSet 结构 DataSetDataTable集DataColumn集ColumnDataRow集Row5. DataSet 中 对 列、行相关 操作 DataSe
17、t ds; ( 1) 获取该 DATASET 中表的数量: ds.Tables.Count ( 2) 指定其中的一个表: ds.Tablesi /i 为 Table 在数组序列中的位置 (从 0 开始) 或 DataSet.Tables“表名 “; ( 3) 获取该表的记录数: ds.Tablesi.Rows.Count ( 4) 获取列数: ds.Tablesi.Columns.Count ( 5) 获取表中单元数据: ds.tables“表名 ”.Row“行号 ”“列名 ”.tostring 注意:要转换成相应的数据类型。 ( 6) 删除一行: dsTablesi.Rowsi.Delete
18、 ( ) ;只是对第 i+1(因为 序号 从 0 开始)行做删除标记 , 并没有直接移除第 0 行 。可以通过 RejectChanges 方法 回恢复删除标记。若要真正删除,则要用 AcceptChanges 方法 结束编辑状态。 ( 7) 直接删除一行 ds.Rows.RemoveAt(i),直接删除第 i+1(因为序号从 0 开始)行,不需用 AcceptChanges 方法 结束编辑状态。 ( 8) 插入一列: /先定义一行变量 datarow dr=ds.Tablesi.NewRow() /给行变量的不同字段赋值 dr“字段名 1”=值 1; dr“字段名 2”=值 2; - /通过
19、 Rows 的 Add 方法,新建的行增加到数据集中的表中去 ds.Tables“UserList“.Rows.Add(dr) ( 9) AcceptChanges 方法 AcceptChanges 方法提交自上次调用 AcceptChanges 以来对该表进行的所有更改。调用 AcceptChanges 时,任何仍处于编辑模式的 DataRow 对象将成功结束其编辑。 一般放在更改数据库命令之前。 ds. AcceptChanges(); da. Update(ds.tables0); ( 10) RejectChanges 方法 恢复数据 RejectChanges 方法回滚自该表加载以来
20、或上次调用 AcceptChanges 以来对该表进行的所有更改。调用 RejectChanges 时,任何仍处于编辑模式的 DataRow 对象将取消其编辑。 下面的程序,显示如何判断是否有错误发生: if(MyDataSet.HasErrors) ds.RejectChanges(); 首先我们检查 DataSet 中是否有错误发生,如果有就使用 RejectChanges()方法,恢复 DataSet 中的数据。注意这里恢复是在 DataSet 中所有表以及表中 DataRow 中的数据,也就是在此次操作的数据全部恢复。如果我们只需要恢复部分内容,我们可以使用 DataTable 或 D
21、ataRow 的 RejectChanges() ( 11) 探测 dataset 是否有改动 我们在将 dataset 送交给数据库去保存去,我们需要看看这个 dataset 是否已经被改动了。如果没有改动,我们也就没有必要去修改数据库了。 if(ds.haschanges) /保存 else /不进行任何操作 四、 Sqlcommand的 parameters 属性 利用 parameters 属性 处理 存储过程或 SQL 语句中的参数, 不但可以使代码清 晰 ,减少出错情况,更可减少可能的sql 注入。 1 SQL 语句拼接 ,容易被人为注入 string cnnstring = “D
22、ata Source=HP;Initial Catalog=Xk;Integrated Security=True“; string sqlstr = “select * from student where stuName=“ + textBox1.Text.ToString()+“; sqlstr += “ and pwd=“ + textBox2.Text.ToString()+“; SqlCommand mycmd = new SqlCommand(sqlstr, mycnn); mycnn.Open(); SqlDataReader myread=mycmd.ExecuteReade
23、r(); if (myread.Read() MessageBox.Show(“登录成功 “); else MessageBox.Show(“登录失败 “); 上述 SQL 语句是用字符串拼接来组的 .所以就有人想到如果我输入一个单引号来闭合原本程序里的单引号 , 然后在自己加些条件呢 , 如在密码输入 PWD 的值为 or 1=1,这样就被注入了 。轻易进入你的系统。 防范注入漏洞攻击的方法: 采用 SqlParameters 传递参数的方式 2.使用参数代替拼接 (1)使用 Sqlcommand 类的 parameters 属性 ,通过 add 方法直接添加命名参数 string cnns
24、tring = “Data Source=HP;Initial Catalog=Xk;Integrated Security=True“; sqlstr = “select * from student where stuName=stuName and pwd=pwd“ ; SqlCommand mycmd = new SqlCommand(sqlstr, mycnn); /添加命名参数到 ParametersCollection 集中 mycmd.Parameters.Add(“stuName“, SqlDbType.NChar, 8); mycmd.Parameters.Add(“pwd
25、“, SqlDbType.NChar, 10). /给命名参数赋值 mycmd.Parameters0.Value = textBox1.Text.ToString (); mycmd.Parameters1.Value = textBox2.Text.ToString(); /命名参数 与赋值可以合拼在一起 ,上述语句可写成以下两条 /mycmd.Parameters.Add(“stuName“, SqlDbType.NChar, 8).Value =textBox1.Text.ToString (); /mycmd.Parameters.Add(“pwd“, SqlDbType.NChar
26、, 10).Value = textBox2.Text.ToString(); mycmd.CommandText = sqlstr; mycmd.Connection = mycnn; mycnn.Open(); SqlDataReader myread=mycmd.ExecuteReader(); if (myread.Read() MessageBox.Show(“登录成功! “); else MessageBox.Show(“登录失败! “); (2) 使用 Sqlcommand 类的 parameters 属性 ,通过 add 方法添加一个 SqlParameter 对象 mycmd
27、.Parameters.Add(new SqlParameter (“stuName“, SqlDbType.NChar, 8); mycmd.Parameters.Add(new SqlParameter (“pwd“, SqlDbType.NChar, 10); mycmd.Parameters“stuName“.Value = textBox1.Text.ToString(); mycmd.Parameters“pwd“.Value = textBox2.Text.ToString(); (3) 通过 创建 SqlParameter 对象 数组来处理参数 在编写数据库访问类 的 方法时,
28、要传递参数,用 SqlParameter 数组来传递; 分两步骤: 建立 SqlParameter 对象 数组,并给数组元素赋值 把数组依次添加到 Sqlcommand 中的 Parameters 集中 /建立 SqlParameter 对象数组,并给数组元素赋值 sqlstr = “select * from student where stuName=stuName and pwd=pwd“; SqlParameter SQLpas =new SqlParameter (“stuName“, SqlDbType.NChar, 8), new SqlParameter (“pwd“, Sql
29、DbType.NChar, 10); SQLpas0.Value = textBox1.Text.ToString(); SQLpas1.Value = textBox2.Text.ToString(); 注意:由于 SQLpas 是数组,对数组的访问只能通过下标 ,下标必须是大于 0 的整数 /把数组依次添加到 Sqlcommand 中的 Parameters 集中 foreach (SqlParameter var in SQLpas) mycmd.Parameters.Add(var); 注: foreach 循环语句是用于遍历集合的,自动从集合中的第一个元素、第二个元素 到最后一个元
30、五、 带参数的存储过程 在开发数据库应用程序,在客 户 端对数据库的访问,为了数据的安全,通常编写存储过程,通过调用存储过程来对数据库 访问及 操作。 1. 在数据库中编写带参数的存储过程 为了方便记忆与使用 , 对于一个功能界面用一个存储过程 ,在存储过程中通过标识变量 if 语句及 type来区分要对数据库怎样的操作 ,type标识符的值采用“ 控件 +事件 +对 DB的操作描述 ” 定义。 Create PROCEDURE dbo.btnEdit type nvarchar(1)=,StuNo nvarchar(8)=,ClassNo nvarchar(8)=, StuName nvar
31、char(10)=,Sex nvarchar(1)=,BirthDay datetime=, Pwd nvarchar(8)= AS BEGIN if type =frmEdit Load selectStudent -格式:控件 +事件 +对 DB的操作描述 begin select stuNo,stuName,sex,birthday,pwd,className,student.ClassNo from student join class on student.ClassNo=Class.ClassNo where StuNo =stuNo end if type =btnSave_Cl
32、ick_saveStudent -格式:控件 +事件 +对 DB的操作描述 begin update Student set ClassNo=ClassNo,StuName=StuName,Sex =Sex , BirthDay=BirthDay,Pwd=Pwd where StuNo=StuNo end 2 SqlParameter 对象数组来处理参数 SqlParameter SQlpas = new SqlParameter(“type“,SqlDbType.NChar ,1), new SqlParameter(“stuNo“,SqlDbType.NChar ,8), new SqlP
33、arameter(“StuName“,SqlDbType.NChar ,10), new SqlParameter(“ClassNo“,SqlDbType.NChar ,8), new SqlParameter(“Sex“,SqlDbType.NChar ,1), new SqlParameter(“BirthDay“,SqlDbType.DateTime ), new SqlParameter(“Pwd“,SqlDbType.NChar,8) ; SQlpas0.Value = “2“; SQlpas1.Value =textBox1.Text.Trim().ToString(); SQlp
34、as2.Value = textBox2.Text.Trim().ToString(); SQlpas3.Value = cmbClass.SelectedValue; if (rdBtn1.Checked = true) SQlpas4.Value = “男 “; if (rdBtn2.Checked = true) SQlpas4.Value = “女 ?“; SQlpas5.Value = dateTimePicker1.Value; SQlpas6.Value = textBox4.Text.Trim().ToString(); /实例化类对象 DBClass.DBClass frmE
35、ditDB = new DBClass.DBClass(); /调用类的方法, 传递两个参数 int myop = frmEditDB.opdb(“btnEdit“, SQlpas); if (myop0) MessageBox.Show(“信息修改成功 !“); else MessageBox.Show(“信息修改失账 !“); 六、 常用控件 (一 ) ComboBox组合框 1、常用属性 及方法 : ( 1) DropDownStyle 属性,指定组合框的显示风格。 cmbclass.DropDownStyle = ComboBoxStyle.DropDown; /设置 ComboBox
36、 样式 ,有 S imply, DropDownList, /DropDown ( 2) Items 属性: 用于存放列表框中的列表项,是一个集合。通过该属性,可以添加列表项、移除列表项和获得列表项的数目。 在窗体上创建一 ComboBox,Name 属性值为 cmbClass; Add 方法添加项目 cmbclass.Items.Add(“教育会计学 “); /添加项目 cmbclass.Items.Add(“信息管理与信息系统 “); /添加项目 cmbclass.Items.Add(“电子商务 “); /添加项目 移 去项 cmbclass.Items.Remove(“电子商务 “);
37、/称去指定项 cmbclass.Items.RemoveAt(1); /移去指定索引处的项 获取列表项的数 MessageBox.Show(cmbclass.Items.Count.ToString() ); ( 3) SelectedIndex 属性:用来获取或设置 ComboBox 控件中当前选定项的从零开始的索引。如果未选定任何项,则返回值为 -1 ( 4) SelectedItem 属性:获取或设置 ComboBox 中的当前选定项。 cmbclass.SelectedIndex = 0; /通过索引,设置当前选定项 MessageBox.Show(cmbclass.SelectedI
38、tem.ToString() ); /获取当前选定项 看执行结果是怎样? cmbclass.Items.Add(“教育会计学 “); /添加项目 cmbclass.Items.Add(“信息管理与信息系统 “); /添加项目 cmbclass.Items.Add(“电子商务 “); /添加项目 cmbclass.SelectedIndex = 0; /通过索引,设置当前选定项 cmbclass.Text = “1 电子商务 “; /设置关联项,若该项在项目集中,则作为当前选定项; /若该项不在项目集中,则只表示关联。 cmbclass.Items.Remove(“电子商务 “); /移去指定项
39、 cmbclass.Items.RemoveAt(1); /移去指定索引处的项 MessageBox.Show(cmbclass. SelectedIndex.ToString() ); /获取当前选定项 2与数据源绑定 ( 1) .DataSource 属性:获取 或 设置数据源 ( 2) .DisplayMember:获取或设置显示属性 ( 3) .ValueMember:获取或设置 值属性 ( 4) .SelectedValu:获取或设置 ValueMember 指定成员的属性的值 例: /ds1 是一数据集,数据集中有一班级表 cmbClass.DataSource = ds1.Tab
40、les0; /绑定数据源 cmbClass .DisplayMember =ds1.Tables0.Columns“className“.ToString();/设置 combox 的显示属性 cmbClass.ValueMember = ds1.Tables0.Columns“classNo“.ToString(); /设置 combox 的实 际值 问下列语句显示的值是? MessageBox.Show(cmbClass.SelectedValue.ToString(); 3 绑定 DGV中的 ComboBoxColumn列 /绑定 DGV中的 ComboBoxColumn列 SQLsti
41、ng = “select * from class“; da2 = new SqlDataAdapter(SQLsting, cnnstring); ds2 = new DataSet(); da2.Fill(ds2, “class“); (DataGridView ComboBoxColumn)this.dgv1.Columns“classNO“).DataSource = ds2.Tables“class“; (DataGridView ComboBoxColumn)this.dgv1.Columns“classNO“).DataPropertyName = “classNO“; (Dat
42、aGridView ComboBoxColumn)this.dgv1.Columns“classNO“).DisplayMember = “className“; (DataGridView ComboBoxColumn)this.dgv1.Columns“classNO“).ValueMember = “classNo“; 注: DataGridView Column的值有: DataGridView ButtonColumn、 DataGridView CheckBoxColumn、 DataGridView ComboBoxColumn、 DataGridView TextBoxColu
43、mn等六种。 (二) DataGridView控件 1. DataGridView绑定数据源 cnnstring = “Data Source=(local);Initial Catalog=Xk;Integrated Security=True“; SqlConnection sqlcnn = new SqlConnection(cnnstring); string SQLsting = “select * from student “; da1 = new SqlDataAdapter(SQLsting, cnnstring); ds1 = new DataSet(); da1.Fill(
44、ds1, “student“); dgv1.DataSource = ds1.Tables“student“; /绑定到 DGV1 2.常用属性及方法 (1) 设置 DataGridView奇数行的样式 只要设置 AlternatingRowsDefaultCellStyle属性的值。 (2) DataGridView取得或者修改当前单元格的内容: 通过 DataGridView对象的 CurrentCell 属性取得。如果当前单元格不存在的时候,返回 Nothing(C#是 null) / 取得当前单元格内容 MessageBox.Show(dgv1.CurrentCell.Value.To
45、String(); / 取得当前单元格的列 Index MessageBox.Show(dgv1.CurrentCell.ColumnIndex.ToString(); /取得当前单元格的行 Index MessageBox.Show(dgv1.CurrentCell. RowIndex.ToString(); /取得当前单元格的行列坐标 MessageBox.Show(dgv1.CurrentCellAddress.Y.ToString(); MessageBox.Show(dgv1.CurrentCellAddress.x.ToString(); / 设定 (0, 0) 为当前单元格 (活
46、动单元格 ) dgv1.CurrentCell = dgv1 0, 0; / 向下遍历 行 private void button1_Click(object sender, EventArgs e) int row=dgv1.CurrentRow.Index +1; /获取当前单元格行索引 +1,就是下一行 if (row dgv1.Rows.Count -1) /判定是否到了最后一行的下一行 ,是的话则返回到 0行 . row = 0; dgv1.CurrentCell = dgv10,row ; 问题 .向上遍历行如何写 ? (3) DataGridView 设定单元格只读 : 1) 使
47、用 ReadOnly 属性 如果希望, Dgv1 内所有单元格都不可编辑, 那么只要: / 设置 dgv1 为只读 dgv1.ReadOnly = true; 此时,用户的新增行操作和删除行操作也被屏蔽了。 / 设置 Dgv1 的第 2 列整列单元格为只读 Dgv1.Columns1.ReadOnly = true; / 设置 Dgv1 的第 3 行整行单元格为只读 Dgv1.Rows2.ReadOnly = true; / 设置 Dgv1 的 0, 0单元格为只读 Dgv10, 0.ReadOnly = true; 2) 使用 EditMode 属性 DataGridView.EditMod
48、e 属性被设置为 DataGridView EditMode.EditProgrammatically 时,用户就不能手动编辑单元格的内容了。但是可以通过程序,调用 DataGridView.BeginEdit 方法,使单元格进入编辑模式进行编辑。 /设置单元格 进入编辑模式进行编辑 Dgv1.EditMode = Dgv1EditMode.EditProgrammatically; (4) DataGridView 不显示最下面的新行: 通常 DataGridView 的最下面一行是用户新追加的行(行头显示 * )。如果不想让用户新追加行即不想显示该新行,可以将 DataGridView 对象的 AllowUserToAddRows 属性设置为 False。 / 设置用户不能手动给 DataGridView添加新行 Dgv1.AllowUserToAddRows = false