zoukankan      html  css  js  c++  java
  • DTO,DMO,DPO

    大家都看到标题中的三个英文缩写了:DTO,DMO,DPO。DTO大家应该还是熟悉的,Data Transfer Ojbect(数据传输对象)。研究过DDD(Domain Driven Design领域驱动设计)的人应该了解过DTO。是用来传输数据的对象,应为领域对象虽然有数据(属性),但是领域对象上面还带有操作,在某些场合不适合进行传输,因为有些时候传输还需要序列化,而且也不是所有的领域对象属性都可以暴露给调用端的,而且有些属性可能要合并,可能要分解,之后才有利于调用端的使用,加上其他一些的业务原因,于是就有了专门用来传输数据的DTO,只有属性,没有操作,必要的时候加上序列化标记,实现远程调用。

    DMO和DPO是我自己创造的名词,在后面再解释给大家听。

    刚开始看到别人用来表达数据对象的类的时候,都是只有属性,没有操作,而且大都是和数据库表一一对应的。可以单独建立一个项目,名字叫做Project.Entity。在独立的一个项目中保存所有用到的实体,其他的项目添加对Project.Entity项目的引用。

    entity1

    就拿User举个例子吧。

    public class User{    public Guid UserID { get; set; }    public string Username { get; set; }}

    也有人喜欢在实体类添加后缀,方便标识,因为有可能领域对象也叫做User,但是觉得都叫做User又有点别扭,不好区分。就像分层的话,可能会有UserBll,UserDal之类的类产生。(在这里不讨论这些类是否合适,只是说明这种现象,但是如果大家有这方面的好思路,也可以分享一下)

    然后不管是添加还是修改,还是查询显示,都是用这个User实体。这个在做ASP.NET或者WinForm的时候还可以。反正客户端和服务端都可以引用这个类库,不影响开发。

    有一点,我个人比较喜欢将一些查询条件作为一个实体的属性。这样查询方法就不需要很多参数了,只有一个实体作为参数就可以了。而且在后面如果条件有变化,只要在实体添加属性,方法的内部添加或者删除参数的处理就可以了。至少调用端不用做任何修改。如果每个添加都作为一个参数的话,增加或者删除参数,服务端修改方法,调用端就需要修改调用的地方。也能减少一些开发工作吧,而且在界面的查询条件很多的时候,不至于查询方法的参数列表也很长。

    例如用户查询,我就会建立一个UserFind实体。下面的例子中说明界面有两个条件,一个是用户姓名,一个是注册时间。

        public  class UserFind    {        public string Username { get; set; }        public DateTime RegDate { get; set; }            }

    问题1

    产生的问题就是添加的时候肯定是每个属性都要添加到数据库,修改的时候,有些属性不用或者是不能修改,允许部分的修改。还有就是显示的时候,可能还需要其他的属性,例如User实体下面可能会有一些集合属性,例如用户全部地址,邮件个数,是否有新邮件,是否有新订单之类的需求,就要在User实体添加其他属性。但是这些属性在添加和修改的时候都用不到。如果这几种情况还是共享一个实体的话,容易引起误用。而且增加沟通,需要告诉做添加功能的人,你只要添加属性1,2,3就可以了。告诉做显示的人,你需要每个属性都赋值。告诉做修改的人,属性2,3,4,5是可以修改的。

    还有那个查询实体,例如查询订单吧。用户查询订单,只能查询自己的订单。

        public class OrderFind    {        public string OrderSeqNo { get; set; }        public DateTime PlaceDate { get; set; }    }


    根据订单编号和下单时间查询。

    可是后台查询用户订单的时候,可能会需要用户的信息,例如查询姓名为“张三”的订单。好吧,修改这个查询实体。

        public class OrderFind    {        public string OrderSeqNo { get; set; }        public DateTime PlaceDate { get; set; }        public string Username { get; set; }    }

    问题2

    同样,这就需要在开发用户查询订单的时候忽略Username属性,在开发后台查询订单的时候加上Username属性。

    是不是这两个功能也应该区分一下呢?

    于是我就有了下面的总结。

    1、实体的专用性

    1) 尽量的保持实体的专用性,也就是一个功能的方法,虽然和两外一个方法的返回结果类似,可能只需要添加一两个属性,这样的情况,重新建立实体,方便后面可能对这两个方法返回内容的修改不至于相互影响。

    2) 尽量保持一个实体中的每一个属性,每一个被赋值的属性,将来都会用到,否则减少实体的属性,或者新建一个实体,使用正好合适的属性个数。

    3) 分离添加和显示用的实体,因为添加可能不是每个字段都需要赋值,或者一些值是默认值。

    4) 分离不同类型的用户使用的实体,尽管是相同的功能。可以在类名添加ForPlanter之类的后缀来解决。因为不同用户关注的点不同,关注的属性肯定不相同。而且修改也不影响其他类型用户的使用。

    最近的一个项目是WCF+Silverlight。一个类库项目不行了,需要添加两个类库项目,因为Silverlight不能添加普通类库引用,Silverlight有自己的类库项目模板。

    当然了,实体的代码还是可以共享的,但是类库必须是两个。

    在简单学习了DDD之后,发现里面的一个概念叫做DTO,数据传输对象。觉得其他和我的Project.Entity项目比较像,反正功能都是用来承载数据,不带有任何操作。甚至连数据验证都没有,数据验证可以通过attribute,集合独立的模块来完成。

    问题2已经有了解决方案,就是保持实体的专用,减少混用。

    可是问题1呢?

    后来我们想减少代码的开发量,尤其是在增、删、改、查的数据库操作方面,想要引进一些工具类库,来帮助我们完成数据库的操作,使得我们可以专注于业务方面的开发。

    这方面的类库有很多,例如:NHibernate,还有微软的Entity Framework等。引入这些时候我发现问题1变得更加突出了。要不然就会有大量的冗余字段被读取,甚至被网络传输(WCF+Silverlight的数据需要经过网络,SOAP消息的形式传输到客户端)。

    于是DTO,DPO,DMP就产生了。

    1、传输实体,经过客户端传输给wcf。在服务端可能需要组合产生新的数据库持久化实体(区分添加用实体和更新用实体),这些实体经过ORM将数据持久化到数据库。

    2、从数据库查询的数据,经过ORM映射产生的实体,然后经过处理,产生传输实体,传输给客户端。

    3、数据传输实体dto,数据库持久化实体dpo,数据库映射实体dmo

    Technorati 标签: DTO,DPO,DMO,DDD

    【Blog】http://virusswb.cnblogs.com/

    【MSN】jorden008@hotmail.com

    【说明】转载请标明出处,谢谢

    CWF框架之SQLHelper,简单的数据逻辑案例

    对于数据处理逻辑,上篇已经发布了又VB.net写的接口,这里公布一个又vb.net写的接口实现类

    本来想发布类工厂操作,但是我的工程采用了配置文件注入方式,所以代码又点长,就先发sql数据库操作的实现类。

    Imports System.Data
    Imports System.Data.SqlClient
    Imports System.Data.Common
    ''' <summary>
    ''' 简单数据操作底层类SQL数据库
    ''' </summary>
    ''' <remarks>
    ''' 该类执行简单的数据操作支持SQL
    ''' 开发者:欧阳寒玟
    ''' 开发时间:2009-01-25
    ''' 修改时间:2010-10-25
    ''' 作者网站:http://www.coldwin.org
    ''' </remarks>
    Public Class SQLHelper
        Implements IDbHelper
        Private conStr As String
        Private conn As SqlConnection ''连接对象
        Private cmd As SqlCommand     ''Command对象
        Private _isTran As Boolean = False  ''是否执行事务
    #Region "准备工作"
        ''' <summary>
        ''' 获取或设置链接字符串
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property ConnectionString As String Implements IDbHelper.ConnectionString
            Get
                Return conStr
            End Get
            Set(ByVal value As String)
                conStr = value
            End Set
        End Property
        ''' <summary>
        ''' 获取或设置连接对象
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Connection As IDbConnection Implements IDbHelper.Connection
            Get
                Return conn
            End Get
            Set(ByVal value As IDbConnection)
                conn = value
            End Set
        End Property
        ''' <summary>
        ''' 是否执行事务
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property isTranSaction As Boolean Implements IDbHelper.isTranSaction
            Get
                Return _isTran
            End Get
            Set(ByVal value As Boolean)
                _isTran = value
            End Set
        End Property

        ''' <summary>
        ''' 获取或设置数据执行事务
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property TranSaction As IDbTransaction Implements IDbHelper.TranSaction
            Get
                'isTranSaction = True
                Return cmd.Transaction
            End Get
            Set(ByVal value As IDbTransaction)
                isTranSaction = True
                cmd.Transaction = value
            End Set
        End Property
        ''' <summary>
        ''' 关闭Connection对象
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub Close() Implements IDbHelper.Close
            If conn.State = ConnectionState.Open And isTranSaction = False Then
                conn.Close()
            End If
        End Sub
        ''' <summary>
        ''' 默认读取配置文件的链接字符串
        ''' </summary>
        ''' <remarks></remarks>
        Public Sub New()
            Try
                conStr = Configuration.ConfigurationManager.AppSettings("sql").ToString()
            Catch ex As Exception
                Try
                    conStr = System.Configuration.ConfigurationManager.ConnectionStrings("sql").ToString()
                Catch exp As Exception
                    CWF.DocumentService.ServerSession(Of String).log.Save(exp.Message)
                End Try
            End Try
            conn = New SqlConnection(ConnectionString)
            cmd = New SqlCommand()
            cmd.Connection = conn
            Try
                conn.Open()
            Catch ex As Exception
                Throw New Exception(ex.Message)
            End Try
        End Sub
        ''' <summary>
        ''' 带参数实例化
        ''' </summary>
        ''' <param name="constring">链接字符串</param>
        ''' <remarks></remarks>
        Public Sub New(ByVal constring As String)
            ConnectionString = constring
            conn = New SqlConnection(ConnectionString)
            cmd = New SqlCommand()
            cmd.Connection = conn
            Try
                conn.Open()
            Catch ex As Exception
                Throw New Exception(ex.Message)
            End Try
        End Sub
    #End Region
        Private Function Exec(ByVal Command As SqlCommand, ByVal CmdTxt As String, ByVal commondType As CommandType) As Integer
            Command.CommandText = CmdTxt
            Command.CommandType = commondType
            Try
                If conn.State = ConnectionState.Closed Then conn.Open()
                Return Command.ExecuteNonQuery()
            Catch ex As Exception
                Throw New Exception(ex.Message)
            Finally
                Close()
            End Try
        End Function
        Private Function Exec(ByVal Command As SqlCommand, ByVal CmdTxt As String, ByVal commondType As CommandType, ByVal Parameters() As SqlParameter) As Integer
            Command.CommandText = CmdTxt
            Command.CommandType = commondType
            Command.Parameters.AddRange(CType(Parameters, SqlParameter()))
            Try
                If conn.State = ConnectionState.Closed Then conn.Open()
                Return Command.ExecuteNonQuery()
            Catch ex As Exception
                Throw New Exception(ex.Message)
            Finally
                Close()
            End Try
        End Function
        Private Function qureys(ByVal Command As SqlCommand, ByVal CmdTxt As String, ByVal commandType As CommandType) As DataTable
            Dim dt As New DataTable
            Command.CommandText = CmdTxt
            Command.CommandType = commandType
            Dim DataAdapter As New SqlDataAdapter(Command)
            If conn.State = ConnectionState.Closed Then conn.Open()
            Try
                DataAdapter.Fill(dt)
                Return dt
            Catch ex As Exception
                Throw New Exception(ex.Message)
            Finally
                Close()
            End Try
        End Function
        Private Function qureys(ByVal Command As SqlCommand, ByVal CmdTxt As String, ByVal commandType As CommandType, ByVal Parameters() As SqlParameter) As DataTable
            Dim dt As New DataTable
            Command.CommandText = CmdTxt
            Command.CommandType = commandType
            Command.Parameters.AddRange(CType(Parameters, SqlParameter()))
            Dim DataAdapter As New SqlDataAdapter(Command)
            If conn.State = ConnectionState.Closed Then conn.Open()
            Try
                DataAdapter.Fill(dt)
                Return dt
            Catch ex As Exception
                Throw New Exception(ex.Message)
            Finally
                Close()
            End Try
        End Function
        Private Function qureysDataset(ByVal Command As SqlCommand, ByVal CmdTxt As String, ByVal commandType As CommandType) As DataSet
            Dim dt As New DataSet
            Command.CommandText = CmdTxt
            Command.CommandType = commandType
            Dim DataAdapter As New SqlDataAdapter(Command)
            If conn.State = ConnectionState.Closed Then conn.Open()
            Try
                DataAdapter.Fill(dt)
                Return dt
            Catch ex As Exception
                Throw New Exception(ex.Message)
            Finally
                Close()
            End Try
        End Function
        Private Function qureysDataset(ByVal Command As SqlCommand, ByVal CmdTxt As String, ByVal commandType As CommandType, ByVal Parameters() As SqlParameter) As DataSet
            Dim dt As New DataSet
            Command.CommandText = CmdTxt
            Command.CommandType = commandType
            Command.Parameters.AddRange(CType(Parameters, SqlParameter()))
            Dim DataAdapter As New SqlDataAdapter(Command)
            If conn.State = ConnectionState.Closed Then conn.Open()
            Try
                DataAdapter.Fill(dt)
                Return dt
            Catch ex As Exception
                Throw New Exception(ex.Message)
            Finally
                Close()
            End Try
        End Function
        ''' <summary>
        ''' 执行无参数存储过程
        ''' </summary>
        ''' <param name="ProcName">存储过程名称</param>
        ''' <remarks></remarks>
        Public Sub ExcuteProc(ByVal ProcName As String) Implements IDbHelper.ExcuteProc
            Exec(cmd, ProcName, CommandType.StoredProcedure)
        End Sub
        ''' <summary>
        ''' 执行带参数的存储过程
        ''' </summary>
        ''' <param name="ProcName">存储过程名称</param>
        ''' <param name="Parameters">参数数组</param>
        ''' <remarks></remarks>
        Public Sub ExcuteProc(ByVal ProcName As String, ByVal Parameters() As IDbDataParameter) Implements IDbHelper.ExcuteProc
            Exec(cmd, ProcName, CommandType.StoredProcedure, CType(Parameters, SqlParameter()))
        End Sub
        ''' <summary>
        ''' 执行无参数sql语句
        ''' </summary>
        ''' <param name="cmdTxt">执行语句</param>
        ''' <returns>影响行数</returns>
        ''' <remarks></remarks>
        Public Function Execute(ByVal cmdTxt As String) As Integer Implements IDbHelper.Execute
            Return Exec(cmd, cmdTxt, CommandType.Text)
        End Function
        ''' <summary>
        ''' 执行带参数的sql语句
        ''' </summary>
        ''' <param name="cmdTxt">命令语句</param>
        ''' <param name="Parameters">参数</param>
        ''' <returns>影响行数</returns>
        ''' <remarks></remarks>
        Public Function Execute(ByVal cmdTxt As String, ByVal Parameters() As IDbDataParameter) As Integer Implements IDbHelper.Execute
            Return Exec(cmd, cmdTxt, CommandType.Text, Parameters)
        End Function
        ''' <summary>
        ''' 启用内部事务执行多条命令
        ''' </summary>
        ''' <param name="cmdTxt">命令数组</param>
        ''' <param name="cmdType">执行类型</param>
        ''' <returns>影响行数</returns>
        ''' <remarks></remarks>
        Public Function ExecuteNonQuery(ByVal cmdTxt() As String, ByVal cmdType As System.Data.CommandType) As Integer Implements IDbHelper.ExecuteNonQuery
            cmd.CommandType = cmdType
            Dim tran As SqlTransaction = Nothing
            Dim num As Integer = 0
            Try
                tran = conn.BeginTransaction
                For Each st As String In cmdTxt
                    If st = "" Then Exit For
                    If conn.State = ConnectionState.Closed Then
                        conn.Open()
                    End If
                    cmd.CommandText = st
                    cmd.Transaction = tran
                    num += cmd.ExecuteNonQuery()
                Next
                tran.Commit()
            Catch ex As Exception
                tran.Rollback()
                num = 0
                Throw New Exception(ex.Message)
            Finally
                cmd.Parameters.Clear()
                Close()
            End Try
            Return num
        End Function
        ''' <summary>
        ''' 执行无参数sql命令返回第一行第一列
        ''' </summary>
        ''' <param name="cmdTxt">sql命令</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function ExecuteScalar(ByVal cmdTxt As String) As Object Implements IDbHelper.ExecuteScalar
            cmd.CommandText = cmdTxt
            If conn.State = ConnectionState.Closed Then conn.Open()
            Try
                Return cmd.ExecuteScalar()
            Catch ex As Exception
                Throw New Exception(ex.Message)
            Finally
                Close()
            End Try
        End Function
        ''' <summary>
        ''' 执行带参数sql命令返回第一行第一列
        ''' </summary>
        ''' <param name="cmdTxt">sql命令</param>
        ''' <param name="Parameters" >参数</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function ExecuteScalar(ByVal cmdTxt As String, ByVal Parameters() As IDbDataParameter) As Object Implements IDbHelper.ExecuteScalar
            cmd.CommandText = cmdTxt
            cmd.Parameters.AddRange(CType(Parameters, SqlParameter()))
            If conn.State = ConnectionState.Closed Then conn.Open()
            Try
                Return cmd.ExecuteScalar()
            Catch ex As Exception
                Throw New Exception(ex.Message)
            Finally
                Close()
            End Try
        End Function
        ''' <summary>
        ''' 执行无参数命令返回DataTable
        ''' </summary>
        ''' <param name="cmdTxt">SQL命令</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function Query(ByVal cmdTxt As String) As System.Data.DataTable Implements IDbHelper.Query
            Return Me.qureys(cmd, cmdTxt, CommandType.Text)
        End Function
        ''' <summary>
        ''' 执行带参数命令返回DataTable
        ''' </summary>
        ''' <param name="cmdTxt">SQL</param>
        ''' <param name="Parameters">参数</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function Query(ByVal cmdTxt As String, ByVal Parameters() As IDbDataParameter) As System.Data.DataTable Implements IDbHelper.Query
            Return Me.qureys(cmd, cmdTxt, CommandType.Text, Parameters)
        End Function
        ''' <summary>
        ''' 执行无参数命令返回DataSet
        ''' </summary>
        ''' <param name="cmdTxt">SQL命令</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function QueryDataSet(ByVal cmdTxt As String) As System.Data.DataSet Implements IDbHelper.QueryDataSet
            Return Me.qureysDataset(cmd, cmdTxt, CommandType.Text)
        End Function
        ''' <summary>
        ''' 执行带参数命令返回DataSet
        ''' </summary>
        ''' <param name="cmdTxt">SQL</param>
        ''' <param name="Parameters">参数</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function QueryDataSet(ByVal cmdTxt As String, ByVal Parameters() As Object) As System.Data.DataSet Implements IDbHelper.QueryDataSet
            Return Me.qureysDataset(cmd, cmdTxt, CommandType.Text, Parameters)
        End Function
        ''' <summary>
        ''' 执行无参数存储过程返回DataTable
        ''' </summary>
        ''' <param name="ProcName">存储过程名</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function QueryProc(ByVal ProcName As String) As System.Data.DataTable Implements IDbHelper.QueryProc
            Return Me.qureys(cmd, ProcName, CommandType.StoredProcedure)
        End Function
        ''' <summary>
        ''' 执行带参数存储过程返回DataTable
        ''' </summary>
        ''' <param name="ProcName">存储过程名</param>
        ''' <param name="Parameters">参数</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function QueryProc(ByVal ProcName As String, ByVal Parameters() As IDbDataParameter) As System.Data.DataTable Implements IDbHelper.QueryProc
            Return Me.qureys(cmd, ProcName, CommandType.StoredProcedure, Parameters)
        End Function
        ''' <summary>
        ''' 执行带无数存储过程返回DataSet
        ''' </summary>
        ''' <param name="ProcName">存储过程名</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function QueryProcDataSet(ByVal ProcName As String) As System.Data.DataSet Implements IDbHelper.QueryProcDataSet
            Return Me.qureysDataset(cmd, ProcName, CommandType.StoredProcedure)
        End Function
        ''' <summary>
        ''' 执行带无数存储过程返回DataSet
        ''' </summary>
        ''' <param name="ProcName">存储过程名</param>
        ''' <param name="Parameters">参数名</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Function QueryProcDataSet(ByVal ProcName As String, ByVal Parameters() As IDbDataParameter) As System.Data.DataSet Implements IDbHelper.QueryProcDataSet
            Return Me.qureysDataset(cmd, ProcName, CommandType.StoredProcedure, Parameters)
        End Function
    End Class

    其实为什么选择vb写数据持久层,自己也不太清楚,大概是以前一直觉得vb是数据库的亲家,那是acc时代的事情了,现在不太清楚,但是我发现一个问题,vs里(我用vs2010)写vb比写C#快,智能提示很完善,C#手动打的代码很多,VB却大多能提示出来,连try catch都是自动补全的。不知道这个可以设置成一样不,但是可以确定一点就是,VB写的注释在折叠后能显示注释的标题如下图显示:

    image

    让人看起来很方便,C#没法做到这点吗?

    我是个代码狂,不太喜欢去摆弄开发工具,IED对我来说差不多就是做智能提示写代码和编译的工具,让人见笑了。

  • 相关阅读:
    IDEA 删除java类的3种提示
    IDEA类和方法注释模板设置(非常详细)
    IntelliJ IDEA 2019,从入门到疯狂,图文教程
    intellij idea 如何将普通项目转换为maven项目
    使用idea误点 Add as Ant Build File选项后
    idea使用"svn"到项目报错Error:Cannot run program "svn" (in directory "E:XXXXXX"):CreateProcess error=2,
    Alertmanager 部署配置
    Prometheus PromQL 简单用法
    Prometheus PromQL 基础
    Prometheus 自动发现
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/1888436.html
Copyright © 2011-2022 走看看