【个人机房重构】——泛型集合代替DataTable

2024-05-08 02:38

本文主要是介绍【个人机房重构】——泛型集合代替DataTable,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景:听说,在VB.NET机房收费系统中,尽量使用泛型来传递数据,不要使用DataTable。


一、【DataTable】


    DataTable是一个临时保存数据的表,我们在机房收费系统中,将查到的数据先暂时存放在DataTable上,然后将DataTable一层一层的进行传递,最终传到U层,把用户需要的数据呈现给用户。

    在VB.NET版机房收费系统中,采用的是三层架构。用三层架构开发项目,各层之间经常会传递数据。例如:D层负责与数据库交互,一般是得到DataTable或DataSet对象,然后返回给B层,B层进行类似的处理来读取数据:dt.Rows[0][“xxx”];或者dt.Rows[0][1]。有时DataTable也会被传到UI层,与控件进行绑定,显示数据。例如使用DataGridView控件。

    无论是什么情况,使用DataTable不可避免的要填写读取的字段,这样做非常容易写错,而且编译器不检查;而且你必须要了解数据库的结构,如果是进行合作开发的话,我想如果使用DataTable,那就呵呵了吧。同时,使用DataTable不符合面向对象编程思想。


下边是一段使用DataTable的代码:


 If dt.Rows.Count > 0 Then'查到的表中有数据,则需要给实体字段赋值Dim Drow As DataRow    'DataTable中的一行数据Drow = dt.Rows(0)'从dt中取值user.studentID = Drow("studentID").ToString.Trim() '学号赋值user.studentName = Drow("studentName").ToString.Trim   '学生姓名赋值user.Sex = Drow("sex").ToString.Trim    '性别赋值user.Department = Drow("Department").ToString.Trim   '系别赋值user.Grade = Drow("Grade").ToString.Trim     '年级赋值user.Sclass = Drow("Sclass").ToString.Trim    '班级赋值user.State = Drow("State").ToString.Trim     '状态赋值user.Comment = Drow("Comment").ToString.Trim    '备注赋值user.Balance = Drow("Balance").ToString.Trim    '余额赋值

上边的代码是“学生查询余额”窗体中的,dt就是一个新实例化的DataTable。在这里,你必须清楚的了解数据库的结构,才能保证准确无误的写出正确的代码。而且,在这个“学生查询余额”这个窗体中,需要返回的实体属性只有9个,工作量还比较小。但是,以后我们不可能只开发这样的小系统,到那时,一个实体的属性可不就是几个的事情了。


二、【泛型集合】


1、什么是泛型 ?

    

    泛型是具有占位符(类型参数)的类、结构接口方法,这些占位符是类、结构、接口和方法所存储或使用的一个或多个类型的占位符。当然可能看不太懂,其实我也不懂,百度百科上是这样写的。

    泛型其实就像一个口袋,你可以很方便地往里面装东西,只是在第一次使用这个口袋的时候要注意声明它只能装什么样类型的东西,以后就不能装错了。那么我们就用钱包为例吧,我们首先描述一下钱包。钱包的用途不外乎是装点儿东西,当然,除了钱还可以装其它很多东西,例如银行卡、便签条、照片等等,但是这些东西有些共同的地方,至少是尺寸方面不能超过钱包的限制,谁可以把冰箱也揣在钱包里呢?因此,我们在设计能装进钱包的物品的类的时候就要考虑到尺寸的因素。

    在三层架构中,实体类即数据库的映射,因此实体类中的属性和数据库表中的字段是相对应的。把DataTable中的每一行记录视为一个实体类,把其中的字段读取出来,到实体类的属性中,再把所有的实体类存在泛型集合中。因此,DataTable中有多少个记录,泛型集合中就有多少个实体类,每个实体类的属性和DataTable的字段是相对应的。这样一来,传到B层或U层的将是一个实体类的泛型集合。

    使用泛型集合传递数据,编写B层的人员无需手动填写需要的字段,直接按一下点,全都提示出来了,想用哪个用哪个,不会出现写错的情况;你不必了解数据库结构;符合面向对象思想。


2、具体的使用


下边是具体使用泛型集合的方法:

    因为在系统中,传递数据大都用泛型,所以我们可以把将DataTable转换成一个实体填充泛型集合的方法抽象出来,写成一个类似于SQLHelper的工具类,放在D层,用的时候直接调用。


定义一个ConvertHelper的工具类


