请指点--关于数据访问层(1)

  在发表这篇随笔之前,我犹豫了很久,到底要不要把这篇随笔放在首页,作为一篇菜鸟的随笔,不是太合适放在首页,但是如果不放首页,可能这篇随笔很快就沉了,所以,我鼓起勇气把它放在首页...

  写这篇随笔主要是由于我在做数据访问层时碰到了问题,我有在博客园群里请教别人,也得到了大家热心的帮助,但QQ上的消息沉得比博客可快得多了,所以我就想把它放到博客园上.....不说了,切入正题吧。

  现在要弄一个简单的视频网站,有管理员、用户、视频类别、视频、管理员和用户可以上传视频、对视频进行评论。

我的意图:在这篇随笔中,先抛开业务逻辑层和表现层,只看这个网站的数据访问层,我想要让这个DAL层能够实现数据库无关,同时能更加符合面向对象的设计思想,做这个更多的是为了学习,所以我不想采用一些现成的东西,希望能对其慢慢改进,在改进中让自己得到锻炼。

下面是我的DAL类图:



说明:IDatabase是一个接口,定义了一些执行SQL语句或存储过程的方法,上图中只标出了三个,SQLServer和Oracle是两个具体的数据库,实现IDatabase接口,IDAL是一个表示对Video、User、Admin、Comment进行管理的接口,其中的CreateDb()方法从配置文件中读取数据库类型,然后利用反射创建该具体数据库(SQLServer类或Oracle类)并返回,其它方法全部都利用CreateDb()返回的数据库类来执行相应的Sql语句或存储过程,其中GetCount()是返回该对象的总数量(如Video的总数、User的总数),GetItem(int id)通过该对象的id(在数据库中是主键)返回对象(比如VideoDAL中的GetItem(int id)就通过数据库中video的ID返回Video对象),GetList就是返回对象列表(如VideoList,UserList),GetPagedListOrderByPK(int startRow, int maxRows, SortType sortType)也是返回一个列表,但它是分页时当前页应该显示的那部分对象列表,startRow和maxRows是该页的起始行号和取出的最大记录数(可以认为是page size),方法体中是与数据库交互,取出数据,SortType是一个枚举,有ASC和DESC两值,代表排序规则,结果是按主键排序的。

下面是业务对象(这个叫法不知道是不是有问题,因为它们仅仅只是对数据库相应表字段的一个映射,只不过多了两三个属性)



上图中的User类、Video类等中拥有数据库中对应表的所有字段(数据库中有Admin、User、Video、VideoSort、Comment表),我没有画出来,在User类中,有Videos和Comments属性,表示某用户上传的视频列表和发表的所有评论列表,其它类中也有类似的属性。

我现在所能想到的就是这样,但我知道,这里面存在着很多很多的问题,只是我的水平比较菜,不知道要如何改进,所以斗胆把它放到首页,希望能得到大家的指点。大家可以放心的说,完全不用担心会伤害我的自尊心,OK,来吧。。

Tag标签: 数据访问层,DAL
posted @ 2008-04-16 23:15 水言木 阅读(2446) 评论(37)  编辑 收藏 所属分类: Design Patterns

  回复  引用  查看    
#1楼 2008-04-17 00:27 | Clark Zheng      
不如使个轻量的框架,譬如IBatisNet
  回复  引用  查看    
#2楼 2008-04-17 01:12 | 预备役中尉      
你想要干什么?
  回复  引用    
#3楼 2008-04-17 02:40 | 苏州网站建设 [未注册用户]
你觉得有什么问题呢?
  回复  引用  查看    
#4楼 2008-04-17 08:21 | brightwang      
还是推荐你用ORM工具。。。
  回复  引用  查看    
#5楼 2008-04-17 08:38 | Yannic Yang      
你确定你需要支持多种数据库吗,不是的话就去掉那块功能
如果按照大牛们的想法,肯定能给你找出不少的orm或需要用的模式,但到底有没必要使用只有你最了解
所以建议把系统做出来,发现解决不了的问题再重构,先别考虑那么多了
  回复  引用  查看    
#6楼 2008-04-17 08:48 | Justin      
是有点没看出来你想做什么
建议先把文章修改一下,加上每个部分的设计初衷,这么设计为了解决什么问题,优缺点分析等,这样一来可能自己就能找出问题了
  回复  引用    
#7楼 2008-04-17 08:52 | jackyw [未注册用户]
你这种结构无法真正实现数据库无关,一旦使用的sql语句有差异就不行了。
IDAL的方法里使用object做为参数,不是强类型,抽象出来就没什么意义了
  回复  引用  查看    
#8楼 2008-04-17 09:55 | Zealic      
新手不推荐使用框架

虽然楼主的设计很原始
但是已经比很多人(只有一个 IDatabase 或直接在界面层拼接sql)好多了
设计能力的提高方式就是
自己设计
实现它
发现问题
改进

