the5fire

关注Python、Django、Vim、Linux、Web开发、团队管理和互联网--Life is short, we need Python.


软件设计:DAO层该如何设计

作者:the5fire | 标签:   | 发布:2011-01-04 10:26 a.m. | 阅读量: 16031, 15551
关于Dao层的设计我现在也还是有点模糊,大大小小的项目也做了五六个了,负责的数据库设计也有三四个了。


在对Dao层进行设计时采用过两种方案:


  方案一:每一表对应一个Dao类(接口也可),每个Dao将完成对该表的增删改查以及业务上要求的查询操作。这么设计的话如果表很多的话将会产生很多类,并且将会出现大量重复的代码,因为每一个Dao中都将涉及到基础的增删改查。


  方案二:写一个基础的类,可以完成基本的增删改查,其他的对于业务上有额外需求的表单独在写一个类,不过这个类只包括额外的功能。这里的基础类写的时候是需要严格注意的,因为采用的类似映射的实现,需要你把实体类设计的同表结构一摸一样,因为在该类中对数据库的增删改查的Sql语句就是通过对实体类类名以及对实体类类中属性的提取完形成的。


  这里给出一个基本的添加方法(vb.net实现):

Public Class SqlDao : Implements Dal.IDao

Private SqlDr As SqlDataReader
Private SqlCon As SqlConnection
Private SqlCmd As SqlCommand
'从配置文件app.config中取得连接数据库的字符串
Private strConnect As String = ConfigurationManager.AppSettings("strCon")
'得到类名
Private strClassName As String
'得到类的类型
Private mType As Type
'得到属性集
Private mProS As PropertyInfo()

'在初始化方法中连接数据库
'Public Sub Init(ByVal obj As Object) Implements IDao.Init
' SqlCon = New SqlConnection(strConnect)

' '在构造函数中对必要类型进行初始化
' strClassName = TypeName(obj)
' mType = obj.GetType()
' mProS = mType.GetProperties
'End Sub

'连接数据库的一个私有方法
Private Function GetCon() As SqlConnection Implements IDao.GetCon
Try
If (SqlCon.State = ConnectionState.Closed) Then
SqlCon.Open()
End If
Catch ex As Exception
MsgBox("打开数据库时:" + ex.Message)
End Try

Return SqlCon
End Function


'''
''' 将对象添加到对应的表中,参数为对象,返回值为Int型,表示影响的行数
'''

'''
''' Integer
'''
Public Function AddObj(Of T)(ByVal Entity As T) As Integer Implements IDao.AddObj
Dim res As Integer = 0 '用来返回该操作影响的行数
'定义单个属性
Dim mPro As PropertyInfo
'定义sql参数
Dim para As SqlParameter
Dim strFields As String = ""
Dim strCondition As String = ""
Dim strSql As String = ""
For Each mPro In mProS
'该循环用来进行参数组合
'再添加时不用添加时间
strFields = CStr(Trim(mPro.GetValue(Entity, Nothing))) '获取属性值
If strFields <> "0" And strFields <> "00:00:00" And strFields <> "" Then

strSql = strSql + "@" + mPro.Name + ","
'组合形成字段名
strCondition = strCondition + mPro.Name + ","
End If
Next
'最后再插入最后的括号

strSql = Left(strSql, Len(strSql) - 1) + ")"
strCondition = Left(strCondition, Len(strCondition) - 1) + ")"
strSql = "INSERT INTO " + strClassName + " (" + strCondition + " VALUES (" + strSql
'MsgBox(strSql)
Try
Using sCmd As New SqlCommand(strSql, GetCon)
'设定执行方式
sCmd.CommandType = CommandType.Text
For Each mPro In mProS
'进行参数的赋值
'Dim stra As String = mPro.GetValue(obj, Nothing)
'一般的添加不用加入时间,除了下机表
strFields = CStr(Trim(mPro.GetValue(Entity, Nothing))) '获取属性值
If strFields <> "0" And strFields <> "00:00:00" And strFields <> "" Then
para = New SqlParameter("@" + mPro.Name, mPro.GetValue(Entity, Nothing))

sCmd.Parameters.Add(para)
End If
Next
res = sCmd.ExecuteNonQuery
End Using
Catch ex As Exception
MsgBox("进行对象添加时:" + ex.Message)
End Try
Return res '返回该操作影响的行数
End Function
End Class

  这几天从网上也查了一些资料主要就是关于Dao层该如何设计的问题,最直接的设计方案就是每一个表对应一个Dao,说是代码重复太多,不过这样设计那些基本的代码是不用写的,都有现成的工具,直接根据表生成对应的增删改查。


  不过因为需要重复的代码太多了,因此有人提出这种方法:

public interface BaseDao {
public void create (T t);
public void delete (T t);
public void update (T t);
}

public interface WindDao extends BaseDao {
public void other (Wind wind);
}



  将基本的增删改查通过泛型放置到一个基础的接口中,其他的只需实现该接口,如果有额外的需求便可自行添加方法。这可谓一个典型的继承的应用。不过说实话,这种方法也不能使代码量减少。


  这块还真是不太明白,论坛里有人说:“其实可以将basedao注入baseservice来实现,这样就不用每个dao都写一个类了”,实在是理解不了,如果有大牛恰好经过劳烦指点一二,不胜感激。

曹师哥点拨:

遇到一个问题,我会采用软件工程上的3w原则(what,why,how)来思考。


首先what:
  • dao(data access object),数据访问对象,既然是对象那么就有封装,他封装了业务及相关数据与数据库进行交互的一系列的接口。




  • why:
  • 1.用户不需要了解这个对象细节,只需要了解这个对象的接口就可以数据库进行交互,这样方便了用户的使用。

  • 2.设计一个dao层,上面所有的业务层都调用这个dao层的接口,这样就实现了软件的重用性。


  • 3.dao层的存在使得业务逻辑层跟访问数据库的代码分开了。


  • 4.dao层可以处理不同数据库的差异性,使得软件在oracle,mysql,db2等数据库上迁移时改变代码很少。


  • 5.dao层的封装不需要开发人员直接跟数据库交互(有了dao层,通过dao层交互),增加了数据库的安全性。等等



  • how:通过以上的why的分析,我们在设计dao层的时候,要注意:
  • 1.提供丰富的接口供用户调用,


  • 2.在dao中不能涉及业务内容,一个dao层接口就对应一次数据库操作(是原子性的)。


  • 3.考虑软件在不通数据库上的迁移。


  • 4.dao层是用来实现业务及相关数据和数据库交互的桥梁,那么dao层就需要对数据库的操作进行一系列的封装,包括增删改查,数据库的事务,存储过程,触发器等等操作。其中有一点要注意的是事务的处理,dao层一般不负责事务的处理,把事务处理遗留给业务层来做。原因是:如果一次业务逻辑需要调用多个dao的方法,一旦某个dao的方法失败,造成回滚,则已经执行的那些DAO则无法回滚。



  • 总之,使用dao层,使得业务的操作跟数据库的操作进行了解耦,业务的变化不会影响数据的访问,而数据访问方式的改变(保证接口不变),不会影响业务,使得系统的各个部分相互独立。dao层的操作是对业务的一个分解,把一个完整的业务分解到数据库中的相关表中。




    - from the5fire.com
    ----EOF-----

    微信公众号:Python程序员杂谈


    其他分类: