在机房重构过程中,在实现将数据库中数据显示到DataGridView控件这一功能时,遇到这样一个问题:由于在SqlHelper类中,定义查询操作时是将数据库,得到的是DataTable和DataSet对象(表),因此在使用DataGridView、Textbox等控件对数据进行绑定时,需要读取数据库中的字段。
举一例子,在实现“查询卡中金额”这一功能,需要将数据中Card_info表中的数据显示到文本框中。由于在D层中实现与数据库交互,获得的是DataTable对象(也就是Card_info表)。因此,在U层中的文本框需要与Card_info表中的字段一一对应起来。代码如下:
If card.Rows.Count Then
txtClass.Text = card.Rows(0)(5).ToString()
txtName.Text = card.Rows(0)(3).ToString()
txtDepartment.Text = card.Rows(0)(8).ToString()
txtGrass.Text = card.Rows(0)(4).ToString()
txtSex.Text = card.Rows(0)(2).ToString()
txtState.Text = card.Rows(0)(7).ToString()
txtCash.Text = card.Rows(0)(6).ToString()
txtStuNo.Text = card.Rows(0)(1).ToString()
End If
这样做功能虽然能实现,但是却在一些缺陷:
1、必须了解数据库的结构,降低数据库的安全性。
2、在代码编写过程容易写错,而且编译器不检查。
3、在程序中进行数据传递的是DataTable,不再是实体,违背了面向对象编程的思想。
4、DataTable为弱类型,无法直观的看出字段的数据类型。
DataTable对象是我们在程序与数据库交互必须使用的,为了弥补DataTable对象给我们在重构机房中带来的不便,这时我们采用将Datatable转化成泛型集合来解决这个问题。核心思想图:
实体类即数据库的映射,因此实体类中的属性和数据库表中的字段是相对应的。把DataTable中的每一行记录视为一个实体类,把其中的字段读取出来,存放到实体类的属性中,再把所有的实体类存在泛型集合中。因此,DataTable中有多少个记录,泛型集合中就有多少个实体类,每个实体类的属性和DataTable的字段是相对应的。这样做的好处是:
1、编写B层的人员无需手动填写需要的字段,直接按一下点,全都提示出来了,想用哪个用哪个,不会出现写错的情况。
2、不必了解数据库结构,保证了数据库的安全性。
3、在程序中进行数据传递的是实体,符合面向对象思想。
4、实体类的属性是强类型,每个字段的类型都是已知的。
好了,了解了泛型的好处和特点,现在看看是如何实现DataTable转换成泛型的。代码如下:
Imports System.Collections.Generic
Imports System.Reflection
'************************************************************
'类名称:EntityHelper
'命名空间:Entity
'功能:实现datatable类型对实体的转换功能
'创建时间:2015-2-14
'作者:孟浩杰
'小组:**
'**************************************************************
Public Class EntityHelper
''' <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
'设置对象的属性值。
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
总结