第二天 -- 《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控件取出绑定的数据(实体对象) 

详见《Winform控件——关于数据绑定

(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层录入后,一般要经过“数据验证”。

  数据验证一般有两种形式:一是验证输入的值是否合法(检查非空,可以用正则检查....),二是验证数据库中是否存在某值(比如登录名),要保证值的唯一性。(满足数据库表的约束)

 

posted on 2017-08-23 15:55  困兽斗  阅读(427)  评论(0)    收藏  举报

导航