浅谈“三层结构”原理与用意 7
函数中清除了数据集中所有的表之后,加入了一个新的数据表后就匆匆返回了。这样作的后果,会直接影响listlword.aspx。
...
#018 <asp:datalist id="m_lwordlistctrl" runat="server">
#019 <itemtemplate>
#020 <div> <!--// 会提示找不到下面这两个字段 //-->
#021 <%# databinder.eval(container.dataitem, "posttime") %>
#022 <%# databinder.eval(container.dataitem, "textcontent") %>
#023 </div>
#024 </itemtemplate>
#025 </asp:datalist>
...
这和前面提到的“情形一”,一模一样!我没有明确地提出自己想要的饭菜,但是餐馆服务生却揣摩我的意思,擅自作主。
其次,再看lwordservice.cs文件
...
#019 public int listlword(dataset ds, string tablename)
#020 {
#021 return (new lwordtask()).listlword(ds, tablename);
#022 }
...
在lwordservice.cs文件中,也是使用dataset对象来取得留言板信息的。这个dataset同样的不明确,含糊不清的指令还在执行……行#021由lwordtask填充的dataset不一定会含有我们希望得到的表。即便是行#019中的dataset参数已经明确的定义了每个表的结构,那么在带入行#021之后,可能也会变得混淆。例如,lwordtask类中的listlword函数其函数内容是:
...
#006 namespace tracelword2
#007 {
...
#011 public class lwordtask
#012 {
...
#022 public int listlword(dataset ds, string tablename)
#023 {
#024 ds.tables.clear();
#025
#026 // 在sql语句里选取了 [reguser] 表而非 [lword] 表
#027 string cmdtext="select * from [reguser] order by [reguserid] desc";
#028
#029 oledbconnection dbconn=new oledbconnection(db_conn);
#030 oledbdataadapter dbadp=new oledbdataadapter(cmdtext, dbconn);
#031
#032 int count=dbadp.fill(ds, tablename);
#033
#034 return count;
#035 }
...
函数中清除了数据集中所有的表之后,选取了注册用户数据表[reguser]对dataset进行填充并返回。也就是说,即便是lwordservice.cs文件中行#019中的dataset参数已经明确的定义了每个表的结构,也可能会出现和前面提到的和“情形三”一样结果。
最后,再看看lwordtask.cs文件
...
#022 public int listlword(dataset ds, string tablename)
#023 {
#024 string cmdtext="select * from [lword] order by [lwordid] desc";
#025
#026 oledbconnection dbconn=new oledbconnection(db_conn);
#027 oledbdataadapter dbadp=new oledbdataadapter(cmdtext, dbconn);
#028
#029 int count=dbadp.fill(ds, tablename);
#030
#031 return count;
#032 }
...
看到这里,我感到很是欣慰!我只能说我们的大厨师傅是一个厚道的人,而且还是很知我心的人。
我们不能只坐在那里期盼着我们的程序会往好的方向发展,这样很被动。写出上面的这些程序段,必须小心翼翼。就连数据库表中的字段命名都要一审再审。一旦变化,就直接影响到位于“表现层”的listlword.aspx文件。仅仅是为了顺利的完成tracelword3这个“大型项目”,页面设计师要和程序员还有数据库管理员要进行额外的沟通。我们需要一个“土豆炖牛肉盖饭”式的强制标准!——
引入实体规范
为了达到一种“土豆炖牛肉盖饭”式的强制标准,所以在tracelword4中,引入了classes项目。在这个项目里,只有一个lword.cs程序文件。这是一个非常重要的文件,它属于“实体规范层”,如果是在一个java项目中,classes可以看作是:“实体bean”。更完整的代码,可以在codepackage/tracelword4目录中找到——
lword.cs文件内容如下:
#001 using system;
#002
#003 namespace tracelword4.classes
#004 {
#005 /// <summary>
#006 /// lword 留言板类定义
#007 /// </summary>
#008 public class lword
#009 {
#010 // 编号
#011 private int m_uniqueid;
#012 // 文本内容
#013 private string m_textcontent;
#014 // 发送时间
#015 private datetime m_posttime;
#016
#017 #region 类 lword 构造器
#018 /// <summary>
#019 /// 类 lword 默认构造器
#020 /// </summary>
#021 public lword()
#022 {
#023 }
#024
#025 /// <summary>
#026 /// 类 lword 参数构造器
#027 /// </summary>
#028 /// <param name="uniqueid">留言编号</param>
#029 public lword(int uniqueid)
#030 {
#031 this.uniqueid=uniqueid;
#032 }
#033 #endregion
#034
#035 /// <summary>
#036 /// 设置或获取留言编号
#037 /// </summary>
#038 public int uniqueid
#039 {
#040 set
#041 {
#042 this.m_uniqueid=(value<=0 ? 0 : value);
#043 }
#044
#045 get
#046 {
#047 return this.m_uniqueid;
#048 }
#049 }
#050
#051 /// <summary>
#052 /// 设置或获取留言内容
#053 /// </summary>
#054 public string textcontent
#055 {
#056 set
#057 {
#058 this.m_textcontent=value;
#059 }
#060
#061 get
#062 {
#063 return this.m_textcontent;
#064 }
#065 }
#066
#067 /// <summary>
#068 /// 设置或获取发送时间
#069 /// </summary>
#070 public datetime posttime
#071 {
#072 set
#073 {
#074 this.m_posttime=value;
#075 }
#076
#077 get
#078 {
#079 return this.m_posttime;
#080 }
#081 }
#082 }
#083 }
这个强制标准,lwordservice和lwordtask都必须遵守!所以lwordservice相应的要做出变化:
#001 using system;
#002 using system.data;
#003
#004 using tracelword4.accesstask; // 引用数据访问层
#005 using tracelword4.classes; // 引用实体规范层
#006
#007 namespace tracelword4.interservice
#008 {
#009 /// <summary>
#010 /// lwordservice 留言板服务类
#011 /// </summary>
#012 public class lwordservice
#013 {
#014 /// <summary>
#015 /// 读取 lword 数据表,返回留言对象数组
#016 /// </summary>
#017 /// <returns></returns>
#018 public lword[] listlword()
#019 {
#020 return (new lwordtask()).listlword();
#021 }
#022
#023 /// <summary>
#024 /// 发送留言信息到数据库
#025 /// </summary>
#026 /// <param name="newlword">留言对象</param>
#027 public void postlword(lword newlword)
#028 {
#029 (new lwordtask()).postlword(newlword);
#030 }
#031 }
#032 }
从行#018中可以看出,无论如何,listlword函数都要返回一个lword数组!这个数组可能为空值,但是一旦数组的长度不为零,那么其中的元素必定是一个lword类对象!而一个lword类对象,就一定有textcontent和posttime这两个属性!这个要比dataset类对象作为参数的形式明确得多……同样的,lwordtask也要做出反应: