【讨论】关于数据实体层的设计
今天与同事一起讨论了2种数据实体层的设计方案哪个比较好的问题,只有讨论,虽然心里有所倾向但是没有答案。
先介绍下两种设计,其实很简单,方案1是参照NetTiers的强类型设计继承自Object自己实现相应接口;
方案2是弱类型设计,实体继承自DataTable;两种方案都是一个表/视图对应一个数据实体。
相应的数据访问层都采用Provider模式,方案1每个表单独实现一个数据访问类,语句写死在类中;
方案2借助弱类型的优势只实现一个Base类,所有的表的访问类继承这个Base类,就都具备CRUD功能了,当然具体业务操作都还需要单独实现。
上面两种方案都用相应的CodeSmith模板自动生成。
简单复制些代码比较容易看懂
方案1:
先定义一个数据结构类
1 <EditorBrowsable(EditorBrowsableState.Never)> <Serializable> Friend Class AmmeterData
2 Implements ICloneable
3
4 Public ID As String = ""
5 Public OriginalID As String
6 Public AmmeterCode As String = ""
7 Public AmmeterName As String = ""
8 Public DeptId As String = ""
9 Public Multiple As Decimal = 0
10 Public MeasurePoint As String = ""
11 Public LocationId As String = ""
12 Public UseType As String = ""
13 Public Remark As String = ""
14 Public ParentId As String = ""
15
16 Public Function Clone() As Object Implements System.ICloneable.Clone
17 Dim tempEntity as New AmmeterData
18
19 tempEntity.ID = Me.ID
20 tempEntity.OriginalID = Me.OriginalID
21 tempEntity.AmmeterCode = Me.AmmeterCode
22 tempEntity.AmmeterName = Me.AmmeterName
23 tempEntity.DeptId = Me.DeptId
24 tempEntity.Multiple = Me.Multiple
25 tempEntity.MeasurePoint = Me.MeasurePoint
26 tempEntity.LocationId = Me.LocationId
27 tempEntity.UseType = Me.UseType
28 tempEntity.Remark = Me.Remark
29 tempEntity.ParentId = Me.ParentId
30
31 Return tempEntity
32 End Function
33
34 End Class
再封装数据结构并实现System.IComparable, System.ICloneable, IEntity, IEditableObject几个接口形成数据实体类,不知道为啥贴代码报错,贴个图吧。
与字段数关系不大,10个字段的表约500+行代码
方案2:
弱类型方案,继承自DataTable
1 Public Class CodeActionTable
2 Inherits DataTable
3
4 Public Sub New()
5 Mybase.New()
6
7 TableName = "CODE_ACTION"
8
9 '动作主键
10 Columns.Add ("ACTION_ID", GetType(String))
11 '动作名
12 Columns.Add ("ACTION_NAME", GetType(String))
13 '动作类型
14 Columns.Add ("ACTION_TYPE", GetType(String))
15 '是否需要计费
16 Columns.Add ("CHARGE_SN", GetType(String))
17 '动作编码
18 Columns.Add ("ACTION_CODE", GetType(String))
19 '备注
20 Columns.Add ("MEMO", GetType(String))
21 '录入人
22 Columns.Add ("CREATOR", GetType(String))
23 '创建时间
24 Columns.Add ("CREATE_TIME", GetType(DateTime))
25 '修改人
26 Columns.Add ("MODIFIER", GetType(String))
27 '修改时间
28 Columns.Add ("MODIFY_TIME", GetType(DateTime))
29
30
31 PrimaryKey = New DataColumn(){ Columns("ACTION_ID")}
33
34 End Sub
35 End Class
其实两种方案的模板最初都是我写的,但是目前我个人是倾向于方案2的,即弱类型方案,原因如下
1、方案1是深层封装,自己实现了System.IComparable, System.ICloneable, IEntity, IEditableObject等接口,复杂而且容易隐藏bug;
方案2是浅封装,集成了DataTable的丰富功能,简单、健壮;
2、方案1的表结构发生变化时,实体层和数据存取层需要同时调整,并且由于实现复杂,因此需要重新生成后覆盖,耦合度高,后期维护比较困难;
方案2只需要调整实体层即可,数据存取层不需要任何变化,耦合度低,维护简单;
3、随着系统开发,很多情况下需要多表链接或存储过程等获取数据,方案1会出现DataSet+强类型实体混合使用;
方案2很自然的易用DataTable传递结果;
4、方案1访问某个字段的值时,需要在设计时写好,否则只能用反射,效率和可读性都是问题;
方案2可以在设计时和运行时需要访问特定字段的值,更灵活;
5、实体层我理解是一个数据库表、视图等的逻辑映射,而在系统中起一个DTO(数据传输类)的作用,在实践中数据库频繁修改非常常见,因此越薄、越轻便、耦合度越低越好。而需要业务实体的时候可以在BLL层定义一个强类型业务实体,在业务实体内封装一个或多个实体类及相应的业务逻辑,满足面向对象、设计时类型检查等需要。
大家怎么看?非常想听听大家的意见,谢谢!