第四天 -- 《2014-07-09 ADO》 -- DataReader多结果集的读取、参数化查询、ComboBox下拉列表的数据绑定
一、上午《01、数据库操作流程》--《06、NextResult》
1、杂项
<1>每个Winform控件有一个ContextMenuStrip属性,可以为它指定已创建的右键菜单。
<2>数据库中的数值,被DataReader读取过来后已经被装箱。而我们需要将数据拆箱,注意拆箱操作只能拆到原始的数据类型。(比如把int装箱object,后者只能拆箱为int。假如希望转换为double,那必须(double)(int)obj,即拆箱完再转换。)
2、读取多个结果集时,使用DataReader.NextResult
SqlCommand命令的sql语句可以是多条语句。例如“select * from grade; select * from student;”这样服务器会返回两个结果集。我们用DataReader读取完第一个结果集后,可以使用NextResult判断是否存在下一个结果集,如果存在,读取器会自动指向下一个结果集开始位置,然后我们再通过Read()方法去读取。如:
1 ... 2 3 conn.Open(); 4 string sql = "select subjectid,subjectname,classhour,classid from subject; select stuname from student"; 5 SqlCommand comm = new SqlCommand(sql,conn); 6 //创建这个对象,相当于向服务器请求数据,服务器会将响应,将数据存储到服务器的缓存中。你还需要通过某种方式去服务器缓存中读取出数据 7 SqlDataReader reader = comm.ExecuteReader(); 8 while (reader.Read()) 9 {//Read():判断有没有下一行记录,如果有就将读取指针移动到下一行记录,同时将这一行记录的数据读取到reader对象的_data数组。数组是一私有数组,通过方法或者索引器进行访问 10 11 if (! (reader["classid"] is DBNull)) 12 {//数据库中的null读取到c#后就被封装为DBNull类型 13 int cid = Convert.ToInt32(reader["classid"]); 14 } 15 16 //先创建主项,再为主项添加子项 17 ListViewItem lv = new ListViewItem(reader.GetInt32(0).ToString()); 18 lv.SubItems.AddRange(new string[]{reader["subjectname"].ToString(),reader["classhour"].ToString(),reader["classid"].ToString()}); 19 this.lvSubejct.Items.Add(lv); 20 } 21 if(reader.NextResult()) 22 {//判断有没有下一个结果集,如果有就将读取指针移动到下一个结果集 23 while(reader.Read()) 24 { 25 ListViewItem lv = new ListViewItem(reader[0].ToString()); 26 lv.SubItems.Add(reader[1].ToString()); 27 this.listView1.Items.Add(lv); 28 } 29 } 30 31 ...
二、上午《07、数据库中的null读取到c#后就被封装为DBNull类型》
1、C#中的null与数据库中的null根本是两个概念
C#中的null表示空引用。引用类型变量为null表示不指向(不引用)堆上的任何对象实例。而数据库中的null表示未知数据(即该数据未录入),数据库中根本就没有引用类型这种概念。
当数据库的null被DataReader读取后,会创建一个System.DBNull类型的对象来表示它。因为DataReader读取的数据都为object类型,我们在做数据转换的时候,需要用DataReader.IsDBNull()来判断是否是DBNull(当然也可以用if (xxx is DBNull) 来判断)。是DBNull的话不可以强制转换,否则会报转换失败的异常(DBNull转成其他数值都抛异常,转字符串得到String.Empty对象,即空字符串)。
三、上午《08、参数化查询》
1、sql字符串注入漏洞(sql拼接的漏洞)
举一个sql注入漏洞的小例子:

