三层架构之我见 —— 不同于一般的三层架构。也许对您会有所启发!

楼主jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)2006-08-15 07:26:31 在 .NET技术 / ASP.NET 提问

 
  近来三层好像挺火,但是和以前的一律称赞有所不同,很多人表示了困惑、不解。  
   
  好像有很多的疑问。我根据我的经验,写了一点东东,也许对你会有所帮助。  
   
  (blog怎么发不了文章了?又在升级吗?)  
   
   
                  我从02年开始了编程的工作,开始接触一些简单的网站,下半年写了个小的自助建站程序(asp和asp.net),比较简陋没有使用。03年开始正式做网站(asp)。03年下半年开始改版三好在线(www.sanhaoonline.com   asp.net   ),03年底、04年初才知道了三层架构的相关东东,一开始是很不了解的,所以呢根本就没有理睬,依旧按照我自己的思路写网站。  
     
                  后来有点痫暇时间才开始看了看三层方面的东东,不过很遗憾至今为止我依然没有看懂petshop和duwish的代码(也许是我没有花费太多的时间去看吧)。三层给我的总体感觉就是两个字   ——   麻烦;四个字   ——   浪费代码。感觉自己的东东很简洁。因为一直都是我一个人写网站,没有人帮我分担其它层的编写;而我又很懒,一个人写三个层的代码   ——   太累。  
     
                  随着时间的推移,逐渐验证了我自己的想法。不能说是绝对的好,但是也能够达到方便、简洁、可扩展、稳定性好的程度了。一直都想写点东西出来,但是由于种种原因阻挠,一直没有实现愿望。(以前在csdn里面也发了一些帖子,都是不了了之了。)  
     
                  近两天三层又被提起来了,看来我也该写点东东了。  
     
                  在继续说明之前,先缩小一下范围(程序员的思路都是很广的,很容易联想到其它的方面):  
     
                  目前我想讨论的只是asp.net,而且只是网站,再缩小一点就是那种很简单的网站。(其他的情况暂且不考虑,当然以后会加以说明的!请不要心急。当然您不要认为我根本没有考虑到复杂的情况。)  
     
  下面简单说一下我的思路。其实很简单了,就是两个字   ——   通用!  
     
  1、   数据访问层是通用的。(和三层里的数据访问层的概念是有区别的,请不要较真。)  
  2、   实体类也是通用的。  
  3、   常用的功能(比如分页、联动下拉列表等)都写成了控件,自然也就是通用的了。  
     
  先说一下数据访问层。  
     
                  我的印象:三层架构里的数据访问层并不是通用的,其实我现在也没用完全弄明白三层架构里数据访问层到底要写些什么东东,感觉是在重复的写着  
     
  SqlConnection   cn   =   new   SqlConnection(…);  
  SqlCommand   cm   =   new   SqlCommand  
  SqlDataAdapter   da   =   new   SqlDataAdapter(cm);  
  da.Fill(…);  
     
  这些代码。不知道我的理解是不是正确。  
     
                  可能你会说:你不知道SqlHelp吗?  
                  我知道SqlHelp,但是知道的时候已经太晚了。在我知道他之前,我已经在用我自己写的“数据访问层”了(那时的还没有现在的这么强大,所以加了引号)。而且我感觉自己写的要比   SqlHelp   好用得多。当然我也参考了一些   SqlHelp   和其它的类似的程序,以便吸取精华,来不断地完善自己的数据访问层。  
     
  我的数据访问层的功能:  
     
                  简单的说就是对ado.net的进一步的封装   ——   简化功能的封装。ado.net是通用的,所以我的数据访问层自然也就是通用的了。  
     
     
                  想想我们需要的是什么?执行sql语句(比如添加、修改、删除)、返回记录集(存放在DataSet等对对象里面)。我的数据访问层也就是围绕这两个功能而展开。  
     
  直接使用   ado.net   的话要写好几行代码才能得到一个DataSet   。(就像我上面写的那个例子)。  
     
  而使用我的数据访问层的话就不那么多的代码了,基本上一行就可以了。  
     
  需要传入的参数:sql语句、存储过程的名称(存储过程的参数)。  
     
  根据实际情况判断具体传入什么参数,以及使用那些函数。(这些都是调用数据访问层的地方的事情。)  
     
                  返回类型:返回   void   、DataSet   、DataTable、DataRow、string[]、string,最近又增加了返回结构数组的功能,结构数组也就是“实体类”。  
     
  简单的说我的数据访问层就是这些接口。  
     
  下面举例说明我的数据访问层的使用方法:  
     
  比如我想在网站的首页里调用最后添加的五条资讯,然后绑定到Repeater控件上。  
     
  我可以这样写  
     
  JYK.DataAccessLayer   dal   =   new   JYK.DataAccessLayer();                     //实例化数据访问层  
  Rpt_News.DataSource   =   dal.RunSqlDataTable   (“select   top   5   字段   from   表名   where   条件   排序等”);                 //获得记录集  
  Rpt_News.DataBind();  
     
  dal.   Dispose()   ;//释放资源。  
     
                  短短几行就实现了功能,除了前台Repeater   里面需要再写点代码之外,其他的地方就不用再写任何的代码了。我感觉我的方法是相当的简介,你的感觉呢?  
     
  (当然首页里面不会只显示资讯就完事了,其他的也是类似的写法。也可以用  
  DataSet   ds   =   dal.RunSqlDataSet(sql语句)  
  或者  
  DataSet   ds   =   dal.RunStoreDataSet(存储过程名称)  
     
  返回多个记录集。然后用   ds.Table[0]、ds.Table[1]…来绑定控件。)  
     
     
     
  数据访问层先说到这里,下面说说实体类  
     
                  一开始我是不用实体类的,因为感觉需要一个表对应一个实体类,如果是这样的话就太麻烦了。取代的是直接使用DataTable   ,和数据访问层搭配用起来也是很简单的。  
     
                  后来发现   <%#   DataBinder.Eval(Container,   "DataItem.txt")%>   的绑定方法实在是效率太低了,后弃之不用,改成了   <%#((DataRowView)Container.DataItem)["Url"]%>。但是总感觉不爽。突然想起来以前有位高人提及自定义数据源绑定控件的方法。记忆已经很是模糊了,隐约感觉是使用了结构之类的东东。经过一段时间的摸索和实验,确定了自己的一种“实体类”   ——   更准确的说就是结构(struct)数组。  
     
  //插叙  
                  让我们先来看看网页里的“元素”。想想上面那个显示资讯的例子,在页面里面(UI层)我们需要获取什么呢?链接网址、资讯标题、发表时间、人气、资讯图片的网址、资讯的简要介绍。(还有其它的吗?)  
     
                  根据我的编写网站的经验,这些已经足够了。也就是说结构(struct)里面定义这些属性就足够一般的页面(首页和列表页面)使用了。当然在实际中我又加了一个ID的属性。  
  //插叙结束  
     
                  通用的实体类,也就是说不管是资讯还是文件下载还是其它的什么,都用具有这些属性的结构数组来保存记录集。再在数据访问层里面增加一个函数来返回结构数组(就像返回DataTable   那样的函数)。前台调用也是很方便,不仅可以绑定到控件,而且可以直接使用   for   循环来显示数据(仿佛回到了asp的时代J)。因为for更加的灵活,是控件所无法比拟的!而且可以很轻松的应对美工给的不好循环的页面。  
     
  绑定控件的写法  
  <%#   ((BaseTitle)Container.DataItem).URL%>  
  <%#   ((BaseTitle)Container.DataItem).Title%>  
  <%#   ((BaseTitle)Container.DataItem).ImagePath%>  
  <%#   ((BaseTitle)Container.DataItem).Hits%>  
  ……  
     
  for的写法。(后台定义   myData,并使用我的数据访问层填充数据)  
  <%=   myData[i].URL%>  
  <%=   myData[i]..Title%>  
  <%=   myData[i]..ImagePath%>  
  <%=   myData[i]..Hits%>  
     
  相同的写法,不用考虑具体的字段名称,那里使用复制到哪里就可以了,是不是很方便。  
     
     
     
     
  下面是最后一个部分了。  
     
  说了首页之后,下面就是列表页面了。主要就是分页和查询。  
     
                  也许分页对你来说不是太容易(包括查询功能)(当然可能对于您也是非常容易的事情),但是对于我来说却是相当的容易   ——   因为我有自己的分页控件。  
     
     
  private   void   Page_Load(object   sender,   System.EventArgs   e)  
  ...{  
                //   在此处放置用户代码以初始化页面  
                Response.Cache.SetNoStore();  
     
                Page1.PubShowDataObject   =   DL;   //给一个显示数据的控件  
                 
                if   (!Page.IsPostBack)  
                ...{  
                              SetPageInfo();  
                }  
  }  
     
  设置分页控件#region   设置分页控件  
  private   void   SetPageInfo()  
  ...{  
                Page1.SqlTableNames   =   "TableName";                 //表名  
                Page1.SqlColumns   =   "*   ";                                             //显示的字段  
                Page1.SqlOrderColumn   =   "ID";                                           //排序字段  
                Page1.SqlOrderColumnKind   =   "int";                       //排序字段的类型  
                Page1.IsOrderDesc   =   true;                             //倒序显示  
     
                Page1.SqlPageSize   =   10;                 //一页的记录数  
                Page1.SqlQuery   =   ""   ;                                         //查询条件  
     
                Page1.CreateQuery();                                           //生成查询语句  
                Page1.BindFirstPage();                                     //绑定第一页  
     
  }  
  #endregion  
     
     
                  我只要写上面这几行代码即可实现分页显示数据的功能(提取数据的部分,显示数据当然要另行处理了)。查询也是很简单的事情。组合SQL语句(where   后面的),然后赋值给   Page1.SqlQuery   属性,再执行    
  Page1.CreateQuery();                                         //生成查询语句  
                Page1.BindFirstPage();                                     //绑定第一页  
     
  就可以了。点击下一页等的处理事件已经包含在控件里面了,没有特殊情况就不用自己再加事件了。  
     
  这都是控件带来的好处,也就是通用。在任何项目里面(包括后台管理)都可以很方便的使用!  
     
     
  下面总结一下:  
     
  UI层   :   aspx页面  
     
  逻辑层,分为两种情况:  
  在项目里面只出现一次的函数,直接写在aspx.cs页面;  
  在项目里面会多次出现的函数,写在.cs文件里面。(比如登录、验证用户登录信息等)  
  大量使用自定义控件来简化编码。  
     
  数据访问层:调用dll文件,无需重复编写代码。  
     
  当然这么看起来的话好像变成了一层的代码,因为代码都写在了   aspx和aspx.cs里面了。  
   
  我采用的是分层的思路,而不是分层的形式!  
     
  不知道我有没有说明白。  
     
  我的表述能力比较差,请多多原谅。  
     
  先写这些,具体的以后慢慢写。  
  问题点数:100、回复次数:282Top

1 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 07:45:54 得分 0

本来想写在blog里的,这里不了功能加各式,看起来比较费劲。  
   
  但是blog又发布不了文章。没办法,只好写在这里了。Top

2 楼DreamOfEyes(风之语)回复于 2006-08-15 07:50:17 得分 1

谢谢楼主  
  学习了Top

3 楼winner2050(winner)回复于 2006-08-15 07:51:27 得分 0

你还是不明白。  
   
  我都用到N层结构  
  BLL  
  Common  
  DALFactory  
  SQLDataAccess  
  ACCESSDataAccess  
  IDAL  
  Model  
  Webui  
   
  对于庞大的代码量来说,层次不明朗,管理代码很麻烦的。  
  现在我越用越HAPPYTop

4 楼truecoffeefox(咖啡狐)回复于 2006-08-15 08:12:05 得分 2

呵呵  
  比起你的我自己的数据访问层简陋多了  
  Top

5 楼fattycat(最爱胖猫)回复于 2006-08-15 08:18:37 得分 1

 
  markTop

6 楼nekiy(云淡风清)回复于 2006-08-15 08:18:48 得分 2

向楼主学习~~  
                      支持~~  
                                      支持~~Top

7 楼jc15271149(奶皮儿)回复于 2006-08-15 08:21:49 得分 1

正在学习中,不过觉得对于大型的应用来说,分层还是必须的Top

8 楼ioleon13(我落日般的忧伤就像惆怅的飞鸟,惆怅的飞鸟飞成我落日般的忧伤)回复于 2006-08-15 08:24:44 得分 1

我没有太多项目的经验啊,可惜Top

9 楼kason_j(伊松)回复于 2006-08-15 08:29:44 得分 1

呵呵。   正在学习中。。谢谢楼主Top

10 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 08:31:45 得分 0

首先呢,这里讨论的是简单的情况.  
   
  其次呢,是要以缩减大量的冗余代码为基础的。  
   
  复杂的情况,我日后还会陆续介绍的。  
   
  请耐心等待。  
   
  Top

11 楼fxqyyzg(海冬青)(昨夜西风凋碧树。独上高楼,望尽天涯路)回复于 2006-08-15 08:42:37 得分 1

MarkTop

12 楼wufato(.net学习提高中)回复于 2006-08-15 08:57:53 得分 1

强,学习,学习Top

13 楼wudemingsunny(罗纳尔迪尼奥)回复于 2006-08-15 09:04:57 得分 0

upTop

14 楼whChina(江城老温)(as a thinker)回复于 2006-08-15 09:10:12 得分 0

强帖留名Top

15 楼szc21(卖炭翁)回复于 2006-08-15 09:11:07 得分 1

mark,我还没想通啊Top

16 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 09:14:08 得分 0

不要着急,我会慢慢说明的。Top

17 楼zzmsl(周先生)回复于 2006-08-15 09:15:36 得分 1

回复人:winner2050(winner)    
  BLL  
  Common  
  DALFactory  
  SQLDataAccess  
  ACCESSDataAccess  
  IDAL  
  Model  
  Webui  
   
  太跟风,一个方法就做成一层吧?LZ说的是“目前我想讨论的只是asp.net,而且只是网站,再缩小一点就是那种很简单的网站。”Top

18 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 09:18:22 得分 0

由简单繁,慢慢说明:)Top

19 楼yzx110(原振侠)回复于 2006-08-15 09:18:58 得分 1

复杂的情况,这样很难行得通的。各种架构各种模式的运用,看上去代码越来越多,弄得“好像越来越复杂“,但是对付复杂的系统,你就会觉得那些分层、模式的威力了。当然简单的系统还是简单点弄好。  
   
  你说的数据访问通用,既然能直接写SQL语句,那么相同的代码切换数据库的时候可能是需要修改的,当然一般是不会换数据库的。Top

20 楼zzmsl(周先生)回复于 2006-08-15 09:21:15 得分 1

目前我也没脱离SQLHelper  
  每一个数据库的操作,都在写不同的  
   
  SQLHelper.GetCachedParameters(CACHE_NAME)  
   
  SQLHelper.CacheParameters(CACHE_NAME,   parms)  
   
  SqlParameter[]   sParms   =   GetCACHE_NAMEParameter()  
  {  
  sParms[0].Value   =   XXX;  
  }  
   
  using   (......)  
  {  
  ......  
  }  
  觉得挺麻烦的。Top

21 楼ustbwuyi()回复于 2006-08-15 09:22:02 得分 0

学习了..Top

22 楼dapanda()回复于 2006-08-15 09:22:36 得分 1

petshop是非常简单的架构,一看就懂  
  Top

23 楼oldmoon(电子商务人,电子商务路)回复于 2006-08-15 09:23:40 得分 1

楼主说的对是中小型项目,特别是那些开发人员比较少的团队,具有很好的参考性,很灵活。让本人也受益菲浅!  
   
  也有一点想请教楼主,象你举的例子首页显示资讯当然可以直接使用传一条SQL语句的形式,但是对于用户输入数据页面(比如用户注册等等),我一向都是使用SqlParameter这种参数方式来防止非法用户的注入,但在一个项目中,需要用户输入数据的地方往往很多(参数个数和名称都不一致),是不是对于每一次都得写一个方法,写一个类?还是有其它更好的方法?Top

24 楼myminimouse(坚决不用baidu)回复于 2006-08-15 09:25:15 得分 1

只看到几个类似el的东西,还有一些小技巧,和架构感觉没什么关系Top

25 楼LoveCherry(论成败,人生豪迈;大不了,重头再来!^_^)回复于 2006-08-15 09:26:27 得分 3

还是要根据项目来,要在开发成本、开发效率、后期维护成本之间做平衡  
  没有唯一的构架,适合项目的构架就是好构架,多个规模不同的项目都使用同一种构架也不好  
  你说的重用的原则是对的,重用了也就易维护,但是可以看出你的项目还不够大  
   
  有的人对ADO.NET进行简单封装  
  后来又觉得自己的构架似乎很土,开始使用NHIBERNATE  
  后来又觉得配置麻烦,效率低下、有的时候还要自己写SQL语句于是决定开始使用SQLMAP的方案  
  后来觉得SQL语句写在XML文件还是不爽啊,用企业库加存储过程算了  
  还是觉得没有实体很麻烦啊,算了用NetTiers在企业库上封装  
  后来想想“在企业库上封装我还不如直接用ORM啊?”  
  。。。。。。。。。。。。。。。。。。。。Top

26 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 09:29:01 得分 0

更换数据库也是很简单的事情(对于程序来说)  
   
  针对SQL编译一个dll,再针对OLEDB   编译一个dll,再针对Orcale   编译一个dll.....  
   
  有几种类型的数据库就编译几个dll,然后在项目里面根据不同的数据库引用不同的DLL就可以了。  
   
  当然要保证所有的dll的命名空间、函数名(接口)、参数、返回类型完全一致。  
   
   
  缺点就是同一个项目里面不能同时使用两种数据库。  
   
  (不过稍微修改一下数据访问层的命名空间和dll文件名,也就可以达到目的了。)  
   
   
  其实更换数据库最大的问题不在代码上,而在于   SQL语句是否完全兼容。Top

27 楼liuzhanpeng(圣诞菠萝包)回复于 2006-08-15 09:29:05 得分 2

简单的网站我也决不分层,无论是性能上,开发效率上都有优势。  
  大项目我没什么经验,但大项目的维护成本往往是最高的,分层最明显有优势了。Top

28 楼smalladam(强者的孤独---达到一定的高度 即可体会...)回复于 2006-08-15 09:31:33 得分 1

不用三层的话..日后维护升级   比较繁琐...Top

29 楼pantian(香草园主)回复于 2006-08-15 09:36:36 得分 1

如果只是一个人写,并且是同一个人维护,并且系统超级简单,那么,分不分层根本就无所谓,你愿意怎么写就怎么写。当年的程序英雄们都是这么一个人过来的。  
   
  如果不是你一个人写,哪怕就算是不正规的公司,只要有10来号开发人员的,也都会是多人来写的。  
  如果不是你自己来维护,而是别人来维护,说实话,你这不是难为人家吗?还让人家养成了不良的习惯,以后,别人去大公司,再写出这样的代码,还不被直接干掉呀?  
  如果系统并不是简单到只有20个不到的页面,你想不分层都难。  
   
  算了,我也不多说了,等看看楼主的复杂情况分析后再说吧。Top

30 楼wadsunglow(东)回复于 2006-08-15 09:36:49 得分 1

对于大型的应用来说,分层还是必要的,减少维护成本和方便他人阅读Top

31 楼longwycn((理想0769) ---要做DBA)回复于 2006-08-15 09:40:02 得分 1

我认为是很方便的,但确实不是三蹭结构,而你只是使用类和结构的形式来模拟三层,其实我也始终认为如果用多了SP的话,你的方法,可重用性和可修改性得到发挥。  
   
  但是,这始终不是面向对象的设计,或者说只是实现的部分使用了面向对象,  
   
  这是我的看法,欢迎拍砖Top

32 楼liuxiaoyi666(MSMVP 小猪妹荣誉马甲之八卦兔子)回复于 2006-08-15 09:40:47 得分 1

我也asp也用三层,有时做dll封装有是时直接写类  
   
  三层结构使你的东西很清晰  
   
  构架太重要了  
   
  做网站,还要做很多针对网站的生成工具.....Top

33 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 09:44:42 得分 0

首先我并没有说不分层,只是分层的方式不一样,看起来像一层的代码,其实是分层的思想。Top

34 楼lincai(隐身)回复于 2006-08-15 09:45:09 得分 1

以前我也不屑于三层,感觉好麻烦,一个很简单的返回记录集,要跑几个弯(BLL-IDAL-DALFactory-DALSqlServer-Model),最近几天才认真看三层的例子(我属于较菜那种,喜欢用自己土方法实现一些功能),觉得三层最大的用处是体现在数据库更改,如果从sql   server换成oracle数据库,只要改DALSqlServer这一层的代码就行,还有配置一下Web.config文件。如果照楼主的层次,那么整个项目代码都需重写了,但通常项目会更改数据库发现的情况比较少,站在商业的角度来说,重新意味着重新收到一笔开发费用^_^  
  对楼的分页控件很感兴趣,总感觉asp.net自带的数据控件都不真正符合自己的要求,其实觉得asp中的for可以运用在这,加上一些“当前页,总页,转到第几页”这些,才是完整的分页控件。楼主,能否详细讲一下你的分页是怎样实现的,谢谢!Top

35 楼netspies(从头再来)回复于 2006-08-15 09:53:18 得分 0

记号Top

36 楼artak(甜葡萄)回复于 2006-08-15 09:53:21 得分 0

markTop

37 楼LoveCherry(论成败,人生豪迈;大不了,重头再来!^_^)回复于 2006-08-15 09:56:48 得分 1

我在想如果IDE能支持数据库基元的智能感应多好啊?ORM的开发效率,ADO.NET的执行效率Top

38 楼extcsdn(Studing VB now)回复于 2006-08-15 09:57:18 得分 1

留名收藏Top

39 楼greywizard(烈破)回复于 2006-08-15 09:57:26 得分 0

markTop

40 楼flygoldfish(长江支流)回复于 2006-08-15 09:58:26 得分 3

收到楼主的MSG了,针对楼主说的观点说一下:  
   
  对1,只能说楼主的DataAccess做了简单的封装,如果应用设计模式之工厂模式,楼主就不会搞这么多dll  
   
  对2,同一项目是可以使用多种数据库的  
   
  应用设计模式做数据(库)访问层,就如楼主所说,不是物理数据库  
   
  楼主只要搞个IDataAccess接口,如打开关闭,执行SQL存储事务等,然后SqlDataAccess、OracelDataAccess、Access2000DataAccess、Access97DataAccess、DB2DataAccess、OleDbAccess....  
   
  它们实现IDataAccess接口,但是访问类型不为public而是Internal,这样封装后的dll使用者是看不到的,也就是对使用者透明。如果针对接口编   程如IConnection之类,只需要把具体的实例类在子类中实例化,其它子类没几行代码就搞定。  
   
   
  之后用一个DataAccessFactary,方法只有一个,那就是Creat()  
  根据配置文件返回一个IDataAccess  
   
  应用单件模式,可以方便访问,应用连接池(不同于数据库连接池)只是一个你程序员的集合,可以访问多种数据库  
   
   
  ----------------------------------------------  
  1、更换数据库也是很简单的事情(对于程序来说)  
   
  针对SQL编译一个dll,再针对OLEDB   编译一个dll,再针对Orcale   编译一个dll.....  
   
  有几种类型的数据库就编译几个dll,然后在项目里面根据不同的数据库引用不同的DLL就可以了。  
   
  当然要保证所有的dll的命名空间、函数名(接口)、参数、返回类型完全一致。  
   
   
  2、缺点就是同一个项目里面不能同时使用两种数据库。  
  Top

41 楼nonesharp(无锋)回复于 2006-08-15 10:00:50 得分 0

楼主为什么不考虑代码生成呢,那些重复的繁琐的劳动本就应该让电脑自己去完成Top

42 楼jijl2001(jijl2001)回复于 2006-08-15 10:05:13 得分 1

是不是楼主的项目还不够大。Top

43 楼flygoldfish(长江支流)回复于 2006-08-15 10:06:14 得分 0

楼主如有兴趣,可以加QQ群讨论  
   
  我实现的是用XML做映射或实现IEntityMap,我的底层自动生成带参SQL调用DataAccess。  
  带参SQL好处是不用处理特殊字符如',不用担心攻击安全性输入SQL,不用针对特定的数据库用特定的函数转换数据如日期等。而只要你有一个解析执行带参SQL的东东。  
   
  有了这一点,我的同一代码实现在Oracle、SQLServer、Access。。。各种数据中的应用,只需更改配置文件。  
   
   
  我做的:  
   
  1、DataAccess,跨数据访问,专门用于数据存取,已封装  
        IDataAccess                     数据库打开关闭、执行SQL等  
        IDataAccessFactory       工厂,根据配置文件实例多种数据访问,已实现Access、SQLServer、Oracle、DB2、OleDB、ODBC  
   
  2、EntityAccess,跨数据访问,调用数据访问层,为了与DataAccess实现松耦合,增加了IExeSql接口,因而只要你的数据访问实现了IExeSql接口也行,已封装  
   
        IEntityAccess,依赖IEntityFacade,调用IExeSql,是IEntityMap与DB的中间产物,已封装  
        IEntityMap,依赖IEntityFacade,调用IEntityAccess的增、删、改查  
        IEntityFacade,不用说了,仅仅是对象,这样不像强类型暴露了数据结构  
   
  这里的命名刚更改为现在这个名,正好和数据访问、中间层、表现层对应  
   
  3、实体定义与实体管理,实现IEntityFacade、IEntityMap接口或EntityAccess给定的基类  
        EntityDefine如PersonEntiy  
        例如成员Name,Age,这个名字不一定是数据库中Person表的字段名,这样很好的保护了结构不暴露,UI调用也方便,直接调用person.Name比强类型的dataRow["Name"].ToString()更直接方便,如果用强类型,UI还要了解结构,不爽。  
      如果你不会在意像DataSet强类型暴露数据结构,EntityManagement直接继承IEntityFacade的已实现的基本类EntityFacade并实现IEntityMap  
   
        EntityManagement如PersonManagement  
        调用者自己用成员适配模式定义EntityManagement适配IEntityMap的增删改查,这样就不会暴露数据结构  
      如果你不会在意像DataSet强类型暴露数据结构,EntityManagement直接继承IEntityMap或它的基本实现EntityMap类  
   
   
  4、还有业务外观和业务逻辑,调用EntityManagement,至于逻辑如多个实体对象利用COM+达到事务共享  
   
      因为各个对象在不同的数据访问层中提交,但很多时候需要事务,这里启动MSDTS  
   
  5、用户界面层,直接申明实体如PersonEntiy并用EntityManagement如PersonManagement达到数据存取目的。PersonEntiy仅仅是根据成员读写数据,调用PersonManagement的增删改  
  这样,UI不像调用强类型的DataSet还要清楚字段名等,而直接以对象方式存取,屏蔽了数据结构。  
   
  需要说明的是:  
  只要实现EntityAccess的IEntityMap接口,数据存取不用你写一行SQL,自动跨数据访问。  
   
   
  需要看演示的朋友可以临时加QQ群(网友建)  
  群号:17556475  
   
  您下载代码后可以主动退出群。  
  需要说明的是把示例代码上传到群上的时候还是采用以前的命名方法,但是也是这个思想,你只需更改配置文件(见readme.txt)无需更改代码就可以运行在Access、SQLServer、Oracle上。  
   
  最后更新代码将在我的Blog上下载,并再加以文章说明。  
   
  http://blog.csdn.net/flygoldfishTop

