在通常情况下,进行数据的维护开发(添加、修改),是件相当耗费体力的劳动,一般需要先建立表单,然后是验证(客户端或非客户端),然后逐一提取表单数据,对应数据表中的字段,然后拼装Sql,然后执行Sql。。。
当我们面对大量的数据表(表中还包含繁多的字段),需要进行几乎相同的操作时,着实很让人头疼。。。
现在已经有很多方案来解决这个问题,例如 ASP.NET Dynamic Data Web Application,主要是借助ADO.NET 实体框架来实现对数据的添删改,这套解决方案本身非常强悍,只需将数据表导入为 Entity Data Model,将表结构引入动态模型中,改改配置,就能对数据进行简单的添删改了(还有一套过得去的界面)。动态数据模型实际是通过分析 Data Entity 中的元数据,根据表结构和字段类型调用控件,最终生成操作界面。
这套解决方案比较重口味,它的理想是不需要任何代码就实现数据维护!它非常通用,但实际使用它时,需要做的工作还是很多,要根据需求定制控件、维护Data Entities 数据结构等等。。。
这里给大家分享一个比较简单的解决方案,核心思想与动态数据模型类似,但比较紧耦合。
首先,在进行数据库添改时,本质就是获取和设置控件的值,对用户输入的数据进行验证,并将错误信息提示给用户。 定义如下接口
public interface IControls
{
/// <summary>
/// 控件值访问器
/// </summary>
object ControlVal { get; set; }
/// <summary>
/// 控件别名 消息提示用
/// </summary>
string Alias { get; set; }
/// <summary>
/// 控件验证 - 返回空字串验证成功,否则消息提示用户
/// </summary>
/// <returns></returns>
string Validate();
}
定义好接口后,实现IControls 接口,并继承.net 现有控件(这里可为任意Asp.net 控件)。例如定制一个TextBox的扩展:
public class TB : System.Web.UI.WebControls.TextBox, IControls
{
public TB()
{
}
//别名
public string Alias { get; set; }
//控件值
public object ControlVal
{
get
{
return this.Text;
}
set
{
if (value == null || value == DBNull.Value)
this.Text = "";
else
this.Text = value.ToString();
}
}
//验证
public string Validate()
{
string text = this.Text.Trim();
string validateStr = string.Empty;
//验证不允许为空
if (IsRequire)
{
if (String.IsNullOrEmpty(text))
{
validateStr = String.Format("{0}:不允许为空!\\r\\n", Alias);
}
}
return validateStr;
}
//验证的条件:验证是否为空
public bool IsRequire = false;
//这里可定义更多验证属性。。。
}
OK,控件做好了,现在把它搬到页面上
<tr>
<th>
用户名:
</th>
<td>
<csk:TB runat="server" ID="UserName" Alias="用户名" IsRequire="True"></csk:TB>
</td>
</tr>
<tr>
<th>
邮箱:
</th>
<td>
<csk:TB runat="server" ID="UserEmail" Alias="邮箱" IsRequire="True"></csk:TB>
</td>
</tr>
<tr>
<th>
</th>
<td>
<asp:Button runat="server" ID="Button1" title="提交" OnClick="Button1_Click" />
</td>
</tr>
注意:页面中控件ID要与数据表中的字段名一一对应,数据与控件是通过【控件ID==列名】来关联的,这就是紧耦合的地方了~
ps:csk 为自定控件前缀,在页面顶部加入 <%@ Register TagPrefix="csk" Namespace="yourNameSpace" Assembly="yourProject"%>
或在Web.config 中配置前缀。
接下来,要让数据与控件联动起来,基本思路是:在页面中找到已实现 IControls 接口的控件,能够获取他们的值,并验证数据的正确性,并且可以将数据绑到控件上:
public class ControlsRelationData
{
//控件容器 private Control Container;
/// <summary> /// 控件数据绑定 /// </summary> public ControlsRelationData(Control container)
{
this.Container = container;
}
/// <summary> /// 收集验证信息 /// </summary> public string ValidateString { get; set; }
/// <summary> /// 获取控件所有值 /// </summary> /// <returns>表单数据键值对(键:表单ID(数据列名),值:表单值)</returns> public Dictionary<string, object> GetControlValues()
{
var vals = new Dictionary<string, object>();
//遍历容器内所有控件
foreach (var obj in Container.Controls)
{
//检查控件是否实现接口
IControls iControl = obj as IControls;
if (iControl != null)
{
Control ctl = obj as Control;
if (ctl != null)
{
//获取键值
string key = ctl.ID;
object val = iControl.ControlVal;
//数据验证信息 var validateStr = iControl.Validate(); if (!String.IsNullOrEmpty(validateStr))
ValidateString += validateStr;
vals.Add(key, val);
}
}
}
return vals;
}
/// <summary> /// 将数据绑到控件上 /// </summary>
/// <returns>单行</returns> public void SetControlValues(DataRow dataRow)
{
foreach (var obj in Container.Controls)
{
IControls iControl = obj as IControls;
if (iControl != null)
{
Control ctl = obj as Control;
if (ctl != null)
{
string key = ctl.ID;
//数据列名与控件ID同名,故dataRow[key]值即控件值 ((IControls)obj).ControlVal = dataRow[key]; } } } } }
准备就绪,现在调用他们,当用户提交信息时获取键值对,当修改信息时,读取数据并绑定到控件上:
//主键
int userId = 0;
//控件关联数据类
ControlsRelationData CRD;
protected void Page_Load(object sender, EventArgs e)
{
//实例化关联类,Page为当前页面
CRD = new ControlsRelationData(Page);
//传入主键时为修改状态 if (int.TryParse(Request["userid"], out userId))
{
//读取用户数据
DataRow userAccount;// = UserDA.GetUserById(userId); CRD.SetControlValues(userAccount); } } /// <summary> /// 用户提交信息 /// </summary> protected void Button1_Click(object sender, EventArgs e)
{
//获取字段名和值 Dictionary<string, object> keyValues = CRD.GetControlValues();
//检查是否收集到错误信息 if (!String.IsNullOrEmpty(CBD.ValidateString))
{
//提示错误信息并返回 //Tool.Alert(this, CBD.ValidateString); return;
}
if (userId == 0)
Parse_ExcuteInsert(keyValues, "UserAccount");
else Parse_ExcuteUpdate(keyValues, "UserAccount", "UserId", userId);
//提示修改成功 } /// <summary> /// 解析并执行插入操作 /// </summary> private void Parse_ExcuteInsert(Dictionary<string, object> dicts,string tableName)
{
SqlParameter[] dataParams = new SqlParameter[dicts.Count];
string keys = string.Empty;
string values = string.Empty;
int i = 0;
foreach (var kv in dicts)
{
if (i > 0)
{
keys += ",";
values += ",";
}
dataParams[i] = new SqlParameter("@" + kv.Key, kv.Value);
keys += kv.Key;
values += "@" + kv.Key;
i++;
}
if (i > 0)
{
string sqlStr = string.Format("INSERT INTO {0}({1}) VALUES({2})", tableName, keys, values);
//SqlParameter[] 与 sql 拼装完成,执行数据库操作 //Access.SqlServer.ParamExecute(sqlStr, dataParams); } } /// <summary> /// 解析并执行修改操作 /// </summary> void Parse_ExcuteUpdate(Dictionary<string, object> dicts, string tableName,string primaryName,int primaryValue)
{
SqlParameter[] dataParams = new SqlParameter[dicts.Count + 1];//加上主键Parameter string setValues = string.Empty;
int i = 0;
foreach (var kv in dicts)
{
if (i > 0)
{
setValues += ",";
}
dataParams[i] = new SqlParameter("@" + kv.Key, kv.Value);
setValues += string.Format("[{0}] = @{0}", kv.Key);
i++;
}
//主键 dataParams[i] = new SqlParameter("@p_" + primaryName, primaryValue);
if (i > 0)
{
string sqlStr = string.Format("UPDATE Market_Info {0} SET {1} WHERE @p_{2}", tableName, setValues,primaryName);
//SqlParameter[] 与 sql 拼装完成,执行数据库操作 //Access.SqlServer.ParamExecute(sqlStr, dataParams); } }
以上代码仅限于对单主键表进行操作,数据库执行方法未包含其中。
控件也仅仅实现了TextBox,可扩展任意Asp.net 标准控件以及用户控件(实现IControls接口)。
当一些常用的控件封装好,加上各种验证属性,以后添加修改数据就省事多了,只需要摆摆控件,改改验证属性,只需少量的代码,即可轻松的完成数据添改操作。^_^