2、ADO.NET的参数化查询解决上面的漏洞
<1>sql语句要使用参数化查询语句
<2>为SQLCommand添加SqlParamter
1 //1.定义参数占位 @参数 相当于在sql中创建一个变量,所以也不需要使用' '引号包含 2 string sql = "select count(*) from [user] where username=@name and pwd=@pwd"; 3 //2.在c#中创建对应的 参数对象.参数名称不区分大小写.第一个参数是指对应的形参名称,第二个参数是指你需要赋的值 4 SqlParameter p = new SqlParameter("@name", txtName.Text.Trim()); 5 SqlParameter p2=new SqlParameter("@pwd", txtPwd.Text.Trim()); 6 7 SqlCommand comm = new SqlCommand(sql, conn); 8 //3.还需要将创建好的参数传递的服务器让其使用。所以让comm对象将参数一起传递过去 9 comm.Parameters.Add(p); 10 comm.Parameters.Add(p2); 11 12 int num = (int)comm.ExecuteScalar();//执行命令,获取Count计数 13 14 if (num > 0) 15 { 16 MessageBox.Show("登录ok"); 17 } 18 else 19 { 20 MessageBox.Show("登录失败"); 21 }
四、下午《01、数据的导入和导出》--《02、如何插入数据库null》
1、参数化查询,将数据库null插入记录,如下例子(代码片段):
1 string sql = "insert into [user] values(@username,@pass,@email,@phone)"; 2 SqlParameter[] ps = 3 { 4 new SqlParameter("username",txtName.Text.Trim()), 5 new SqlParameter("pass",txtPwd.Text.Trim()), 6 new SqlParameter("email",string.IsNullOrEmpty(txtEmail.Text.Trim())? DBNull.Value:(object)txtEmail.Text.Trim()), 7 new SqlParameter("phone",string.IsNullOrEmpty(txtPhone.Text.Trim())? DBNull.Value:(object)txtPhone.Text.Trim()) 8 }; 9 SqlCommand comm = new SqlCommand(sql, conn); 10 comm.Parameters.AddRange(ps); 11 int num = comm.ExecuteNonQuery();
注意:在本例代码第6、7行创建SqlParameter时,要提供一个object类型的对象。虽然C#中所有类型都继承自object类型,但DBNull.Value是DBNull类型(DBNull继承自object),txtEmail.Text.Trim()返回的是String类(String继承自object)对象。三元操作符 ?: 要求冒号两边对象的类型能够隐式转换,显然DBNull与String不能隐式转换。所以需要先将后者强制转到object,这样就和DBNull有了隐式转换关系(即DBNull可以隐式转换到object)。
五、下午《03、初步实现省市级联》--《04、使用实体类对象做为下拉列表的项》
1、Winform的ComboBox添加实体类对象时,指定显示的属性值
1 class Student 2 { 3 public int Id{get;set;} 4 public string Name{get;set;} 5 public int Age{get;set;} 6 } 7 8 9 ... 10 Student stu = new Student { Id = 1, Name = "小明", Age = 10 }; 11 cbx_Student.DisplayMember = "Name";//指定下拉列表显示对象的Name属性值,注意"Name"可以不区分大小写。 12 cbx_Student.Items.Add(stu); 13 ... 14 15 16 private void cbx_Student_SelectedIndexChanged(object sender, EventArgs e) 17 { 18 int id = (cbx_Student.SelectedItem as Student).Id;//因为ComboBox的每个项都是Student对象。所以可以在这里转换过来 19 txt_Id.Text = id.ToString(); 20 }
2、Winform的ComboBox可以直接绑定实体类对象的集合(即指定ComboBox.DataSource属性)
1 ... 2 List<Student> list = new List<Student>(); 3 for (int i = 0; i<10; i++) 4 { 5 Student stu = new Student { Id = 1 + i, Name = "小明" + i, Age = 10 }; 6 list.Add(stu);//为列表添加若干实体对象 7 } 8 cbx_Student.ValueMember = "Id";//下拉列表项被选中后,选中的值是对象的哪个属性的值。 9 cbx_Student.DisplayMember = "Name";//下拉列表显示的对象属性 10 cbx_Student.DataSource = list;//指定数据源。注意要先指定上面两个属性,再绑定数据源 11 ... 12 13 14 private void cbx_Student_SelectedIndexChanged(object sender, EventArgs e) 15 { 16 int id = (int)cbx_Student.SelectedValue;//选中值实际上就是实体对象的Id值 17 txt_Id.Text = id.ToString(); 18 }
浙公网安备 33010602011771号