三层架构中DataTable华丽变身泛型集合

前言:

    做系统前期,抱着“实现了三层已经很不错了”的心情,并没有考虑到DataTable传到B层,或传到U层与DataGridView绑定,显示数据有什么错误的地方。后来“偷”听了一节课,才知道返回DataTable是破坏三层结构的。于是就开始了三层架构中DataTable变形记的探索。


    变形之前我考虑到了以下几点内容,也是看了很多的资料,总结下来的。(本身是菜鸟一枚,So...下面展示的代码不是我自己写的,参考了十期师哥的博客。站在巨人肩膀上啦)



一、DataTable与List<>的区别


    DataTable是数据集的填充,List<>是对象化的填充。DataTable是弱类型,没有办法直接看出数据表中字段的数据类型,List<>是强类型。最大的区别是,List<>可以灵活转换,不用装箱和拆箱(装箱拆箱:利用装箱和拆箱功能,可通过允许值类型的任何值与Object 类型的值相互转换),这个过程中可能会造成数据的错误丢失,这样看来DataTabel也不是很安全的。


三层架构中DataTable华丽变身泛型集合_第1张图片

图一(三层依赖model传数据)

三层架构中DataTable华丽变身泛型集合_第2张图片

图二(三层依赖DataTable传数据)



    从上面的图中明显看得到,DataTable的出现,使UI,BLL,DAL层都去直接的访问它了,而我们自己写的Model被甩到了一边。这一点就可以看出DataTable破坏了我们的三层结构。那么如果不使用DataTable,问题就来了。一条数据好处理,就实例化一个实体对象就可以了。如果是多个数据呢?那么就引出了我们需要使用的泛型集合了,简单的可以理解为一群实体。





二、为什么使用List<>

回答这个问题,其实就是在回答泛型集合有什么好处?因为它的优点,我们才考虑去使用它。

优点:

  • 减少输入,传输时只需要传一个实例T就可以获取它的任何属性。遍历方便,取到的都是单个的对象。——方便
  • 正确地构建的泛型类可以真正减少代码中的安全性问题。——安全
  • 使用泛型类还可以提高性能。其中最大的一个改进是.NET框架组件不会在值类型上使用包装(boxing)。尽管泛型类可以使用多个数据类型工作,但是它在后台单独地处理每一种数据类型。这种技术确保了在你的工作量最小的情况下,应用程序提供最佳的性能。——效率高

缺点:

  • 在绑定数据时也会产生很多麻烦。——绑定要重新实例化





三、实践变形


    这里我们需要写一个转换的类,让DataTable实现变身:


Imports System.Collections.Generic
Imports System.Reflection
'************************************************************
'类名称:ModelHelper  
'命名空间:DAL
'功能:实现datatable 对实体的转换功能
'创建时间:2014-10-21
'作者:周洲
'小组:**
'**************************************************************
Public Class ModelHelper
    ''' <summary>
    ''' 将dataTable中的数据转换为实体集合
    ''' </summary>
    ''' <typeparam name="T"></typeparam>
    ''' <param name="dt"></param>
    ''' <param name="ts"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function ConvertToList(Of T As New)(dt As DataTable, ts As IList(Of T))
        '获得T的类型  
        Dim type As Type = GetType(T)
        '定义一个临时变量  
        Dim strTemp As String = String.Empty
        '遍历表中所有行数  
        For Each dr As DataRow In dt.Rows
            '定义类型变量act获取动态创建对象T的类型。  

            Dim act As T = If((Nothing Is Nothing), Activator.CreateInstance(Of T)(), Nothing)
            '引用反射表示可获得对象的所有属性组成的集合  
            Dim propertys As PropertyInfo() = act.[GetType]().GetProperties()
            '定义array变量,接收propertys中含有的属性,并提供对属性propertys元数据访问  
            Dim array As PropertyInfo() = propertys
            Dim intCount As Integer = 0
            '遍历所有对象属性  
            While intCount < array.Length 'length表示所有维数中元素的总和  
                'pr表示元素中含有的属性,并提供对数据访问  
                Dim pr As PropertyInfo = array(intCount)
                strTemp = pr.Name
                '列名=对象的属性名    
                If dt.Columns.Contains(strTemp) Then
                    '判断此属性是否设置函数  
                    If pr.CanWrite Then   '该属性是否可写  
                        Dim value As Object = dr(strTemp)
                        '如果非空,则赋值给对象的属性  
                        If value IsNot DBNull.Value Then
                            'If value IsNot Nothing Then
                            '设置对象的属性值。  
                            pr.SetValue(act, value, Nothing)
                        End If
                    End If
                End If
                intCount += 1
                Continue While
            End While
            '添加对象到泛型集合中  
            ts.Add(act)
        Next
        Return ts
    End Function
End Class

    D层中定义一个List<>,定义一个dt变量接收传回来的数据,调用上面写的函数,填入mylist和dt就转换成功啦。



''' <summary>
    ''' 用有参数的查询方法查询充值表,条件是卡号
    ''' </summary>
    ''' <param name="student"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function QueryReRecord(student As ModelReInfo) As List(Of ModelReInfo) Implements IDAL.IRecharge.QueryReRecord

        Dim str As String = "Select cNO,rAdd,rDate,rTime,rUID from T_Recharge where cNo=@cNo"
        Dim helper As New SqlHelper
        Dim para As SqlParameter() = {
            New SqlParameter("@cNo", student.cNo)
            }
        If student.cNo Is Nothing Then
            Throw New Exception("请填写卡号")
        End If
        Dim dt As New DataTable
        Dim myList As New List(Of ModelReInfo)
        dt = helper.ExecSelect(str, CommandType.Text, para)
        If (dt.Rows.Count > 0) Then
            myList = ModelHelper.ConvertToList(dt, myList)
            Return myList
        Else
            Throw New Exception("没有记录!")
            Return Nothing
        End If

    End Function




四、总结

    上面讨论了这么多,那到底为什么不能使用DataTable呢?归根结底,我认为做系统最主要是体现软件发展的分层处理,体现三层之间的分工合作(既然DataTable这么的破坏结构又实用,那我们照常用它,但是转换它),提高开发效率和降低耦合度,以使人能处理更加复杂的问题,更高层的抽象。不断的抽象,这就是目的吧。




你可能感兴趣的:(重构,VB.NET,三层)