前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >软件设计:DAO层该如何设计

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

作者头像
the5fire
发布2019-02-28 10:33:33
1.3K0
发布2019-02-28 10:33:33
举报

关于Dao层的设计我现在也还是有点模糊,大大小小的项目也做了五六个了,负责的数据库设计也有三四个了。

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

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

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

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

代码语言:javascript
复制
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,说是代码重复太多,不过这样设计那些基本的代码是不用写的,都有现成的工具,直接根据表生成对应的增删改查。

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

代码语言:javascript
复制
	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层的操作是对业务的一个分解,把一个完整的业务分解到数据库中的相关表中。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2011-01-04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档