• 【6】页面数据和控件的自动交换机制


    阅读目录

    只要使用了数据库,那么管理和维护数据的工作就是不可避免的。应用程序中,对于数据库中数据的管理和维护,有两种情况。一种是与业务逻辑密切相关的数据,往往通过关系-对象映射的方法转换为对象,应用程序的运行就围绕这些对象进行,所以这类数据的管理维护的过程其实就是应用程序的运行过程。另外一种,就是很多的资料性的数据,涉及到数据表和数据字段都很多,但使用频度不高。对于这类数据,每个都转换为对象的话,一方面太复杂,另一方面由于使用率不高,也比较浪费。

    对于后者,通过一个管理页面直接访问和操作数据库,反而简单有效。这类管理页面的技术难度不大,但是需要的步骤繁琐,对此类操作进行优化,可以大大提高开发的生产效率。

    数据维护的流程

    要优化数据管理页面,必须要了解典型的数据维护页面有哪些操作,才能有的放矢,既简化操作又能适应需求的变化。下面通过一个简单的数据管理页面,来剖析数据管理的一般过程。假如有以下的一个教师信息表,字段结构如下:

    image_thumb

    在Default.aspx页面,为每个字段添加一个对应的控件,如下所示:

    image_thumb21

    对于部分控件,需要进行初始化,比如加载备选的条目、设定控件外观等操作。这些操作,需要在初次加载页面时进行:

    
    if (!Page.IsPostBack)  //初始化控件
    {
    	 ddlTitle.Items.Add("助教");
    	 ddlTitle.Items.Add("讲师");
    	 ddlTitle.Items.Add("副教授");
    	 ddlTitle.Items.Add("教授");
    }

    控制初始化以后的效果:

    image_thumb2

    数据的加载

    接下来,就可以进行数据的加载了。数据管理页面,一般都通过传递一个数据的ID给页面,在页面中进行加载。假如数据库中已经存在如下数据:

    image_thumb3

    就可以通过default.aspx?ID=1的方式打开页面并加载数据。

    需要说明的是,下面的数据库访问采用CommonCode下的AccessDB完成,因此,可以不用过多地考虑数据库的种类、数据库的操作等细节。

    控件加载数据记录的代码如下:

    
    if (!Page.IsPostBack)  //加载数据
    {
    	if (Request.QueryString["ID"] != null)
    	{
    		DataTable dt = AccessDB.GetData("select * from Teacher where f_ID=" + Request.QueryString["ID"].ToString());
    		if (dt.Rows.Count == 1)
    		{
    			txtID.Text = dt.Rows[0]["f_ID"].ToString();
    			txtName.Text = dt.Rows[0]["f_Name"].ToString();
    			txtBegin.Text = dt.Rows[0]["f_BeginYear"].ToString();
    			ddlSex.SelectedValue = dt.Rows[0]["f_Sex"].ToString();
    			ddlTitle.SelectedValue = dt.Rows[0]["f_Title"].ToString();
    		}
    	}
    }
    

    对于下拉列表而言,显示的文本和值是不同的,所以后两个DropDownList赋值时只要按照Value来赋值即可。下图是ID参数为1时,加载相应数据的界面。

    image_thumb11

    数据的修改

    数据成功加载后,就可以通过界面对控件的数据进行各种操作。当完成编辑后,单击保存,就可以将控件内容保存到数据库中。在进行保存操作时,需要将控件中的内容提出,更新到数据库中,操作代码如下所示:
    
    protected void Button2_Click(object sender, EventArgs e)
    {
    	//保存数据
    	AccessDB.DoNonQuery("update Teacher set f_Name='" + txtName.Text + "',"
    							+"f_Sex="+ddlSex.SelectedValue+","
    							+"f_Title='"+ddlTitle.SelectedValue+"',"
    							+"f_BeginYear="+txtBegin.Text
    							+" where f_ID="+txtID.Text);
    }
    

    数据的添加

    添加新记录操作往往需要两步,第一步,确定要执行的是添加动作,将所有的控件清空;第二步,将控件中的数据插入到数据库。

    第一步的操作非常简单,对“添加”按钮编写事件:

    
    protected void Button1_Click(object sender, EventArgs e)
    {
    	txtID.Text = "";
    	txtName.Text = "";
    	txtBegin.Text = "";
    	ddlSex.SelectedIndex = 0;
    	ddlTitle.SelectedIndex = 0;
    }
    

    第二步的操作中,由于修改和新建两个处理往往放在同一个按钮事件中,所以需要判断当前操作的类型。对比可见,修改和新建的最大区别,在于ID字段。和其他字段有所不同,ID字段是自增的关键字段,不需要用户录入,也不允许修改。所以,在修改操作时txtID控件有内容,而新建操作时txtID控件没有内容。(为了防止用户在新建时的无意填入,可以把txtID控件设置为只读状态)

    根据txtID判断状态后,进行相应的处理,相应的代码为:

    
    if (txtID.Text != "")
    {
    	//保存数据
    	AccessDB.DoNonQuery("update Teacher set f_Name='" + txtName.Text + "',"
    							+ "f_Sex=" + ddlSex.SelectedValue + ","
    							+ "f_Title='" + ddlTitle.SelectedValue + "',"
    							+ "f_BeginYear=" + txtBegin.Text
    							+ " where f_ID=" + txtID.Text);
    }
    else
    {
    	AccessDB.DoNonQuery("insert into Teacher (f_Name,f_Sex,f_Title,f_BeginYear) values("
    							+"'"+txtName.Text+"',"
    							+ddlSex.SelectedValue+","
    							+"'"+ddlTitle.SelectedValue+"',"
    							+txtBegin.Text+")");
    }
    

    单击“添加”后,填入新的记录,再单击保存:

    image_thumb12

    在数据库中可以看到,新记录已经被插入了。

    image_thumb14

    到此,我们把一个最简单的页面的维护基本完成了,可以实现数据的加载、修改、添加。

    自动交换机制

    假如上述的教师表的字段需要扩展,根据上面的代码,至少这些地方是必须要进行修改:

    1、对新字段添加控件

    2、加载控件数据的代码中,添加新的控件的赋值

    3、保存时,增加新的字段

    4、新建时,增加新的字段

    实际项目中表的字段数量往往非常多,几十上百个也不奇怪。那么,上述的修改代码量将是非常巨大的。这些繁杂的代码,存在以下的问题:

    1、这些代码其实都是复制粘贴而来,费时费力,也不便于修改

    2、两个主要的sql语句,随着字段的增加复杂性也随之增加,调试的困难度也不断增加

    因此,如果能够把上面的机械操作变得自动化,将大大降低页面的代码量。自动化处理的思路如下:

    image_thumb20

    AccessDB是公共的数据库处理,提供简单、快速的数据库操作支持。在AccessDB之上,由PageX完成控件和数据之间的数据交换。

    PageX在初始化时,通过注册方法保存了控件和字段之间的对应关系。以后的加载数据、读取数据都可以通过这个对应关系自动完成了。

    PageX的实现

    PageX的结构如下:

    
    public class PageX
    {        
    	public Hashtable Xmap;
    	
    	//注册控件和字段的对应关系
    	public void RegisterControl(string key, object ctl)
    	{
    		if (Xmap == null) Xmap = new Hashtable();
    		Xmap.Add(key, ctl);
    	}
    }
    

    其中的Xmap保存了对应关系,RegisterControl则进行注册。

    有了对应关系,加载数据到控件或者相反的从控件读入数据就变得非常简单了,以加载数据为例,实现代码如下:

    
    public void SetControls(DataRow dr)
    {
    	if (Xmap == null) return;
    	foreach (DictionaryEntry de in Xmap)
    	{
    		switch (de.Value.GetType().Name)
    		{
    			case "TextBox":
    				((TextBox)de.Value).Text = dr[de.Key.ToString()].ToString();
    				break;
    			case "DropDownList":
    				//其他控件……		
    		}
    	}
    }
    

    支持的控件较多,包括TextBox、DropDownList、RadioButtonList、HtmlInputText、Label、Image、CheckBox等,代码较长不再完全展示。

    跟它相对应,从控件中读取的方法也类似。这样,原来的加载方法就变得非常简单了。

    
    public void GetControlsData(ref DataRow dr, string KeyField)
    {
    	if (Xmap == null) return;
    	foreach (DictionaryEntry de in Xmap)
    	{
    		//得到查询结果中,该字段的字段名称
    		string sFieldCName = de.Key.ToString();
    		switch (de.Value.GetType().Name)
    		{
    			case "TextBox":
    				//处理逻辑:文本型字段原样复制,数值型字段,未设置时取0(关键字未设置时留空)
    				if (TypeUtil.IsNumeric(dr.Table.Columns[sFieldCName].DataType) && ((TextBox)de.Value).Text == "")
    				{
    					if (sFieldCName == KeyField) break;   //关键字不能自动赋0值
    					((TextBox)de.Value).Text = "0";
    				}
    				dr[sFieldCName] = ((TextBox)de.Value).Text;
    				break;
    			case "DropDownList":
    				//其他控件……
    		}
    }
    

    使用PageX来完成数据的自动加载

    有了PageX,加载和保存数据就变得异常简单了,只要为页面定义一个PageX对象,对它登记控件和字段之间的对应关系后,加载或读出数据都变得简单了:

    
    PageX px = new PageX();   //页面交换对象
    protected void Page_Load(object sender, EventArgs e)
    {
    	//其他初始化代码...
    	//注册控件-不管是初次访问还是回调,都必须注册,因为回调后px对象无法保持状态
    	px.RegisterControl("f_ID", txtID);
    	px.RegisterControl("f_Name", txtName);
    	px.RegisterControl("f_Sex", ddlSex);
    	px.RegisterControl("f_Title", ddlTitle);
    	px.RegisterControl("f_BeginYear", txtBegin);
    
    	if (!Page.IsPostBack)	//初次打开,加载数据
    	{
    		if (Request.QueryString["ID"] != null)
    		{
    			DataTable dt = AccessDB.GetData("select * from Teacher where f_ID=" + Request.QueryString["ID"].ToString());
    			if (dt.Rows.Count == 1)
    			{
    				px.SetControls(dt.Rows[0]);
    			}
    		}
    	}
    }
    protected void Button2_Click(object sender, EventArgs e)
    {
    	DataRow dr = AccessDB.GetEmptyRow("Teacher");
    	px.GetControlsData(ref dr, "f_ID");
    	if (txtID.Text != "")
    	{
    		//保存数据
    		 AccessDB.Update("Teacher", dr, "f_ID");
    	}
    	else
    	{
    		//添加数据
    		AccessDB.Add("Teacher", dr);
    	}
    }
    

    上述代码中,修改和新建操作时,已经把数据从控件存入到DataRow中了,AccessDB中提供了数据的自动添加和更新的方法,只要提供表名和关键字列,以及DataRow,就可以自动实现数据的添加和更新。

    可以看到,通过PageX的数据交换机制,代码量大大减少了。如果遇到和前面一样的问题,教师表增加新的字段,那么,除了添加新的控件之外,代码中只要增加注册对应关系就行了。

    非标准数据的处理

    除了标准的数据之外,可能还有很多非标准的数据。PageX的机制支持比较自由的扩展。对于非标准的数据,可以不进行注册,在控件加载后进行单独的操作,而且数据更新或者插入前,对DataRow进行特定的操作。

    
    	px.SetControls(dt.Rows[0]);
    	//在此读取dt.Rows[0]中的非标准字段,修改相应的控件
    
    	px.GetControlsData(ref dr, "f_ID");
    	//在此从非标准的控件读取数据,写入dr
    

    PageXDemo

  • 相关阅读:
    学习Android有感!
    使用PHP-Barcode轻松生成条形码(一)
    php利用redis实现分页列表,新增,删除功能
    JS验证input输入框(字母,数字,符号,中文)正则实现
    mac 安装swoole扩展
    git 配置本地SSH秘钥
    lnmp 一键安装
    lnmp php版本升级
    NATAPP内网穿透,本地进行微信开发,支付开发,对象存储回调信息
    微信公众号二维码
  • 原文地址:https://www.cnblogs.com/jetz/p/3740469.html
Copyright © 2020-2023  润新知