【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

posted @ 2014-05-21 08:06  jetz  阅读(1018)  评论(3编辑  收藏  举报