第二天 -- 《2014-07-17 三层架构》1 --数据的查询、映射到实体、实体与UI控件的绑定,从控件获取实体对象、插入新建记录
一、上午《01、回顾》--《02、获取所有人员信息》
1、对表CRUD时,可以把新增和修改数据用的控件放到查询窗体里。(见下图)平时隐藏,点击新增或修改按钮时显示出来。

比如上图,放置于底层的是DataGridView控件用来查询显示。顶层的是GroupBox控件,放置新增或修改数据时让用户输入的控件。平时GroupBox被隐藏,当用户点击新增或修改按钮时,显示该控件。当用户点击取消或者正确输入后点击确定按钮时,该控件再次隐藏起来。
这样做的优点:便于将编辑对象(实体对象)传递,如果新增或修改时弹出一个小窗体,麻烦一点,需要在窗体之间传递对象。相比较这样更懒省事。
2、DataTable转实体集合。(一般还需要DataRow转实体对象)
检索时,SqlHelper一般使用DataAdapter读取结果集,返回给DAL层DataTable。然后在DAL层将DataTable转为实体对象集合也就是将DataTable每一行转为实体对象。
这样便于UI层控件(如DataGridView、ComboBox等)绑定实体对象集合。(现在已经很少有人将控件直接绑定DataTable了)
1 //DataTable转实体对象集合 2 public List<Person> DataTableToList(DataTable dt) 3 { 4 List<Person> list = new List<Person>(); 5 foreach (DataRow row in dt.Rows) 6 { 7 Person per = DataRowToModel(row);//每行转为一个实体对象 8 9 list.Add(per); 10 } 11 12 return list; 13 } 14 15 //DataRow转实体对象 16 public Person DataRowToModel(DataRow row) 17 { 18 Person per = new Person(); 19 20 per.PID = (int)row["pid"]; 21 per.PCID = (int)row["pcid"]; 22 per.Cname = row["Cname"].ToString(); 23 per.PType = (int)row["ptype"]; 24 per.TypeName = row["TypeName"].ToString(); 25 per.PLoginName = row["PLoginName"].ToString(); 26 per.PCName = row["PCName"].ToString(); 27 per.PPYName = row["PPYName"].ToString(); 28 per.PPwd = row["PPwd"].ToString(); 29 30 per.PGender = (bool)row["PGender"]; 31 per.PEmail = row["PEmail"].ToString(); 32 per.PAreas = row["PAreas"].ToString(); 33 per.PIsDel = (bool)row["PIsDel"]; 34 per.PAddTime = (DateTime)row["PAddTime"]; 35 36 return per; 37 }
1 //SqlHelper类中的数据检索方法,返回DataTable 2 public static DataTable ExecuteTable(string sql, params SqlParameter[] ps) 3 { 4 DataTable dt = new DataTable(); 5 var da = new SqlDataAdapter(sql, connStr); 6 7 da.SelectCommand.Parameters.AddRange(ps); 8 da.Fill(dt); 9 10 return dt; 11 }
注意:在上例中SqlDataAdapter通过连接字符串实例化,每次都会在内部先实例化连接,然后Connection.Open(),这种情况下读取数据完毕后它会自动Connection.Close()。
如果实例化SqlDataAdapter时传入(已实例化)的连接,适配器在保证连接Open的情况下读取数据,读完后将Connection连接保持之前的状态(以前是Open的,读完还是Open;之前是Close的要先Open,最后Close掉)。大部分时候,我们使用连接池,最好用上一种方式实例化SqlDataAdapter。
3、UI层从DataGridView和ComboBox控件取出绑定的数据(实体对象)
(1)DataGridView如:this.dgvList.CurrentRow.DataBoundItem as PhoneNum;
(2)ComboBox如:
//实例化实体类对象,下面为对象的属性赋值。
MODEL.Person newPerson = new MODEL.Person();
newPerson.PCID = (this.cbx_Classes.SelectedItem as MODEL.Classes).Cid;
newPerson.PType = (int)cbx_Identity.SelectedValue; //前提是你绑定数据前设置了ValueMenber值。
(3)ListView
ListView没有DataSource属性,不能直接数据绑定,需要循环添加Item。遍历数据源(最好用实体对象集合),循环创建Item,并把对象实例赋给Item的Tag属性。将来方便从Item取回实体对象值。
取值时,一次可以选中多个Item:
比如:SelectedItem[0].Text即选中的显示名,SelectedItem[0].Tag即实体对象。
(4)TreeView
TreeView没有DataSource属性,不能直接数据绑定,需要循环添加Node。遍历数据源(最好用实体对象集合),递归创建Node,并把对象实例赋给Node的Tag属性。将来方便从Node取回实体对象值。
取值时,一次只能选中一个Node:
比如:SelectedNode.Text即选中的节点显示名,SelectedNode.Tag即实体对象。
二、上午《03、修改dgv控件的数据绑定》
1、多表连接查询时的数据绑定要注意:
(1)DAL层sql语句要写多表连接。
(2)实体层创建一个对应ViewModel类,也就是UI上需要的结果集的所有字段。和上面<1>中sql的select子句字段相匹配。
(3)DataTable和DataGridView控件都不支持与sql的“表名.字段名”列做绑定。那么表连接时,如果sql列名没冲突就用列名算了;如果有冲突要用别名,DataTable和DataGridView就要通过别名来绑定。
1 //多表连接时的数据绑定。DAL层 2 public List<MODEL.Person> GetAllPersonList(bool isDel) 3 {//获取所有人员 4 string sql = @"select pid, pcid, cname, ptype, typename, ploginname, pcname, ppyname, ppwd, pgender, pemail, pareas, pisdel, paddtime 5 from person inner join classes on person.pcid = classes.cid inner join persontype on person.ptype = persontype.id where pisdel = @isdel"; //多表连接 6 SqlParameter p = new SqlParameter("isdel", isDel); 7 var dt = SqlHelper.GetDataTable(sql, p); 8 9 return DataTableToList(dt); 10 } 11 12 //DataTable转实体对象集合 13 public List<MODEL.Person> DataTableToList(DataTable dt) 14 { 15 List<MODEL.Person> list = new List<MODEL.Person>(); 16 foreach (DataRow row in dt.Rows) 17 { 18 MODEL.Person per = new MODEL.Person(); 19 per.PID = (int)row["pid"]; 20 per.PCID = (int)row["pcid"]; 21 per.Cname = row["Cname"].ToString();//这是Classes表的cname列。没有字段冲突,直接可以用Cname这个名。(如果写row[“Classes.Cname”]就错了) 22 per.PType = (int)row["ptype"]; 23 per.TypeName = row["TypeName"].ToString();//这是persontype表的TypeName列。因为没有字段冲突,所以直接用TypeName这个名。(假如有冲突,sql中要起个别名,这里用别名) 24 per.PLoginName = row["PLoginName"].ToString(); 25 per.PCName = row["PCName"].ToString(); 26 per.PPYName = row["PPYName"].ToString(); 27 per.PPwd = row["PPwd"].ToString(); 28 29 per.PGender = (bool)row["PGender"]; 30 per.PEmail = row["PEmail"].ToString(); 31 per.PAreas = row["PAreas"].ToString(); 32 per.PIsDel = (bool)row["PIsDel"]; 33 per.PAddTime = (DateTime)row["PAddTime"]; 34 35 list.Add(per); 36 } 37 38 return list; 39 }
三、上午《04、修改dgv控件中列的显示》--《06、获取班级列表信息》
1、修改DataGridView控件中列的显示
我们一般把数据库表和列直接映射为实体类名和属性(及字段)。
当DataGridView控件绑定实体对象集合时,各列都是绑定的实体类的属性,
所以有时可以在实体类加入一些额外的属性作为绑定显示之用。
比如数据库Person表有一个bit类型列PGender,true表示男,false表示女。代码生成器会生成一个bool属性
public bool PGender{get;set;}这个将来显示在控件上的时候是true或false,显然不是用户希望看到的男和女。
实际上我们只需要在实体类中手写一个新的属性PGenderString并绑定到控件即可:
public bool PGenderString
{
get{return PGender? "男" : "女";}//判断自动生成的PGender属性
set{PGender = value == "男";}
}
另外:实体类没有set访问器的属性,绑定到DataGridView控件后,不能在控件上修改值。
四、下午《01、实现初步的新增操作》--《06、加载树控件的节点》
1、插入新记录,就是创建新实体对象(并将用户在UI录入的数据给对象属性赋值),交给BLL层,最后再到DAL层通过insert的sql语句,插入到数据库。
2、数据在UI层录入后,一般要经过“数据验证”。
数据验证一般有两种形式:一是验证输入的值是否合法(检查非空,可以用正则检查....),二是验证数据库中是否存在某值(比如登录名),要保证值的唯一性。(满足数据库表的约束)
浙公网安备 33010602011771号