【6】页面数据和控件的自动交换机制
阅读目录
- 数据维护通用流程
- 数据的加载
- 数据的修改
- 数据的添加
- 自动交换机制
- 使用PageX来完成数据的自动加载
- 非标准数据的处理
只要使用了数据库,那么管理和维护数据的工作就是不可避免的。应用程序中,对于数据库中数据的管理和维护,有两种情况。一种是与业务逻辑密切相关的数据,往往通过关系-对象映射的方法转换为对象,应用程序的运行就围绕这些对象进行,所以这类数据的管理维护的过程其实就是应用程序的运行过程。另外一种,就是很多的资料性的数据,涉及到数据表和数据字段都很多,但使用频度不高。对于这类数据,每个都转换为对象的话,一方面太复杂,另一方面由于使用率不高,也比较浪费。
对于后者,通过一个管理页面直接访问和操作数据库,反而简单有效。这类管理页面的技术难度不大,但是需要的步骤繁琐,对此类操作进行优化,可以大大提高开发的生产效率。
数据维护的流程
要优化数据管理页面,必须要了解典型的数据维护页面有哪些操作,才能有的放矢,既简化操作又能适应需求的变化。下面通过一个简单的数据管理页面,来剖析数据管理的一般过程。假如有以下的一个教师信息表,字段结构如下:
在Default.aspx页面,为每个字段添加一个对应的控件,如下所示:
对于部分控件,需要进行初始化,比如加载备选的条目、设定控件外观等操作。这些操作,需要在初次加载页面时进行:
if (!Page.IsPostBack) //初始化控件
{
ddlTitle.Items.Add("助教");
ddlTitle.Items.Add("讲师");
ddlTitle.Items.Add("副教授");
ddlTitle.Items.Add("教授");
}
控制初始化以后的效果:
数据的加载
接下来,就可以进行数据的加载了。数据管理页面,一般都通过传递一个数据的ID给页面,在页面中进行加载。假如数据库中已经存在如下数据:
就可以通过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时,加载相应数据的界面。
数据的修改
数据成功加载后,就可以通过界面对控件的数据进行各种操作。当完成编辑后,单击保存,就可以将控件内容保存到数据库中。在进行保存操作时,需要将控件中的内容提出,更新到数据库中,操作代码如下所示:
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+")");
}
单击“添加”后,填入新的记录,再单击保存:
在数据库中可以看到,新记录已经被插入了。
到此,我们把一个最简单的页面的维护基本完成了,可以实现数据的加载、修改、添加。
自动交换机制
假如上述的教师表的字段需要扩展,根据上面的代码,至少这些地方是必须要进行修改:
1、对新字段添加控件
2、加载控件数据的代码中,添加新的控件的赋值
3、保存时,增加新的字段
4、新建时,增加新的字段
实际项目中表的字段数量往往非常多,几十上百个也不奇怪。那么,上述的修改代码量将是非常巨大的。这些繁杂的代码,存在以下的问题:
1、这些代码其实都是复制粘贴而来,费时费力,也不便于修改
2、两个主要的sql语句,随着字段的增加复杂性也随之增加,调试的困难度也不断增加
因此,如果能够把上面的机械操作变得自动化,将大大降低页面的代码量。自动化处理的思路如下:
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
- 分布式监控系统Zabbix3.2给异常添加邮件报警
- 分布式监控系统Zabbix3.2跳坑指南
- 一图看懂java内存模型
- 零代码如何打造自己的实时监控预警系统
- 一步一步在Windows中使用MyCat负载均衡 上篇
- 你真的会玩SQL吗?之逻辑查询处理阶段
- javascript中如何正确将日期(Date)字符串转换为日期(Date)对象?
- 全面迎接.Net3.0时代的到来(WCF/WF/WPF/LINQ)
- SQL Server 2005 正则表达式使模式匹配和数据提取变得更容易
- [基础]datagridview绑定数据源的几种常见方式
- c#:winform鼠标拖动窗口大小时,设定窗口最小尺寸
- 在非SqlServer数据库上实现MemberShip和Role功能(自定义MemberShipProvider和RoleProvider)
- 一种实用的表格行鼠标点击高亮效果
- Lucene:QueryParser中操作符的疑惑
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 数据结构实验——校园导游 实现最小生成树+最短路
- Salesforce LWC学习(二十六) 简单知识总结篇三
- 【Java】13 异常
- 【Java】14 多线程
- 【Java】16 字节流
- 【Java】17 字符流
- 极坐标系在数据可视化中的巧妙运用
- 【Java】18 增强流
- 【Java】19 网络编程
- 【Java】20 基于 TCP 协议的网络编程
- 【Java】01 初识 Java
- 多张热图的排版技巧
- 【Java】02 数据类型与运算符
- StringBuilder/StringBuffer源码阅读笔记
- PAT (Advanced Level) Practice 1027 Colors in Mars (20 分)