44 楼RedVesper(&&)回复于 2006-08-15 10:06:52 得分 1

说的都是结构.有没有考虑到扩展开发.如果注重结构没有考虑到三年后的客户需求的话.也只能归于三流的开发人员.针对团队开发,不是三层结构,别人无法用到你的写的方法.也无法在横向和纵向中快速整合.Top

45 楼jimmy_jjl(我心飘摇)回复于 2006-08-15 10:09:35 得分 1

markTop

46 楼flygoldfish(长江支流)回复于 2006-08-15 10:10:54 得分 0

To:nonesharp(无锋)    
  楼主也没有完全表达自己的东东。  
   
  代码生成器好吗?  
  越方便的东西,可能是你越难以维护的东西!  
   
  首先代码生成器的作者是不是对各种应用有研究,是不是有良好的编程习惯...  
   
  最大的缺点:代码生成,就意味着要重新编译。  
  我们做了一个快速开发平台,无需重新编译。  
  当然,各有各的优缺点,各有各自存在的道理,不能一刀切。  
   
  -----------------------------------------------------------------------  
  楼主为什么不考虑代码生成呢,那些重复的繁琐的劳动本就应该让电脑自己去完成  
  Top

47 楼winner2050(winner)回复于 2006-08-15 10:11:43 得分 0

Vista   用了50层结构呢。  
   
  要根据项目大小来确定。分不分,分多少。Top

48 楼xiajianfeng()回复于 2006-08-15 10:12:57 得分 0

i   think   the   key   problem   is   you   should   select   correct   construction   according   to   your   application   situation.Top

49 楼chinank(中国南开)回复于 2006-08-15 10:15:19 得分 1

层,我觉得就是为了方便,只要觉得方便就可以,没有必要去追求什么3层5层的名头。Top

50 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 10:16:08 得分 0

上班中,不能实时回复了,望见谅。Top

