其实添加数据也可以这样简单——表单的第一步抽象(针对数据访问层)《怪怪设计论: 抽象无处不在 》有感

简介: 更正:不好意思,昨天晚上思路有点混乱。有几个前提忘记说明了,现在补充一下。 1、缩小范围。按照由简到难的思路,这里先讨论最简单的添加数据的情况。就是单表的添加和修改;这里讨论的是webform的情况。

更正:
不好意思,昨天晚上思路有点混乱。有几个前提忘记说明了,现在补充一下。
1、缩小范围。按照由简到难的思路,这里先讨论最简单的添加数据的情况。就是单表的添加和修改;这里讨论的是webform的情况。

2、第一步抽象是针对数据访问层的抽象。
如果我没有理解错的话,现在大多数人的做法是:有一个表(或者几个有关联的表)在数据层里就要有一个“函数”与之对应,
如果采用的是SQL语句的方式的话,那么函数的内筒就是组合SQL语句的代码,
如果采用的是存储过程的方式的话,那么函数的内筒就是给存储过程的参数赋值。
而我这里只需要一个函数就可以了。这个函数是共用的,是针对所有表的。再准确点说:SQL语句对应两个函数(一个添加数据、一个修改数据),存储过程对应一个函数(是添加还是修改在存储过程内部判断)。存储过程的方式在这里没有说明。

3、在这里的代码我想写的尽量简单,写多了就会影响主体,所以这里只写了主要代码。

4、如果您有时间的话,您可以拿我的这段代码(实现添加修改数据功能)和您自己写的类似的功能的代码对应一下,先看一下代码量,然后再看一下如果要增加字段(比如加一个新闻字数),需要修改的代码的数量。

5、第二步抽象是针对后置代码的,也可以叫做逻辑层吧。第三步抽象是针对UI的。
Artech的思路有些类似。我是想从基础的代码一步一步写上去,我要是直接写我现使用的方式,估计大家不太容易看懂。

6、 我的思路是:用简单的代码实现复杂的功能(客户的要求)!

7、 怪怪设计论: 抽象无处不在



为了便于说明,先举个实际的例子吧。比如要实现一个发布信息(比如新闻)的功能,说白了就是添加数据。

我的做法是先设计数据库,然后写.aspx (UI),然后写.aspx.cs(后置代码),然后就完成了。

设计数据库:表名叫做 news ,有一下几个字段

NewsID  int  4 主键自增
Title nvarchar 50 标题
Kind  int 4 新闻分类
Editor nvarchar 20 编辑
Content  ntext  16 新闻内容

NewsAdd.aspx  添加数据的页面(UI)
< form  id ="Form1"  method ="post"  runat ="server" >
            
< TABLE  id ="Table1"  cellSpacing ="1"  cellPadding ="1"  width ="400"  align ="center"  border ="1" >
                
< TR >
                    
< TD  align ="right" > 标题: </ TD >
                    
< TD >
                        
< hbs:HBSTextBox  id ="Txt_Title"  runat ="server"  Columns ="50" ></ hbs:HBSTextBox ></ TD >
                
</ TR >
                
< TR >
                    
< TD  align ="right" > 类别: </ TD >
                    
< TD >
                        
< hbs:HBSDropDownList  id ="Lst_Kind"  runat ="server"  Width ="112px" ></ hbs:HBSDropDownList ></ TD >
                
</ TR >
                
< TR >
                    
< TD  align ="right" > 作者: </ TD >
                    
< TD >
                        
< hbs:HBSTextBox  id ="Txt_Editor"  runat ="server"  Columns ="50" ></ hbs:HBSTextBox ></ TD >
                
</ TR >
                
< TR >
                    
< TD  align ="right" > 内容: </ TD >
                    
< TD >
                        
< hbs:HBSTextBox  id ="Txt_Content"  runat ="server"  TextMode ="MultiLine"  Rows ="5"  Columns ="50" ></ hbs:HBSTextBox ></ TD >
                
</ TR >
            
</ TABLE >
            
< hr  color ="#39689f" >
            
< TABLE  cellSpacing ="1"  cellPadding ="1"  width ="100%"  align ="center"  border ="0" >
                
< TR >
                    
< TD  align ="center" > &nbsp;
                        
< asp:Button  id ="Btn_Save"  runat ="server"  Width ="70px"  Text =" 确 定 " ></ asp:Button > &nbsp; < INPUT  id ="Btn_Return"  type ="button"  value =" 返 回 "  onclick ="myEsc()" ></ TD >
                    
</ TD ></ TR >
            
</ TABLE >
        
</ form >


可以暂时把  hbs:HBSTextBox 当作一般的 TextBox 看待,HBSTextBox 是我继承了TextBox写的一个自定义服务器控件。


后置代码(可以看作逻辑层吧)
private   void  Page_Load( object  sender, System.EventArgs e)
        
{
            
// 在此处放置用户代码以初始化页面
            Response.Cache.SetNoStore();

            
初始化#region  初始化
            
//给按钮加前台的验证事件
            this.Btn_Save.Attributes.Add("onclick","return myCheck();");
            
            
if (!Page.IsPostBack)
            
{
                
//先帮定下拉列表框
                BindList();
        
                
switch (Kind )
                
{
                    
case "2"
                        
//准备修改数据,修改用
                        ShowData();
                        
break;
                }

                
            }

            
#endregion

        }


        
        
保存数据 #region 保存数据
        
private void Btn_Save_Click(object sender, System.EventArgs e)
        
{
            
//保存成功后关闭窗口
            if (SaveData())
                Functions.PageRegisterJavascript(Page,
"myReturn()");
            
        }

        
#endregion


        
实现保存数据的函数 #region 实现保存数据的函数
        
private bool SaveData()
        
{
            
string[] str1 = new string[4];
            
定义字段#region 定义字段
            str1[
0= "Title";
            str1[
1= "Kind";
            str1[
2= "Editor";
            str1[
3= "Content";
            
#endregion


            
string[] str = new string[4];
            
数据#region 数据
            str[
0= this.Txt_Title.TextTrimNone;        //Title;
            str[1= this.Lst_Kind.SelectedValue         //Kind;
            str[2= this.Txt_Editor .TextTrimNone;        //Auther;
            str[3= this.Txt_Content.TextTrimNone;        //Content;
            #endregion


            
验证数据#region 验证数据
            
//代码略。写多了会影响这里的主题
            #endregion


            
保存数据#region 保存数据
            
switch (Kind )
            
{
                
case "1":
                    
//添加时验证是否有相同的记录,代码略。写多了会影响这里的主题
                    
//添加数据
                    dal.InsertDataStr("News",str1,str);
                    
break;
    
                
case "2":
                    
//修改时验证是否有相同的记录,代码略。写多了会影响这里的主题    
                    
//修改数据
                    dal.UpdateData("News",str1,str," NewsID=" + DataID);
                    
break;
            }

            
#endregion


            
检查是否出现异常#region 检查是否出现异常
            
if (dal.ErrorMsg.Length > 2)
            
{
                Functions.PageRegisterAlert(Page,
"保存数据的时候出现意外情况,请与管理员联系!");
                
return false;
            }


            Functions.PageRegisterAlert(Page,
"保存成功!");
            
return true;
            
#endregion

        }

        
#endregion


这样呢就完成了添加数据的功能。什么,您问数据访问层呢?对于我来说数据访问层是通用的,也就是标题里说的第一步抽象!

添加数据使用的是  dal.InsertDataStr("News",str1,str); 代码实现请见 www.cnblogs.com/jyk/archive/2006/08/16/478021.html
还是贴出来吧
#region 查询语句的方式添加、修改数据
        
        
// / <summary>
         // / 添加记录。传入表名,字段数组,值数组,返回新生成记录的ID
         // / </summary>
         // / <param name="TableName">要添加记录的表的名称</param>
         // / <param name="ziduan">字段名数组</param>
         // / <param name="msg">字段对应的值的数组</param>
         // / <returns></returns>
        public   string InsertDataStr(string TableName  ,  string[] ziduan  ,  string[] msg )
        
{
            
//添加数据    返回新添加的ID
            System.Text.StringBuilder SQL = new System.Text.StringBuilder(300);
            SQL.Append(
"insert into ");                    //insert into 
            SQL.Append(TableName);
            SQL.Append(
" ([");
            
int i;
            
for( i = 0 ;i< ziduan.Length ;i++)        //字段
            {
                
if (msg[i] != "_n_")
                
{
                    SQL.Append(ziduan[i]);
                    SQL.Append(
"],[");
                }

            }

            SQL 
= SQL.Remove(SQL.Length -2,2);

            SQL.Append(
")  values ('");

            
for( i = 0;i<ziduan.Length ;i++)
            
{
                
if (msg[i] != "_n_")
                
{
                    SQL.Append(msg[i]);
                    SQL.Append(
"','");
                }

            }

            SQL 
= SQL.Remove(SQL.Length -2,2);

            SQL.Append(
")  select scope_identity() as a1");
            
            string re 
= RunSqlGetID(SQL.ToString());
            SQL.Length 
= 1;
            
if (re == null)
                
return "-1";
            
else
                
return re;
        }

        
        
// / <summary>
         // / 修改记录。传入表名,字段数组,值数组 
         // / </summary>
         // / <param name="TableName">要修改记录的表的名称</param>
         // / <param name="ziduan">字段名数组</param>
         // / <param name="msg">字段对应的值的数组</param>
         // / <param name="tiaojian">条件 ,加在where 后面的语句</param>
         // / <returns></returns>
        public bool UpdateData( string TableName ,string[] ziduan ,string[] msg ,string tiaojian) 
        
{
            System.Text.StringBuilder SQL 
= new System.Text.StringBuilder(300);
            SQL.Append(
"update ");                    //update
            SQL.Append(TableName);
            SQL.Append(
" set ");
            
int i;
            
for (i = 0 ;i< ziduan.Length ;i++)
            
{
                
if (msg[i] != "_n_")
                
{
                    SQL.Append(
"[");
                    SQL.Append(ziduan[i]);                    
//update
                    SQL.Append("]='");
                    SQL.Append(msg[i]);
                    SQL.Append(
"',");
                }

            }

            SQL 
= SQL.Remove(SQL.Length-1,1);    //去掉最后一个 ","
            SQL.Append(" where ");
            SQL.Append(tiaojian);
            
            RunSql(SQL.ToString());
            
return true;
        
        }

        #endregion


思路呢就是 组合成 insert into  的SQL语句,insert 需要什么信息呢?表名,字段名和字段对应的值。

我把这三个信息用一个字符串和两个数组传递进来,然后用两个for 循环来组合。最后通过 ADO.net 提交给数据库执行。

这样99%以上的表的添加都可以用这个函数了,是不是可以达到以下几个目标呢?
1、抽象。数据访问层利用一个函数就可以应对多个表的添加数据的功能。
2、代码重用。好多地方都可以调用。
3、零耦合。业务层和数据层的真正零偶合。我觉得修改上一层的代码的时候不用修改下一层的代码,这就是零耦合吧;同样修改下一层的代码的时候不用修改上一层的代码,也就是零耦合吧。而这里就是这样。
只要你把数据放在数据库里(有表有字段的那种),而且这种数据库支持“insert into ”这样的标准SQL语句,那么就不需要修改数据访问层!上一层也不用修改。

我觉得这个不能叫做面向对象吧,顶多是利用了“封装”的特性。应该是面向过程的思路。但是应该说使用了 抽象。


优点:
1、 再多的表也不用一遍一遍的写组合SQL语句的代码了。(前提是使用SQL语句)。
2、SQL语句完全放在数据访问层里,上一层只出现表名和字段名。
3、代码量少!数据访问层只需要一个函数(还是公用的),也不用实体类来传递数据了,也就少了编写实体类和赋值取值的代码。
4、便于修改,增加字段的话,只需要修改一下数组的大小,加两行代码就可以了。(当然UI里还要加一个控件)。其他的地方,数据访问层了根本就不用修改,根本就没有实体类,所以也就不用修改了。

5、添加、修改一个页面完成。

缺点:
1、虽然逻辑层里没有出现SQL语句,但是依然出现了表名和字段名。相信大家对这一点很是不满意吧。这个确实是一个缺点,但是并不足以否掉这种添加数据的方案。
2、没有使用实体类传递数据(也没有用Hashtable),而使用了数组。我觉得数组很灵活,也很基本,绝大多数语言都是支持的,这里使用数组就足够用了吧。
3、不OO。不知道这个算不算缺点,难道不OO就不能写成程序了吗?









相关文章
|
XML JSON 算法
【软件设计师备考 专题 】编写内部设计文档:构件划分图和接口
【软件设计师备考 专题 】编写内部设计文档:构件划分图和接口
53 0
|
28天前
|
设计模式 监控 算法
【领域驱动设计专题】一文带领你透视DDD领域驱动模型的本质和设计原理分析指南(通用语言体系)
【领域驱动设计专题】一文带领你透视DDD领域驱动模型的本质和设计原理分析指南(通用语言体系)
50 2
|
7天前
|
存储 Java 数据库
平台设计-数据相关类
平台上和数据有关的类有实体类BO、视图类VO、传输类DTO;传输类又细分为信息类和请求类。
|
1月前
|
Java 数据库
java面向对象高级分层实例_数据库操作类
java面向对象高级分层实例_数据库操作类
11 1
|
5月前
|
设计模式 安全 Java
Activiti工作流学习笔记(四)——工作流引擎中责任链模式的建立与应用原理
过滤器链就像一条铁链,中间的每个过滤器都包含对另一个过滤器的引用,从而把相关的过滤器链接起来,就像一条链的样子。这时请求线程如蚂蚁一样,会沿着这条链一直爬过去-----即,通过各过滤器调用另一个过滤器引用方法chain.doFilter(request, response),实现一层嵌套一层地将请求传递下去,当该请求传递到能被处理的过滤器时,就会被处理,处理完成后转发返回。通过过滤器链,可实现在不同的过滤器当中对请求request做拦截增加,且过滤器之间彼此互不干扰。
34 0
|
开发者
业务层设计与开发(定义业务层标准) | 学习笔记
简介:快速学习业务层设计与开发(定义业务层标准)
108 0
业务层设计与开发(定义业务层标准) | 学习笔记