Imports System.Collections.Generic  '增加泛型的命名空间
Imports System.Reflection '引入反射:为了使用PropertyInfoPublic Class ConvertHelper'将datatable转化为泛型集合Public Shared Function convertToList(Of T As {New})(ByVal dt As DataTable) As IList(Of T)'注意:convertToList(Of T As {New}) 这里的new是用来约束T的,必须有,不然new T的时候会出现错误Dim myList As New List(Of T)   '定义最终返回的集合Dim myTpye As Type = GetType(T) '得到实体类的类型名Dim dr As DataRow   '定义行集Dim tempName As String = String.Empty   '定义一个临时变量'遍历DataTable的所有数据行For Each dr In dt.RowsDim myT As New T    '定义一个实体类的对象Dim propertys() As PropertyInfo = myT.GetType().GetProperties()  '定义属性集合Dim Pr As PropertyInfo'遍历该对象的所有属性For Each Pr In propertystempName = Pr.Name '将属性名称赋值给临时变量'检查DataTable是否包含此列(列名==对象的属性名) If (dt.Columns.Contains(tempName)) Then     '将此属性与datatable里的列明比较,查看datatable是否包含此属性'判断此属性是否有SetterIf (Pr.CanWrite = False) Then   '判断此属性是否可写,如果不可写,跳出本次循环Continue ForEnd IfDim value As Object = dr(tempName)  '定义一个对象型的变量来保存列的值If (value.ToString <> DBNull.Value.ToString()) Then '如果非空,则赋给对象的属性Pr.SetValue(myT, value, Nothing)    '在运行期间,通过反射,动态的访问一个对象的属性End IfEnd IfNextmyList.Add(myT)   '添加到集合NextReturn myList   '返回实体集合End Function
End Class


U层


Public Class frmCheckBalancePrivate Sub btnCheck_Click(sender As Object, e As EventArgs) Handles btnCheck.Click'Dim EUser As New Entity.StudentInfoEntity   '实例化新的UserInfoEntity,用来传递B层的实体Dim EUser As List(Of Entity.StudentInfoEntity)   '实例化新的泛型集合,用来传递B层的实体Dim BCheck As New BLL.CheckBalanceBLL    '定义BCheck,用来传递参数Dim User As New Entity.StudentInfoEntity '定义传递的参数User.cardNo = txtCID.Text.Trim() '卡号赋值EUser = BCheck.Check(User) '调用B层查询余额的方法'判断 返回的泛型集合是否为空'不为空If IsNothing(EUser) = False Then'查询后显示到窗体上txtSID.Text = EUser(0).studentID     '0代表第一个实体txtName.Text = EUser(0).studentNametxtSex.Text = EUser(0).SextxtDpt.Text = EUser(0).DepartmenttxtGrade.Text = EUser(0).GradetxtClass.Text = EUser(0).SclasstxtState.Text = EUser(0).StatetxtComment.Text = EUser(0).CommenttxtBalance.Text = EUser(0).BalanceElse     '为空txtCID.Text = ""         '清空卡号文本框txtCID.Focus()          '光标停留在卡号文本框End IfEnd Sub'退出按钮Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.ClickMe.Close()End Sub
End Class


B层


Public Class CheckBalanceBLL'定义一个Check函数,用于查询学生余额Function Check(ByVal user As Entity.StudentInfoEntity) As List(Of Entity.StudentInfoEntity)   '返回一个泛型类'先判断卡号是否为空If user.cardNo.ToString.Trim = "" ThenMsgBox("卡号不能为空,请输入卡号!", MsgBoxStyle.Exclamation, "警告")Return NothingEnd If'卡号不为空Dim DUser As New DAL.CheckBalanceDALDim EUser As List(Of Entity.StudentInfoEntity)EUser = DUser.Query(user)     '把实体user传到EUser里,即传到实体层中'判断:集合是否是空值If IsNothing(EUser) = False ThenReturn EUserElseMsgBox("没有此卡号的记录,请重新输入卡号", MsgBoxStyle.Exclamation, "警告")Return NothingEnd IfEnd FunctionEnd Class


D层


Imports System.Data.SqlClient
Imports System.Data
Public Class CheckBalanceDALFunction Query(ByVal user As Entity.StudentInfoEntity) As List(Of Entity.StudentInfoEntity)      '返回实体'定义一个操作数据库的助手类Dim MySqlHelper As New SqlHelper'定义对数据库的操作语句Dim strSql As StringstrSql = "select * from T_StudentInfo where cardNo=@cardNo"'加入参数Dim paras As SqlParameter()paras = {New SqlParameter("@cardNo", user.cardNo)}'执行查询,并将查询的结果保存到dt里边Dim dt As New DataTable'保存转换后的泛型集合Dim myList As List(Of Entity.StudentInfoEntity)'执行查询dt = MySqlHelper.ExecSelect(strSql, CommandType.Text, paras)'先判断dt是否为空If dt.Rows.Count > 0 Then'将dt转换为泛型集合myList = ConvertHelper.convertToList(Of Entity.StudentInfoEntity)(dt)Return myListElseReturn NothingEnd IfEnd Function
End Class


结果:





注:实体层的代码在这里略过。使用泛型集合传递数据,必须满足:实体类的属性名必须和数据库表中的字段名一模一样;必须有已知的实体类和DataTable中的数据相对应,也就是说必须明确你要转换成的实体类类型,否则没办法指定泛型集合的类型,也就没办法调用。


三、【反思】


    刚开始的时候,只是在设计模式中见过泛型这个词。对它并没有多深的理解。后来,上课的时候,米老师和师哥师姐一直提,才慢慢地开始了解。
    敲机房收费系统的时候,刚开始也是使用的DataTable来返回数据的。后来,经过跟别的同学进行交流,都是建议用泛型。后来就改成使用泛型了,省得以后再返工。这就是“前人栽树,后人乘凉”吧 。
    做事情的时候,要和别人多交流,多看看别人是如何做的,不要总守着自己的那一亩三分地,目光局限在自己的世界里。
    多交流、多思考!






这篇关于【个人机房重构】——泛型集合代替DataTable的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/969075

相关文章

基于Redis有序集合实现滑动窗口限流的步骤

《基于Redis有序集合实现滑动窗口限流的步骤》滑动窗口算法是一种基于时间窗口的限流算法,通过动态地滑动窗口,可以动态调整限流的速率,Redis有序集合可以用来实现滑动窗口限流,本文介绍基于Redis... 滑动窗口算法是一种基于时间窗口的限流算法,它将时间划分为若干个固定大小的窗口,每个窗口内记录了该时间

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字

uva 11178 计算集合模板题

题意: 求三角形行三个角三等分点射线交出的内三角形坐标。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <

HomeBank:开源免费的个人财务管理软件

在个人财务管理领域,找到一个既免费又开源的解决方案并非易事。HomeBank&nbsp;正是这样一个项目,它不仅提供了强大的功能,还拥有一个活跃的社区,不断推动其发展和完善。 开源免费:HomeBank 是一个完全开源的项目,用户可以自由地使用、修改和分发。用户友好的界面:提供直观的图形用户界面,使得非技术用户也能轻松上手。数据导入支持:支持从 Quicken、Microsoft Money

分布式系统的个人理解小结

分布式系统:分的微小服务,以小而独立的业务为单位,形成子系统。 然后分布式系统中需要有统一的调用,形成大的聚合服务。 同时,微服务群,需要有交流(通讯,注册中心,同步,异步),有管理(监控,调度)。 对外服务,需要有控制的对外开发,安全网关。

Java IO 操作——个人理解

之前一直Java的IO操作一知半解。今天看到一个便文章觉得很有道理( 原文章),记录一下。 首先,理解Java的IO操作到底操作的什么内容,过程又是怎么样子。          数据来源的操作: 来源有文件,网络数据。使用File类和Sockets等。这里操作的是数据本身,1,0结构。    File file = new File("path");   字

Java基础回顾系列-第六天-Java集合

Java基础回顾系列-第六天-Java集合 集合概述数组的弊端集合框架的优点Java集合关系图集合框架体系图java.util.Collection接口 List集合java.util.List接口java.util.ArrayListjava.util.LinkedListjava.util.Vector Set集合java.util.Set接口java.util.HashSetjava

【408数据结构】散列 (哈希)知识点集合复习考点题目

苏泽  “弃工从研”的路上很孤独,于是我记下了些许笔记相伴,希望能够帮助到大家    知识点 1. 散列查找 散列查找是一种高效的查找方法,它通过散列函数将关键字映射到数组的一个位置,从而实现快速查找。这种方法的时间复杂度平均为(

LeetCode 第414场周赛个人题解

目录 Q1. 将日期转换为二进制表示 原题链接 思路分析 AC代码 Q2. 范围内整数的最大得分 原题链接 思路分析 AC代码 Q3. 到达数组末尾的最大得分 原题链接 思路分析 AC代码 Q4. 吃掉所有兵需要的最多移动次数 原题链接 思路分析 AC代码 Q1. 将日期转换为二进制表示 原题链接 Q1. 将日期转换为二进制表示 思路分析

Java泛型类型解析

解析泛型类型 获取字段泛型类型 **java.lang.reflect.Field#getGenericType**: 作用:返回字段的泛型类型。返回类型:Type。如果字段是一个泛型类型,这个方法将返回一个表示这个泛型类型的 Type 对象,比如 ParameterizedType,TypeVariable 等等。如果字段不是泛型类型,这个方法将返回字段的具体类型,即 Class 对象。示例