一、DataTable
1、一个DataSet中可以有多个DataTable,一个DataTable中可以有多个DataRow。组合一起就是一个虚拟的数据库结构。在程序中,DataTable就是一张表,可以给他定义各种数据类型的列。然后给他赋值,和数据库中的表的作用是一样的。唯一不同的是:他的数据是虚拟的。
用datatable,我们看U层显示代码:
//rows代表行,cell代表第几个格
dataGridView1.Rows[i].Cells[1].Value = table.Rows[i][1]; dataGridView1.Rows[i].Cells[2].Value = table.Rows[i][8]; dataGridView1.Rows[i].Cells[3].Value = table.Rows[i][2]; dataGridView1.Rows[i].Cells[4].Value = table.Rows[i][3]; dataGridView1.Rows[i].Cells[5].Value = table.Rows[i][4]; dataGridView1.Rows[i].Cells[6].Value = table.Rows[i][5]; dataGridView1.Rows[i].Cells[7].Value = table.Rows[i][6]; dataGridView1.Rows[i].Cells[8].Value = table.Rows[i][7];
2、DataTabel的弊端 当我们从数据库中查到结果以后显示在我们窗体上的代码,从上面的代码我们可以看出,我们必须清楚的知道数据库中字段名对应的位置,这样就和数据库的耦合性太大,这在我们编程中是特别忌讳的,另外它不符合面向对象的思想而更倾向于面向过程,尤其是当我们数据库表中的字段非常多的时候,会给我们带来困难。每个属性都要对应好具体的字段,否则就出错,如果数据库中的属性够多,难道我们还要一个个对应写上吗?显然这样做费时费力,效率很低,所以就引进了泛型集合list。
二、泛型list1、理解: 集合中的每个元素都是一个实体,而每个实体都相当于DataTable中的一条记录,DataTable是多条记录的集合,而list<>是多个实体的集合。U层代码:
Facade.Stufacade facade = new Facade.Stufacade(); List<Entity.StuLineBalance> mylist = new List<Entity.StuLineBalance>(); mylist = facade.InquiryBalance(user); if (mylist.Count > 0)
{
//调用数据库信息进行赋值 txtStudentNo.Text = mylist[0].sNo.ToString(); txtName.Text = mylist[0].sName.ToString(); txtSex.Text = mylist[0].sex.ToString(); textBox7.Text = mylist[0].department.ToString(); txtGrade.Text = mylist[0].grade.ToString(); txtClass.Text = mylist[0].Class.ToString(); txtBalance.Text = mylist[0].balance.ToString(); txtState.Text = mylist[0].status.ToString(); }
2、泛型的好处:
(1)遍历方便,取的是单个实体,无需拆装箱,查询方便;
(2)减少输入,只需要一个实例T就可以获取它的任何属性;
(3)正确构建泛型类,可以减少代码中的安全问题;
(4)工作量小,提升系统性能。
3、(1)如何转为泛型?(2)D层调用:public static class DatatableConvert<T> where T : new() { /// <summary> /// 把datatable转为list /// </summary> /// <param name="dt">datatable</param> /// <returns>list泛型集合</returns> public static List<T> ConvertToModel(DataTable dt) { // 定义集合 List<T> ts = new List<T>(); // 获得此模型的类型 Type type = typeof(T); //定义一个临时变量 string tempName = ""; //遍沥该对象的所有属性 foreach (DataRow dr in dt.Rows) { T t = new T(); // 获得此模型的公共属性 PropertyInfo[] propertys = t.GetType().GetProperties(); //遍沥该对象所有属性 foreach (PropertyInfo pi in propertys) { //将属性名称赋值给临时变量 tempName = pi.Name; //检查DataTable是否包含此列(列名=对象的属性名) if (dt.Columns.Contains(tempName)) { // 判断此属性是否有Setter if (!pi.CanWrite) continue; //取值 object value = dr[tempName]; //如果非空,则赋值给对象的属性 if (value != DBNull.Value) pi.SetValue(t, value, null); } } //对象添加到泛型集合中 ts.Add(t); } return ts; } } }
public List<Entity.StuLineBalance> InquiryBalance(Entity.StuLineBalance cardno) { SqlParameter[] sqlparams = { new SqlParameter("@cardNo", cardno.cardNo) }; string sql = @"select * from V_inqueryBalance where cardNo=@cardNo"; DataTable result = SqlHelper.sqlhelper.GetDataTable(sql, CommandType.Text, sqlparams); List<Entity.StuLineBalance> mylist = new List<Entity.StuLineBalance>(); mylist = SqlHelper.DatatableConvert<Entity.StuLineBalance>.ConvertToModel(result); return mylist; }
三、泛型数据的获取在获取到泛型的数据了之后,肯定要读取里面的内容,在B层进行判断的时候也是必不可少的。这个时候有两种方法,其一就是判断是否有数据返回,在判断是否验证成功的时候用到了,这个时候需要检查泛型中的数据是否存在,用到了这个属性:mylist.Count,如果这个值为零,说明没有返回任何值,反之则有值,具体有多少就是这个count在指示。
提取数据的语句是:mylist(0).UserID,其中的(0)就是显示的第几条记录,而后面的UserID则根据泛型里面的实体而定:
四、常见错误
上面这中错误是我们在运用泛型的时候经常遇到的错误,原因是我们封装的实体中的属性的类型和数据库中相应字段的类型不同,例如上面错误的原因是在数据库中cash字段的类型是numeric型而我在实体中用的是string型。
当我们用泛型集合来代替DataTable的时候我们必须保证我们封装的实体的属性名和数据库中字段名一模一样,也就是说我们必须明确要转换的实体类的类型,否则会报错,另外我们在封装实体的属性的类型必须和我们数据库中相应字段的属性一样。
五、小结
在三层架构中,实体类即数据库的映射,因此实体类中的属性和数据库表中的字段是相对应的。把DataTable中的每一行记录视为一个实体类,把其中的字段读取出来,到实体类的属性中,再把所有的实体类存在泛型集合中。因此,DataTable中有多少个记录,泛型集合中就有多少个实体类,每个实体类的属性和DataTable的字段是相对应的。这样一来,传到B层或U层的将是一个实体类的泛型集合。
使用泛型集合传递数据,编写B层的人员无需手动填写需要的字段,直接按一下点,全都提示出来了,想用哪个用哪个,不会出现写错的情况;你不必了解数据库结构;符合面向对象思想。