51 楼ASPNET_TO_VC_YUN(从ASP.NET C# 到 VC++ 又转 VB 汗~~)回复于 2006-08-15 10:27:18 得分 0

针对LZ的简单的范围~~不分层处理起来方便~~但是对于大规模的就不适用了~~  
    小的东西这么写是针对自己写代码的~~   维护也是自己~~  
    但是在做team   work的时候~~   结构的清晰度决定了   无用功的缩减~~  
    写代码的原则是   宁多误少~~~Top

52 楼toxyboy(不专业,我就顶,绝不误导别人!!)回复于 2006-08-15 10:31:13 得分 1

复杂的系统设计,不是约定俗成的非要三层还是四层,是根据实际需要而设计出符合需求的架构就可以。。。这最考验架构师的功底了。。怎么样抽象出接口、怎么样聚合出类。。。我工作六年了,还是不能很好的把握这个度。。。。Top

53 楼goody9807(http://goody9807.cnblogs.com)回复于 2006-08-15 10:38:32 得分 1

楼主总结的很好啊   其实觉得最重要的就是实用,开始偶也试了所有的ORM模型   ,最初也是从Petshop的三层学起,开始先尝试了实用SqlHelper   ,后来也用了一些   NHIBERNATE、NetTiers  
  EnterPrise   Library   等一些ORM模型,但后来遇到问题时就很难解决,偶只有一个想法要用别人的东西,必须要有源码,否则遇到问题解决不了,就会死得很惨了!  
   
   
   
  Top

54 楼leafsword_519(喝水的猪)回复于 2006-08-15 10:45:23 得分 0

mark一下Top

55 楼sorrow_man(不会我就问,零下一度)回复于 2006-08-15 11:02:08 得分 1

学习Top

56 楼redsee(那年那月)回复于 2006-08-15 11:05:23 得分 1

支持楼主Top

57 楼cime63(流浪的孩子)回复于 2006-08-15 11:14:00 得分 0

现在在把一个OA从access迁移到oracle  
  如果以前用三层架构的话,我现在就不用这么痛苦了  
   
  就是这么回事Top

58 楼0009(夏天以南)回复于 2006-08-15 11:35:19 得分 0

markTop

59 楼pw2000net(.NET)回复于 2006-08-15 11:44:05 得分 0

markTop

60 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 11:52:30 得分 0

楼主为什么不考虑代码生成呢,那些重复的繁琐的劳动本就应该让电脑自己去完成  
   
  ===========================  
   
  重复的   的东东就要从根本上加以解决,而不是用电脑来偷懒。  
   
  我的方法本来就没有那么多的重复的部分,或者说根本就没有,那么我为什么要用代码生成器呢?  
   
  Top

61 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 11:59:01 得分 0

看来   flygoldfish(长江支流)     是有一套自己的“开发平台”了。  
   
  其实我也有一个,呵呵。  
   
  只是没有怎么使用,自我感觉是很方便的。  
   
  内部代码没有     flygoldfish(长江支流)     的复杂,因为我根本就不会什么接口了、工厂了之类的东东。  
   
  Top

62 楼nonesharp(无锋)回复于 2006-08-15 12:02:59 得分 1

to:flygoldfish(长江支流)    
          我也是因为被那些重复的代码搞的很烦,所以开发了个代码生成器,结合自己的平台,用起来觉得还算尚可,随着不断的在新项目中的应用,几年来逐步完善之中。  
   
  to:lz  
          我感觉实体层还是有存在的必要的,可以解决不少问题,如果觉得表多了实体也多,那么我建议考虑自己写点辅助的代码生成工具,不会花去多少时间的,因为仅仅是自己使用,够用就好了。Top

63 楼yangcongtou9(逍遥雪)回复于 2006-08-15 12:08:57 得分 2

学习了,三层很累人Top

64 楼xjtandqt(重在参与)回复于 2006-08-15 12:40:07 得分 0

markTop

65 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 12:41:15 得分 0

对于我来说   代码生成工具   只是更快的产生“垃圾”代码,呵呵。  
   
  我寻求的是另一种方法,呵呵。Top

66 楼MonkWang(象写情书一样写程序)回复于 2006-08-15 12:58:14 得分 1

我个人觉得框架和分层等结构对于一些小的项目来说可能很麻烦甚至没有必要,但对于大的复杂的项目可能帮助比较大,尤其在扩展,灵活性及维护等方面!  
  我刚开始学框架,对这些东西还不是很懂!拙见!请勿见笑!Top

67 楼Samen168(Code to coding)回复于 2006-08-15 13:00:56 得分 0

又一个发明轮子的人。。。  
   
  如果你没法理解他的好处,再好的东西到你手上也只能是垃圾Top

68 楼GoogleDotNet(去他妈的败毒,叼3821他老母)回复于 2006-08-15 13:01:54 得分 1

当然,如果就一个helloworld的话,半层就够了   :)  
   
  开个玩笑,别介意  
   
  --------------------------------------------------------------  
    pantian(香草园主)   (   )   信誉:98     2006-8-15   9:36:36     得分:   0      
       
         
  如果只是一个人写,并且是同一个人维护,并且系统超级简单,那么,分不分层根本就无所谓,你愿意怎么写就怎么写。当年的程序英雄们都是这么一个人过来的。  
  Top

69 楼lubosun(大白菜)回复于 2006-08-15 13:03:45 得分 1

学习  
   
  分不分层,都无所谓呀Top

70 楼Samen168(Code to coding)回复于 2006-08-15 13:04:14 得分 1

当然如果看不到他的弊端,做出来的东西也不会好到哪去   ^6^Top

71 楼sekone()回复于 2006-08-15 13:32:17 得分 0

不过很遗憾至今为止我依然没有看懂petshop和duwish的代码(也许是我没有花费太多的时间去看吧)。  
  =============================  
  楼主很没有说服力,首先你自己没有很清楚的明白三层,所以你就没有资格说三层怎么样  
   
  就象以前的贴子,习惯用VB.NET的那些人说VB.NET比C#好用,习惯用C#的人说C#比VB.NET好用,这些人都是站在自己的角度上,以自己为中心的说法Top

72 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 13:34:20 得分 0

热衷于代码生成器的人,有没有注意到一个问题。  
   
  代码生成器   与   控件   的区别!  
   
  可能你会用代码生成器生成项目里的所有的表单,而我会用一个表单控件来实现项目里的所有的表单。  
   
  所以我说这是两个发展方向。  
   
   
  我所说的“垃圾”是加引号的,不是说代码或是代码生成器   垃圾,而是说同一个项目里面出现很多功能类似代码。这就是“垃圾”了。也就是冗余代码。  
   
  Top

73 楼sekone()回复于 2006-08-15 13:38:04 得分 0

而且人家的三层,面向对象是经过多少年的经验总结出来的?当然对于你的小网站可能不需要用。  
   
  忍不住多说了几句Top

74 楼nonesharp(无锋)回复于 2006-08-15 13:38:55 得分 0

呵呵,不要走极端吗,不是说生成了代码就不能用控件啊,反之亦然。为什么不结合起来用呢Top

75 楼MSTOP(陈建华)回复于 2006-08-15 13:47:54 得分 1

对于有点规模的项目,我也在用三层,思路好象与楼主差不多吧.  
   
  1.   COM+   层只负责与数据库打交道.  
  2.   前台多一个类,用于映射   COM+   的属性,方法.  
  3.   数据库访问和COM+访问都是通过一个INI来配置.Top

76 楼sekone()回复于 2006-08-15 13:49:38 得分 0

热衷于代码生成器的人,有没有注意到一个问题。  
   
  代码生成器   与   控件   的区别!  
  =================================  
  看到这里我又忍不住了,  
  我之前说过了,没有用过的东西你就没有资格评价它!你真的以为代码生成器   与   控件   是一样的吗?    
  只要三层架构是类似PetShop的,没有哪个人笨的不用代码生成器的,而且大都的开发团队都有自己开发的代码生成器,以共团队使用。  
   
   
  不是说代码或是代码生成器   垃圾,而是说同一个项目里面出现很多功能类似代码。这就是“垃圾”了。也就是冗余代码。  
  ===============================  
  你敢说PetShop有很多冗余代码吗?  
   
   
   
  结论就是:楼主先弄懂了PetShop再来讨论三层和代码生成器把Top

77 楼Samen168(Code to coding)回复于 2006-08-15 13:57:16 得分 0

好像没人要求你用CodeGenerate  
   
  不管是什么方式,单从代码封装的程度就能看出在设计方面的认识,也许CG比所谓的控件需要的代码可能会更少   ^6^  
   
  有句话说得没错,不要和白痴讨论谁更弱智    
   
  Top

78 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-08-15 14:01:03 得分 1

我支持楼主,先对以上一些观点进行驳斥:  
   
  首先是这个  
  BLL  
  Common  
  DALFactory  
  SQLDataAccess  
  ACCESSDataAccess  
  IDAL  
  Model  
  Webui  
   
  这哪里是什么层。很显然Common根本就不是什么层,然后DALFactory、SQLDataAccess、ACCESSDataAccess、IDAL之间必然是紧耦合,应该说就是一层。  
   
  专注于数据库而对WebUI不够重视,所做出来的东西反正我是不看好的。  
   
   
   
  至于长江支流的解决方案,其实有些为了什么而什么的倾向了。首先数据访问层因为要隐藏不同数据库之间的差别,所以通用的数据访问层肯定是不可能的东西。我们所能做的顶多是能抽象到SQL语句的程度,而不同的数据库所支持的SQL语句并不一致,且不同的数据库有不同的最优写法。这一点是我们不可能预见并完全抽象的。  
   
  况且,数据访问层也并不一定是个项目就必须有的东西,Top

79 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-08-15 14:05:10 得分 2

我对代码生成器也持反对态度。  
   
  首先  
  1、亢余代码大多数是因为抽象不够彻底,并不是实际需要。  
  2、虽然亢余代码能避免效率损失,但降低了代码的可读性。  
  3、滥用代码生成器会造成分析不够彻底,代码复用率低等很多问题。  
  4、大多数的实体类其实除了数据绑定外并没有参与业务逻辑运算,事实上他们根本就是一团数据而不是实体。Top

80 楼Samen168(Code to coding)回复于 2006-08-15 14:12:08 得分 0

1、亢余代码大多数是因为抽象不够彻底,并不是实际需要。  
        这个不知道是代码生成的错还是个人能力问题  
   
  2、虽然亢余代码能避免效率损失,但降低了代码的可读性。  
        如果对代码有效组织的能力都没有,怎么写可读性都好不到哪去  
   
  3、滥用代码生成器会造成分析不够彻底,代码复用率低等很多问题。  
        这个好像更是需求分析的工作  
   
  4、大多数的实体类其实除了数据绑定外并没有参与业务逻辑运算,事实上他们根本就是一团数据而不是实体。  
        实体是什么?看个人选择,有根本不带业务逻辑就是上面说的只是数据,有的带部份逻辑像DomainModel,有的当成业务类用(没几个人愿意再这样用),至于选择后有什么分别早就有个讨论过N次了Top

81 楼sekone()回复于 2006-08-15 14:16:39 得分 0

我对代码生成器也持反对态度。  
   
  首先  
  1、亢余代码大多数是因为抽象不够彻底,并不是实际需要。  
  2、虽然亢余代码能避免效率损失,但降低了代码的可读性。  
  3、滥用代码生成器会造成分析不够彻底,代码复用率低等很多问题。  
  4、大多数的实体类其实除了数据绑定外并没有参与业务逻辑运算,事实上他们根本就是一团数据而不是实体。  
  =============================  
  PetShop的思想就是一个表对应一个实体类,就抽象成一个对象,而这些实体类用代码生成器生成的跟你手工写的是一模一样的,根本不可能产生亢余代码(或者你是说这些实体类是亢余的,难到微软的开发团队都是白痴?),你难到要手工一个个写?  
   
  4、大多数的实体类其实除了数据绑定外并没有参与业务逻辑运算,事实上他们根本就是一团数据而不是实体。  
  ======================================  
  为什么要实体类?因为我要OOP的思想!Top

82 楼Samen168(Code to coding)回复于 2006-08-15 14:16:45 得分 1

并不想说什么好什么不好,其实只想说一句  
   
  先吧一些成熟的架构看明白了,知道别人为什么会选择(或推荐)这样的架构Top

83 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 14:18:04 得分 0

好像有点火药味了。  
   
  你用你的代码生成器,我用我的控件。  
   
  你认为没有冗余代码那就没有冗余代码了。  
   
  我不想在这方面争论些什么。  
   
  我向您道歉,并且收回我说过的关于代码生成器的话。  
   
  希望您能原谅。  
  Top

84 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 14:21:53 得分 0

我好像并没有说三层不好哇,我只是说了一下我的想法,编成程序的方法。  
   
  我也没有说一定不能分层,而且我也采用了分层的思路的。Top

85 楼int64(@163.com:所有的程序员都应该团结起来!)回复于 2006-08-15 14:40:10 得分 1

作项目不仅仅是开发,还有维护的Top

86 楼song1148()回复于 2006-08-15 14:52:56 得分 1

学习  
    支持  
      谢谢Top

87 楼song1148()回复于 2006-08-15 15:02:04 得分 1

看了   帮助很大   再次谢谢Top

88 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 15:15:02 得分 0

不客气。大家共同提高嘛。Top

89 楼bccu(风雨中人)回复于 2006-08-15 15:38:27 得分 1

长期以来,开发的思路跟楼主的相似。还没有真正体会到三层结构的优势。Top

90 楼angelhyli(雨儿)回复于 2006-08-15 15:53:18 得分 0

看了标题,兴奋而来,看了楼主的介绍,失望。  
  看来楼主还没有接触过大一点点的系统,估计做得最多的就是小网站。  
   
  至于楼主自认为接近Perfect的数据绑定和分页代码,我只能说可以改进的地方还有很多,最起码我自己用的就比楼主的简单一些,却万万不敢拿出来献丑。Top

91 楼angelhyli(雨儿)回复于 2006-08-15 15:56:59 得分 1

1、更换数据库也是很简单的事情(对于程序来说)  
   
  针对SQL编译一个dll,再针对OLEDB   编译一个dll,再针对Orcale   编译一个dll.....  
  ---------------------------------------------------------------------------------  
  此处更加不敢茍同。  
   
  当然,楼主的思想用于一个人和网页设计人员结合做小网站还是不错的。团队开发,如此设计,实在不堪设想。Top

92 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-08-15 16:09:12 得分 0

1、亢余代码大多数是因为抽象不够彻底,并不是实际需要。  
        这个不知道是代码生成的错还是个人能力问题  
   
  2、虽然亢余代码能避免效率损失,但降低了代码的可读性。  
        如果对代码有效组织的能力都没有,怎么写可读性都好不到哪去  
   
  3、滥用代码生成器会造成分析不够彻底,代码复用率低等很多问题。  
        这个好像更是需求分析的工作  
   
  4、大多数的实体类其实除了数据绑定外并没有参与业务逻辑运算,事实上他们根本就是一团数据而不是实体。  
        实体是什么?看个人选择,有根本不带业务逻辑就是上面说的只是数据,有的带部份逻辑像DomainModel,有的当成业务类用(没几个人愿意再这样用),至于选择后有什么分别早就有个讨论过N次了  
   
  =============================================================  
   
  代码生成器是好东西,但是如果依赖于它就会产生问题。任何东西都有其适用场景,代码生成器也有它的缺点,我反对代码生成器是说在做一个系统时首先想到的不应该是生成一大堆代码。如果分析得好的话,事实上代码并不会有想象的那样多。  
   
  况且,我更倾向于微软的那种做法,直接解析和编译xsd或者aspx文件,而不是弄一大堆代码出来给我们看……。  
   
  我希望你看懂了我的意思,而不是盲目的维护你的生成器。因为我自己也有代码生成器。Top

93 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-08-15 16:10:34 得分 0

sekone  
   
  对你只有五个字……  
  无知者无畏。Top

94 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 16:16:17 得分 0

看来你是有很多的经验了,为何不拿出来共享一下呢?Top

95 楼simonzone(马叉虫)回复于 2006-08-15 16:26:04 得分 0

冒泡泡。。。~~Top

96 楼sekone()回复于 2006-08-15 16:41:52 得分 0

Ivony()   (   )   信誉:100    
  真不知道你两颗星是怎么拿来的  
   
  4、大多数的实体类其实除了数据绑定外并没有参与业务逻辑运算,事实上他们根本就是一团数据而不是实体。  
  ================================  
  你认为实体类非得要有业务逻辑运算吗?自己再去看看面向对象把!  
   
  一个实体最重要的就是由他的属性组成,而每一个属性就是一个数据,就是你所说的“一团数据”,一个实体并不一定要有动作(也就是你所说的“业务逻辑运算”),现实中一把椅子就是一个实体,他就没有动作,却有属性,如宽,高等  
  先反如果没有属性而只有方法的类能叫实体类吗?他由什么组成一个实体?  
   
  PetShop里面的实体模型类有哪一个是带逻辑运算的?都只有你所说的“一团数据”!  
  一个实体需不需要方法是由实体本身和设计者决定的。Top

97 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-08-15 16:46:40 得分 0

敝人不想与一个Object讨论什么问题……  
  见谅……Top

98 楼sekone()回复于 2006-08-15 16:53:26 得分 0

代码生成器是好东西,但是如果依赖于它就会产生问题。任何东西都有其适用场景,代码生成器也有它的缺点,我反对代码生成器是说在做一个系统时首先想到的不应该是生成一大堆代码。如果分析得好的话,事实上代码并不会有想象的那样多。  
  =====================================================  
  你以为所有的代码生成器,都做的象你那么厉害么,都会生成"一大堆代码"!Top

99 楼lrobbie(给加薪的老板才是好老板)回复于 2006-08-15 16:57:30 得分 2

呵,做做小网站骗两钱可以考虑楼主的做法Top

100 楼nonesharp(无锋)回复于 2006-08-15 16:57:46 得分 0

挺热闹,没想一个下午这么多人讨论,不错不错。  
  我还是坚持使用代码生成器的,但是这个并不代表我会放弃控件啦之类的其它东西,并不矛盾的。  
  代码生成器的好处不仅仅是可以少写代码,我觉得,还有一点也很重要,就是它能辅助规范整个团队的编码规范,因为相当数量的代码都由生成器生成了,其他人就必须要跟着已有的习惯走。  
  在我的团队里,所有的项目都是基于同一个平台的(自建),所有的项目也都是用统一的生成器生成基础代码的,因此,新招聘进来的人,只要看懂一个项目,其它项目也就能够上手了。无论是B/S的也好,C/S的也好。  
  Top

101 楼coffeewar(苦咖啡)回复于 2006-08-15 17:05:38 得分 1

mark  
  有空再看Top

102 楼anheizhizi(目标:★★★★★)回复于 2006-08-15 17:06:48 得分 1

楼主自己都说了是ASP.NET   ,简单的说是小网站.  
  但   三层   只适用于   ASP.NET   吗?   只适用于   小网站吗?   这个答案不用我再来说了吧.  
  对于越大型的项目,层次化越是必要和重要  
   
  楼主共享下你的   数据访问层   看看吧,当学习Top

103 楼john_huang(追梦者)回复于 2006-08-15 18:08:26 得分 0

upTop

104 楼losteveb()回复于 2006-08-15 18:37:07 得分 0

markTop

105 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 19:02:37 得分 0

下班了,开始集中回复了。  
   
  to   :winner2050(winner)      
  你用你的,我用我的,感觉好用就可以了呀。不涉及到谁明白不明白的问题吧。  
   
  to:truecoffeefox(咖啡狐)      
  明天我会开源我的数据访问层的代码的,还请大家多排板砖  
   
   
  to:nekiy(我只是个做美工的!)   、   kason_j(伊松)     、wufato(.net学习提高中)、whChina(江城)(老温)      
   
  大家共同进步。  
   
   
  to:jc15271149(嘿咻)  
  现在先考虑网站的情况  
   
   
  to:ioleon13  
  不要急,慢慢积累经验。我都熬了四年多了。  
   
  to:szc21(  
  那里没有想通呢?  
   
  to:yzx110(原振侠)  
  复杂的情况会有其他的方法应对。但是基本是这个思路。  
   
  to:zzmsl(周先生)      
  SqlHelp   还是考虑换一换吧。  
   
   
   
   
  Top

106 楼jinliangliu(KingNa)回复于 2006-08-15 19:04:44 得分 1

强贴留名。Top

107 楼fatcatman()回复于 2006-08-15 19:07:25 得分 0

markTop

108 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 19:19:07 得分 0

to:oldmoon(浪者)      
   
  表单的处理方法,将在明天的数据访问层里介绍。  
   
  to:anheizhizi(目标:★★★★★)      
   
  如果在网站范围内都没有弄明白的话,那么再扩大范围不是就更不好懂了吗。  
   
   
  to:使用代码生成器的人  
   
  我只简单的看了几个代码生成器,做东西倒是挺快的,一下子一大堆的页面就出来了。  
   
  但是   代码生成器   只是自己用自己的才会感觉好用,除非你我的思路是完全一样的。  
  或者有一个统一的标准。  
   
  很遗憾我感觉三层并没有成为一种标准,因为连数据访问层的定义都还没有明确,如果您反对的话,那么请您给出一个定义,看看有没有反对的(不包括我)。  
   
   
  另外我再明确一下,我说的“控件”并不是指的系统带的那些,而是说我自己编写的自定义服务器控件。比如分页控件、表单控件等。  
   
  (还想问一下,你们遇到需要分页显示数据的情况是怎么处理的?)  
   
   
   
   
  Top

109 楼flygoldfish(长江支流)回复于 2006-08-15 19:39:10 得分 1

不我争了,发表一下看法可以。  
  人家楼主只是说说自己的实现,只是说适合自己和自己的项目,并没有说这好那好,也没有卖弄什么,为什么总是不基于问题而总是有攻击?  
   
  俺在这最后说一句话:  
   
  你让狗去吃燕窝?有些时候是可以,有些时候是不可以,看什么情况?  
  但是:  
  屎,有屎存在的道理  
  米,有米存在的道理  
  燕窝,有燕窝存在的道理  
   
  ...  
   
  Top

110 楼flygoldfish(长江支流)回复于 2006-08-15 19:45:13 得分 0

见鬼,还不是最后一次回此贴,写错了。  
   
  不要争了,存在就是硬道理,方便就是实用,适合自己就是好东东。。。  
   
  屎,有屎存在的道理  
  米,有米存在的道理  
  燕窝,有燕窝存在的道理  
   
  。。。Top

111 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 19:49:11 得分 0

我怎么感觉有点别扭呢?  
   
   
  感谢大家的支持!Top

112 楼insnowind(喜欢穿着厚厚的棉衣~戴着围巾和手套~踏雪而行的感觉~~~)回复于 2006-08-15 20:01:11 得分 1

留名!Top

113 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 20:22:54 得分 0

http://blog.csdn.net/jyk/archive/2006/08/15/1065313.aspx  
   
  blog居然有好用了,早上的时候提交了半个小时都没有结果,也不知道是怎么弄的,又提交上去了。  
   
  Top

114 楼Afritxia(能活不易)回复于 2006-08-15 20:47:10 得分 1

先支持一下!  
   
  我比较习惯使用三层结构进行   Web   开发。其实清楚其结构以后,并不会觉得它很复杂。  
   
  顺便祝贺一下   jyk,你的楼层比我当初的那个要高好象……Top

115 楼lubosun(大白菜)回复于 2006-08-15 20:53:01 得分 1

正在学习中。。。Top

116 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 20:58:05 得分 0

to:   Afritxia  
   
  时代不同了吗,呵呵。  
   
  对了上回你给我的那个代码我找不到了。  
   
  Top

117 楼okeyes(竹子)回复于 2006-08-15 21:01:13 得分 0

mark   downTop

118 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 21:10:15 得分 0

我的数据访问层已经发表到我的   blog里面了,  
   
  http://blog.csdn.net/jyk/category/181415.aspx  
   
  有源代码、使用说明和源代码下载。  
   
  Top

119 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 21:11:25 得分 0

十、 使用示例  
  以新闻系统为例  
  1、 用查询语句的方式获取新闻列表,然后绑定Repeater控件。  
  DataAccessLayer   dal   =   new   DataAccessLayer();  
  Rpt.DataSource   =   dal.RunSqlDataTable("select   NewsID,addedDate,title   from   news   ");  
  if   (dal.ErrorMsg.Length   >   2   )  
  {  
      Response.Write(dal.ErrorMsg   );   //输出错误信息  
      return;  
  }    
  Rpt.DataBind();  
   
  2、 用存储过程的方式获取新闻列表,然后绑定Repeater控件。  
  DataAccessLayer   dal   =   new   DataAccessLayer();  
  Rpt.DataSource   =   dal.RunStoreDataTable("Proc_News_list");  
  if   (dal.ErrorMsg.Length   >   2   )  
  {  
      Response.Write(dal.ErrorMsg   );   //输出错误信息  
      return;  
  }  
  Rpt.DataBind();  
   
  3、 用string[]的方式获取一条新闻纪录。然后给Label控件赋值。  
  DataAccessLayer   dal   =   new   DataAccessLayer();  
  string   sql   =   "select   Title,AddedDate,Content   from   News   where   NewsID="   +   NewsID  
  string[]   Infos   =   dal.RunSqlStrings(sql);  
  if   (dal.ErrorMsg.Length   >   2   )  
  {  
  Response.Write(dal.ErrorMsg   );   //输出错误信息  
  return;  
  }  
  if   (Infos   ==   null)  
  {  
  Response.Write("没有这条新闻!");  
  Response.End();  
  }  
    Lbl_Title.Text   =   Infos[0];  
    Lbl_AddedDate.Text   =   Infos[1].Split('   ')[0];  
    Lbl_Content.Text   =   Infos[2];  
   
  4、 用DataRow的方式获取一条新闻纪录。然后给Label控件赋值。  
  DataAccessLayer   dal   =   new   DataAccessLayer();  
  string   sql   =   "select   Title,AddedDate,Content   from   News   where   NewsID="   +   NewsID  
  DataRow   Infos   =   dal.RunSqlDataRow(sql);  
  if   (dal.ErrorMsg.Length   >   2   )  
  {  
  Response.Write(dal.ErrorMsg   );   //输出错误信息  
  return;  
  }  
  if   (Infos   ==   null)  
  {  
  Response.Write("没有这条新闻!");  
  Response.End();  
  }  
    Lbl_Title.Text   =   Infos["Title"].ToString();  
    Lbl_AddedDate.Text   =   Infos["AddedDate"]   .ToString().Split('   ')[0];  
    Lbl_Content.Text   =   Infos["Content"]   .ToString();  
   
  5、 用InsertDataStr和UpdateData实现添加、修改新闻。同时用RunSqlExists判断新闻标题是否重复。  
  //判断是修改还是添加  
  bool   isAdd   =   false;  
  if   (DG.SelectedIndex   ==   -1)     //利用DataGrid的状态来判断是添加还是修改。  
  isAdd   =   true;  
   
  //设定字段。这里一定要用一个数组来表示,这是   InsertDataStr   函数的参数的要求!  
  string[]   str1   =   new   string[2];  
  str1[0]   =   "title";  
  str1[1]   =   "Content";  
   
  //获取用户输入的信息,并且过滤危险字符  
  //这里一定要用一个数组来表示,这是   InsertDataStr   函数的参数的要求!  
  string[]   str   =   new   string[2];  
  str[0]   =   this.Txt_Title.Text.Trim().Replace("'","");  
  str[1]   =   this.Txt_Content.Text.Trim().Replace("'","");  
  #region   数据验证  
  if   (str[0].Length   ==   0   )  
  {  
  Page.RegisterStartupScript("a",Functions.myAlert("请填写新闻标题!"));  
  return;  
  }  
   
  DataAccessLayer   dal   =   new   DataAccessLayer();  
  if   (isAdd)  
  {  
  if   (dal.RunSqlExists("select   top   1   '1'   from   news   where   title='"   +   str[0]   +   "'"   ))  
  {  
  Page.RegisterStartupScript("a",Functions.myAlert("已经有这个新闻标题了!"));  
  return;  
  }  
  }  
  else  
  {  
  if   (dal.RunSqlExists("select   top   1   '1'   from   news   where   title='"   +   str[0]   +   "'   and   NewsID   <>"   +     DG.SelectedItem.Cells[0].Text))  
  {  
  Page.RegisterStartupScript("a",Functions.myAlert("已经有这个新闻标题了!"));  
  return;  
  }  
  }  
  #endregion  
  if   (isAdd)  
  //添加新闻  
  dal.InsertDataStr("News",str1,str);  
  else  
  //修改新闻  
  dal.UpdateData("News",str1,str,"   NewsID="   +   DG.SelectedItem.Cells[0].Text);  
   
  //检查是否出现异常  
  if   (dal.ErrorMsg.Length   >   2   )  
  {  
  Response.Write(dal.ErrorMsg   );     //输出错误信息  
  return;  
  }  
  if   (isAdd)  
  //添加成功。进行相应处理  
  else  
  //修改成功。进行相应处理  
   
  6、 用RunStore   用的方式添加修改新闻  
  //判断是修改还是添加  
  bool   isAdd   =   false;  
  if   (DG.SelectedIndex   ==   -1)     //利用DataGrid的状态来判断是添加还是修改。  
  isAdd   =   true;  
   
  //获取用户输入的信息,存储过程的方式就不用过滤了  
  string   NewsTitle   =   this.Txt_Title.Text.Trim();  
  string   NewsContent   =   this.Txt_Content.Text;  
   
  //   数据验证  
  if   (str[0].Length   ==   0   )  
  {  
  Page.RegisterStartupScript("a",Functions.myAlert("请填写新闻标题!"));  
  return;  
  }  
  //标题是否重复的判断由存储过程来实现  
   
  DataAccessLayer   dal   =   new   DataAccessLayer();  
  //添加存储过程的参数  
  dal.addNewParameter("@title",NewsTitle,100);  
  dal.addNewParameter("@Content",NewsContent);  
  //output型的参数  
  dal.addNewParameter("@ReturnMsg",ParameterKind.NVarChar   );  
   
  if   (!isAdd)  
  //修改新闻,需要给   @NewsID   负值。  
          dal.addNewParameter("@NewsID",Int32.Parse(DG.SelectedItem.Cells[0].Text))  
   
  //执行存储过程  
  dal.RunStore("Proc_News_ModData");  
   
  //检查是否出现异常  
  if   (dal.ErrorMsg.Length   >   2   )  
  {  
  Response.Write(dal.ErrorMsg   );     //输出错误信息  
  return;  
  }  
  string   err   =   dal.getParameter("@ReturnMsg");//获取参数的返回值  
  if   (isAdd)  
  {//添加状态  
  if   (err.Length   >   1)  
  {  
  //显示存储过程里面返回的错误信息,比如新闻标题重名等。  
  }  
  else  
  {  
  //添加成功  
  SetFormEmpty();  
  }  
  }  
  else  
  {//修改状态  
  if   (err.Length   >   1)  
  {  
  //显示存储过程里面返回的错误信息,比如新闻标题重名等。  
  }  
  else  
  {  
  //修改成功  
  SetFormVisible(false);  
  }  
  }  
   
  7、 用RunSql   删除新闻  
  DataAccessLayer   dal   =   new   DataAccessLayer();  
  dal.RunSql("delete   from   News   where   NewsID="   +   e.Item.Cells[0].Text);  
  //检查是否出现异常  
  if   (dal.ErrorMsg.Length   >   2   )  
  {  
  Response.Write(dal.ErrorMsg   );   //输出错误信息  
  return;  
  }  
   
  8、 说明  
  除了添加修改的地方,代码都是非常简洁的。可以说只用了一行就达到了目的。由于省去了实体层,数据访问层也变成了DLL类库,所以说呢,从表面上看程序的结构就变成了一层结构了,也就是说只需写这些代码就可以实现一个模块的基本功能了。  
  再来看看添加修改的地方。虽然代码好像多了一点,但是合并了添加、修改的共同的地方,减少了三分之一的代码。可能会比三层结构的UI层的代码量多一些,但是没有实体层、业务逻辑层和数据访问层的代码。重整体上来说减少了三倍的代码量。  
  修改上也是很方便的。如果要修改字段名称的话,只需要修改str1数组里对应的值就可以了;添加字段呢,只需要增加str1和str数组的大小,并负值就可以了。省去了其他层的修改(因为根本就没有在其他的地方写代码!)  
   
  Top

120 楼puny(寒束)回复于 2006-08-15 21:14:48 得分 0

还是各个层分清楚,各个业务分清楚,写程序和维护都会轻松很多。Top

121 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 21:14:49 得分 0

数据访问层的相关讨论请到这里:  
   
  http://www.80diy.cn/Expert/TopicView3.asp?id=4952051  
   
  Top

122 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-08-15 21:16:55 得分 1

/home/default.aspx?q=20060228/13/4583043.html  
   
  我的数据访问帮助器,基于SQL语句的。  
   
  另外我也有分页架构,明天公布出来。Top

123 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-08-15 21:19:15 得分 1

有一点我很支持搂主,程序是一门艺术,简洁、优美、流畅的代码才是好的代码。Top

124 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 21:20:13 得分 0

对于网站来说,业务逻辑是什么呢?Top

125 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-08-15 21:24:45 得分 0

一般来说,网站的业务逻辑都是UI逻辑。  
   
  真正复杂的业务逻辑都集成在了用户身份验证授权等上面了。  
   
  或者是算法,而那些算法也不算是什么业务逻辑。Top

126 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 21:39:30 得分 0

其实我感觉对于网站来说根本就没有什么业务逻辑。  
   
  也就只有用户身份验证授权能够算得上了,但是有些网站是根本就没有用户的。  
   
  即使有的话,也不用很麻烦的。写个类就搞定了。  
   
  这里有我的处理用户身份的代码。  
   
  http://blog.csdn.net/jyk/archive/2006/08/15/1067382.aspx  
   
   
   
  Top

127 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 21:41:51 得分 0

一般来说,网站的业务逻辑都是UI逻辑。  
   
  =============  
   
  那么这样的逻辑写在哪一层呢?  
   
  Top

128 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-08-15 21:43:12 得分 0

抱歉……我的用户身份验证的代码牵涉到公司的安全问题,所以不能公开了。  
   
  不过蛮复杂的,因为他的核心思想是实现不同环境下的身份上下文,如在WinForm中、Web中等等。Top

129 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-08-15 21:50:02 得分 0

一般来说,数据层提供数据供页面进行绑定,就是大部分网站的页面了。  
  这些数据大部分是不需要加工直接绑定的。  
  但也有一些需要处理,如性别转换为男女,生日转换为年龄,UBB代码解析等。  
   
  我这里所说的网站是指在我们国家最常见的综合网站(非交互网站),交互网站比较麻烦些。  
   
  需要数据处理的一般都是界面逻辑,如将true转换为男而false转换为女。这仅仅是数据表现形式的问题,一般可以在页面上直接解决,如果绑定的地方比较多,则可以分离出数据绑定层负责把数据转换成各种形式的字符串。  
   
  刚才说到网站的业务逻辑大多是与身份验证集成的。这是因为一个网站的业务逻辑无非是什么东西能显示,什么东西不能显示而什么功能不开放等。  
  这完全是授权的问题,根据授权显示不同的页面。Top

130 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-08-15 21:51:46 得分 0

这些非交互性网站(发布型网站)大部分的交互在后台。而后台主要的功能也无非是将表单的数据灌输到数据表中去。Top

131 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-15 22:06:17 得分 0

如性别转换为男女  
   
  =========  
   
  我一开始也是用   0、1   标识男、女,但是后来感觉太麻烦了,不如直接把“男”、“女”扔到数据库里算了,简单明了。因为有些人会用   “1”标识“男”,而有些人却用“1”标识“女”。头痛的是——根本就没有说明。  
   
   
  看了一下   Ivony   说所的,基本上就是修改sql语句(where后面加不同的条件)的事情。呵呵。  
   
   
  Top

132 楼nonesharp(无锋)回复于 2006-08-15 23:23:15 得分 1

热闹的。  
  可能我和楼主做的系统类型不同,所以观点很不相同,网站以前我从来没有亲手做过,或许网站的确按照楼主这么写比较方便。  
  我不大赞同楼主贴出来的代码,看上去这些代码片段应该式在codebehind中的吧。可以我定的规矩有点过,不过我一直要求所有人的不允许在form或者page的代码中出现和sql相关的代码,这点几乎是天条,必须贯彻。因为很多相关逻辑可能被Winform调用,可能是webform,可能是webserbice,可能是winservice,甚至可能是wince上的程序。  
   
  不过最近几天我倒是自己在做个网站玩玩,虚心请教各位高手:比如说我的网站上有个论坛,我想把所有的帖子都生成静态的页面,这么做是否划算?再则,在处理这些静态页面分页的时候,若分10页,那么如果多一条记录,岂不是10个页面都需要被刷新修改?有啥好方法不?  
   
  另:以前有个同事做公安局系统的,据说公安局系统中,性别分为:男、女、男变女、女变男、男变女变男、女变男变女,搞死。Top

133 楼Ivony(授人以鱼不如授人以渔,上海谋生)回复于 2006-08-16 00:19:09 得分 1

不过最近几天我倒是自己在做个网站玩玩,虚心请教各位高手:比如说我的网站上有个论坛,我想把所有的帖子都生成静态的页面,这么做是否划算?再则,在处理这些静态页面分页的时候,若分10页,那么如果多一条记录,岂不是10个页面都需要被刷新修改?有啥好方法不?  
   
   
   
  生成10个页面不是很费事的,一般都是直接生成十个,生成页面的主要瓶颈在磁盘和数据库上。  
   
   
   
  不同的项目有不同的做法,像网站,是断然没有任何可能整个WinForm来看的。虽然不推荐页面直接写SQL,但实际上有时候页面就是个视图或者是几个视图而已。而显示那些视图实际上完全是UI也就是页面来决定的。并不会像传统的软件先想好这个Form要干什么,因为布局美观也许更重要。Top

134 楼xyxweb(夜行人)回复于 2006-08-16 00:37:15 得分 1

好帖,顶Top

135 楼LoveCherry(论成败,人生豪迈;大不了,重头再来!^_^)回复于 2006-08-16 06:43:19 得分 0

还是要看系统的,一般发布性/信息性网站的业务逻辑不是很强,但是行业性的网站业务逻辑还是很强的,这些网站有大量的用户和系统之间的交互,比如银行/旅游/房产等网站。对于业务逻辑不强而访问量又大的信息网站还是注重效率比较好,对于业务逻辑复杂、模型复杂还是注重维护成本比较好。  
   
  对于静态页面我的看法是变动不大的再去考虑静态的,比如论坛的帖子列表、论坛分类等,但是帖子详细内容用动态就不太适合了,对于数据频繁改动的内容生成静态页面花费的时间非常可观,通常我觉得只要做好缓存,甚至可以是二级缓存,选择何时的缓存策略就可以达到性能要求了。对于非门户网站,静态页面的效率没有想象的这么高。Top

136 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-16 06:52:52 得分 0

老大来的好早哇  
   
  我现在理解了csdn为什么药用静态页面了。  
   
  因为动态页面很占用cpu,静态的可以节省很多cpu的资源。  
   
  想象一下,一天csdn的访问量会有多大,全部都是动态的需要多少个cpu呀。Top

137 楼fanliang11(以编程为兴趣,以盖茨为激励)回复于 2006-08-16 08:32:20 得分 1

好帖,我也顶一个吧!!希望以后多出现此类好文章Top

138 楼fanliang11(以编程为兴趣,以盖茨为激励)回复于 2006-08-16 08:35:27 得分 1

难道LZ没在分层架构加设计模式,比如工厂模式,或者加接口层吗?Top

139 楼jyk(今天由我来写的代码,明天就让程序自己完成!喜欢编程。和气生财。共同提高。共同进步!)回复于 2006-08-16 08:46:07 得分 0

工厂模式,或者加接口层   这些我都不会呀。  
   
  不用这些我也写了这么多的网页了呀。没感觉一定要加上这些呀。Top

140 楼job_2006(初学.net)回复于 2006-08-16 08:52:57 得分 1

顶先Top

141 楼LoveCherry(论成败,人生豪迈;大不了,重头再来!^_^)