如此不断循环
才能真正得到能力的提高
框架,只是简化你的工作而已,除非你想做代码工人
它会让你看不到很多东西
当然,对于能者来说,它是被看透了的



  回复  引用    
#9楼 2008-04-17 10:21 | Kevin Woo [未注册用户]
你就这样做下去,你可以遇到很多问题的,逐一解决就是进步。
针对6楼的回复,你可以为实体类提供一个基类EntityBase。
  回复  引用  查看    
#10楼 2008-04-17 10:25 | 莫耶      
同意7楼的观点
实践出真知
如果一开始就用成熟的框架
确实是方便
但也只能是“知其然不知其所以然”
先自己做个最简单的框架
才能学到更多的东西~
  回复  引用    
#11楼 2008-04-17 10:43 | ddf [未注册用户]
IDAL接口声名的不合理,建议增加一个实体层,IDAL接口更有针对性。
  回复  引用    
#12楼 2008-04-17 11:11 | hoysea [未注册用户]
IDAL接口没有意义,Video,User,Admin,Comment应该定义各自的接口,并根据数据库的不同派生不同的子类,请参考PetShop4.0中实体层的做法.
  回复  引用  查看    
#13楼 2008-04-17 11:26 | Tony Zhou      
admin,user,video应该有接口
他们都comment,comment行为应该有个类,有接口。
  回复  引用  查看    
#14楼 [楼主]2008-04-17 12:13 | 水言木      
@jackyw
@Kevin Woo
@ddf
你们的意思是指加一个实体基类,如EntityBase,然后Video, User, Admin, Comment都继承EntityBase,然后在IDAL中的方法就返回EntityBase类型(或用EntityBase作方法参数),而不是ojbect?
但是Video,User,Comment都没有太大共性啊,那么EntityBase里应该有什么属性或方法呢?请指点:)
  回复  引用  查看    
#15楼 [楼主]2008-04-17 12:39 | 水言木      
@预备役中尉
@Justin
谢谢提醒,我的意图是:在这篇随笔中,先抛开业务逻辑层和表现层,只看这个网站的数据访问层,我想要让这个DAL层能够实现数据库无关,同时能更加符合面向对象的设计思想,做这个更多的是为了学习,所以我不想采用一些现成的东西,希望能对其慢慢改进,在改进中让自己得到锻炼。
  回复  引用  查看    
#16楼 [楼主]2008-04-17 12:40 | 水言木      
@brightwang
我仅仅知道ORM的大体作用是什么,刚打算去看点相关的知识..
  回复  引用  查看    
#17楼 [楼主]2008-04-17 12:42 | 水言木      
@Zealic
谢谢:) 我正是想通过慢慢改进一个糟糕的设计来提高自己
  回复  引用  查看    
#18楼 2008-04-17 13:30 | 李战      
路过
  回复  引用  查看    
#19楼 2008-04-17 14:40 | 风海迷沙      
新手炫耀贴
我的很多业务都被存储过程封装掉了,所以业务层和数据层实际就做成了一个实例层。也想为以后的linq升级做准备。
  回复  引用  查看    
#20楼 [楼主]2008-04-17 16:02 | 水言木      
@风海迷沙
能更具体点么,就算把SQL语句封到存储过程中,但是在C#代码中不是也还要涉及不同数据库的问题么?请指点:)
  回复  引用  查看    
#21楼 2008-04-17 17:04 | 王德水      
参考petshop
  回复  引用  查看    
#22楼 2008-04-17 21:11 | WhyCome[at]live.cn       
 我也路过
  回复  引用  查看    
#23楼 2008-04-18 03:38 | 镜涛      
呵呵,同意七楼的观点,实现应用过程不断改进提高才是硬道理!
  回复  引用  查看    
#24楼 2008-04-18 09:35 | 许晓光      
走过
  回复  引用  查看    
#25楼 2008-04-18 09:59 | 小瑞克      
Linq来了,乱了
  回复  引用  查看    
#26楼 2008-04-18 10:16 | looping      
@Zealic
说的很好。
  回复  引用  查看    
#27楼 2008-04-18 12:50 | magiclee      
@hoysea
idal接口无意义我同意,虽然大部分时间用到的业务实体的逻辑操作由guid四个操作组成,但是每个业务实体都有自己的独特的操作返回的数据类型都不一样,没有必要提供一个接口来限定自己。而且,接口返回object或者其他基类数据,对于接口的使用者需要转换,最关键的是这种数据在穿透webservices时会丢失数据,序列化可是只认编译类型而不是运行时类型的。
  回复  引用  查看    
#28楼 [楼主]2008-04-18 13:26 | 水言木      
@magiclee
谢谢!现在看来,IDAL中返回object存在着大问题。
您说“没有必要提供一个接口来限定自己”,是说让VideoDAL, UserDAL, AdminDAL这些不继承任何类而单独存在么?
  回复  引用  查看    
