上一篇博客分析了什么是泛型,以及使用泛型带来的好处。一是提高程序的类型安全,二是取消了装箱和拆箱过程,使性能得到提高。三层架构中,D层负责与数据库交互,一般得到的都是DataTable或DateSet。机房收费系统中,当你通过D层从数据库中取出数据时,是用DataTable来接收的,DataTable就是临时保存数据的虚拟表,你可以从中取出你想要的数据,通过dt.Rows[0][“xxx”];或者dt.Rows[0][1]方式。
实体类和DataTable的比较
但是就是因为这样,问题来了,如果返回DataTable,那么层与层之间传递的就不再是实体类,这样就违背了面向对象的思想,也破坏了三层架构。使用DataTable的缺点就不言而喻了:
1、如果要取得DataTable中的值,需要得到对应字段的下标值。并且编译器不检查,一旦出错,不易找出。
2、必须了解数据库的结构才能取出字段的值。
3、不符合面向对象的思想,在分层合作开发时每一层的开发人员都必须了解数据库的结构。
4、DataTable为弱类型,无法直观看出字段的类型属性。
面对这个问题,要如何解决呢?使用DataTable来返回值,那么实体类也就没有用了,这样显然是不行的。这个时候就需要使用强大的泛型集合了。通过将DataTable转换为泛型,与实体相对应,然后通过泛型来取得DataTable中的值。那么这样做有什么好处呢?
1、不用了解数据库的结构,数据库中的字段都变成泛型List的属性,可以直接引用。
2、符合面向对象的思想和三层架构,通过返回泛型来调用数据
3、实体类的属性是强类型,每个字段的类型都是已知的
DataTable转化为泛型
这里借用一下别人的图片:(感觉十分经典,直观)
相关代码:
Imports System.Collections.Generic
Imports System.Reflection
Public Class DataTableToList
'将datatable转换为泛型集合
Public Shared Function ConverToList(Of T As {New})(ByVal dt As DataTable) As IList(Of T)
Dim mylist As New List(Of T) '定义最终返回的集合
Dim mytype As Type = GetType(T) '得到实体类的类型名
Dim dr As DataRow '定义行集
Dim TmpName As String = String.Empty '定义一个临时变量
'遍历datatable的所有数据行
For Each dr In dt.Rows
Dim myT As New T '定义一个实体类对象
Dim propertys() As PropertyInfo = myT.GetType().GetProperties() '定义属性集合
Dim pr As PropertyInfo
'遍历该对象的所有属性
For Each pr In propertys
TmpName = pr.Name '将属性名称赋值给全局变量
'检查datatable是否包含此列,列名==对象的属性名
If (dt.Columns.Contains(TmpName)) Then '将此属性与datatable的列名比较,查看datatable是否包含此属性
'判断此属性是否有setter类
If (pr.CanWrite = False) Then '判断此属性是否可写,如果不可写,跳出此循环
Continue For
End If
Dim value As Object = dr(TmpName) '定义一个对象的列来保存列的值
If (value.ToString <> DBNull.Value.ToString()) Then '判断是否为空,如果非空,则赋给对象的属性
pr.SetValue(myT, value, Nothing) '在运行期间通过反射,动态的访问一个动态的属性
End If
End If
Next
mylist.Add(myT) '将myT对象添加到集合
Next
Return mylist '返回实体集合
End Function
End Class
总结:
通过DataTable到泛型的转换,让我对泛型的理解加深了,最开始只是知道用DataTable会破坏三层架构,不符合面对象的思想,可是为什么呢?我的理解就是在分层合作的时候,如果返回值为DataTable,那么负责每层的人都要去了解数据库的结构,才能正确的取出数据。相当于直接和数据库打交道。而泛型是强类型,编程人员可以不用了解数据库中数据的类型和位置,直接通过泛型就可以很容易的引用了。目前只能理解到这个程度,如果有不正确的地方,还请大家指出!