#29楼 2008-04-18 18:43 | brightwang      
其实petshop里结构和LZ的大同小异,还有上面那些说什么用ORM框架的是代码工人纯属胡说,难道用datareader去映射一个实体类,手工映射就真的很了不起?那才真的是浪费时间。
  回复  引用    
#30楼 2008-04-18 23:17 | 天下事 [未注册用户]
看来你是不打算考了...


  回复  引用    
#31楼 2008-04-18 23:18 | 天下事 [未注册用户]
...考研了
  回复  引用  查看    
#32楼 2008-04-19 13:37 | magiclee      
@水言木
对的,各个业务对象的dal没有必要提取接口,仅仅是VideoDAL, UserDAL, AdminDAL就够了。原因如下:
1各业务对象的和外界交互的接口不一样,VideoDAL是video,UserDAL是user。。。
2各业务对象封装的数据库操作也不一样,虽然很多时候都有gucd基本操作,但是还其他的复杂业务操作,尤其是连表查询时返回多个表的数据。
所以,从功能划分上他们是没有什么共同的。如果你提取一个接口仅仅是提供一个gucd操作的基实现,我觉得使用没有必要如此,使用代码生成器一样可以达到同样的效果。
当然某些操作可能类似,比喻获取分页数据操作,这个时候可以考虑重构出部分共用代码,作为helper类,但是避免乱用继承。
  回复  引用  查看    
#33楼 [楼主]2008-04-19 14:14 | 水言木      
@magiclee
谢谢magiclee,后来我模仿Petshop改造了数据访问层,现在的主要问题变成“贫血模式”和“充血模式”的选择了
  回复  引用  查看    
#34楼 2008-04-19 14:53 | magiclee      
@水言木
不客气o(∩_∩)o...,偶也是最近才在园子写点东西的,以前都是只看贴不回的角色o(∩_∩)o...

关于贫血模式和充血模式的选择,是历来一个颇受争议的问题。贫血模式和充血模式的根本区别在于,贫血模式仅仅是对数据的封装,而充血模式不仅对数据进行了封装而且对数据的操作(这里的操作指对数据的存取操作)也进行了封装。
而表模式是贫血模式的一种常用做法。
选择何种模型与系统的复杂度有关和系统部署架构都有关系。通常,对于单机数据库程序、c/s架构,b/s架构(其实b/s架构可以将web服务器看做是客户端),这类采用充血模式开发效率会很不错的。而微软再次提供了一套类型化dataset和dataset作为数据模型,对这种模式进行了很好的支持。
对于贫血的模式而言,我觉得更多的是体现在soa架构上,将对数据的操作提取为一个个的服务,数据模型仅仅是存取数据,支持序列化。这种架构也是现在非常流行的。

最后,我看了上面的帖子,觉得大家是否用对象还是用那个关联id的问题,我觉得这个是是否采用表模式的问题,而数据模型的模式没有什么关系。我觉得,如果系统简单或者业务简单,采用表模式就可以了,但是如果业务复杂,才用表模式就使得客户端的代码极难维护,在我看法的plm系统中,一个零部件结构业务对象通常设计多张表,还会存在树结构,曾经我们是采用表模式来处理,效果很不理想,现在我将业务对象封装成一个树结构,提供一个处理该结构的web服务,效果就好多了。
  回复  引用  查看    
#35楼 [楼主]2008-04-19 17:43 | 水言木      
@magiclee
再次感谢!
我看了点充血模式和贫血模式的文章,那看来不论我在《请指点--关于数据访问层(2)》中使用组合对象还是用关联id,都还是用贫血模式咯。对于您说的“表模式”,我没有搜索到相关文章,表模式是指数据实体完全对应数据库表么?
  回复  引用  查看    
#36楼 2008-04-19 18:09 | magiclee      
表模式是指数据实体完全对应数据库表么?
恩!
表模式配合orm,代码生成工具,还是非常强大的,据说现在orm能够生成比较复杂的dto,不仅限于当初生成那些简单的dto。

其实微软提供的dataset配合dataset生成器同样也可以达到如此效果。

其实我很提倡在dotnet平台使用dataset作为dto对象,这种解决方案是微软提出的,而且对于他的支持也是非常强大的。3.0里面的linq引入对于dataset更是如虎添翼。想象下,将数据表映射到内存来操作,相当于完全屏蔽了数据库的存在,你需要的数据都在内存,强大的linq让你能够优雅的操作这些数据表,而且dataset天生提供数据状态(删除的,增加的,更新的)记录,这样无论是支持离线操作还是回退操作都是非常容易的。虽然,有些人认为使用dataset,不用类,看起来不那么oo,但是我认为数据库就不是oo,基于数据库的开发如果死搬oo那套,无疑是自找麻烦。
  回复  引用  查看    
#37楼 [楼主]2008-04-19 19:39 | 水言木      
@magiclee
恩,谢谢指点:)

标题  
姓名  
主页
Email (博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      
该文被作者在 2008-04-18 23:22 编辑过
"五向定位"职业成长路线公开课(上海、南京、大连)
Google站内搜索


相关链接: