组合查询这个功能的实现,在VB中大家已经体验过了,其中有大量的重复代码,极大地影响了系统的性能,这篇博客将为大家介绍一种面向对象的VB.NET版组合查询,其中结合模板方法模式对组合查询进行了优化,什么是模板方法模式?它的杀手锏是什么?为什么通过它我们就可以实现代码复用,我们到底可以怎么达到我们想要的结果呢?预知答案,精彩内容如下:
有关模板方法模式见博客:http://blog.csdn.net/hongwei15732623364/article/details/50659283
ALTER PROCEDURE [dbo].[PROC_Studentservice] @Comboa1 varchar(50), @Comboa2 varchar(50), @Comboa3 varchar(50), @Combob1 varchar(50), @Combob2 varchar(50), @Combob3 varchar(50), @Combod1 varchar(50), @Combod2 varchar(50), @txtc1 varchar(50), @txtc2 varchar(50), @txtc3 varchar(50), @listName varchar(20) AS declare @strSQL varchar(500) BEGIN set @strSQL='select * from '+@listName+' where '+@Comboa1+@Combob1+char(39)+@txtc1+char(39) if(@Combod1<>'') begin set @strSQL =@strSQL+@Combod1+CHAR(32)+@Comboa2+@Combob2+CHAR(39)+@txtc2+CHAR(39) if (@Combod2<>'') begin set @strSQL=@strSQL +@Combod2+CHAR(32)+@Comboa3+@Combob3+CHAR(39)+@txtc3+CHAR(39) end end execute(@strSQL) END
存储过程这段纠结了好半天,SQL语句少写一个空格,最后结果都会显示“无法找到表0”,char(),括号中的数值表示和ASC码对应,这个也是刚知道的。通过这次存储过程的使用,对它了解更深了,但有时候还是会弄错,不过没关系,尝试着去做了,总会明白过来的。
(1)首先窗体加载后Combobox控件中需要自动加载出应有的查询字段:
<span style="font-size:18px;"><span style="font-size:18px;"> Private Sub UGroupQuery_Load(sender As Object, e As EventArgs) Handles MyBase.Load '将参数传递给实体,赋初值 '不同窗体字段不同,赋“”,子窗体重写它 e_group.comboa1 = "" e_group.comboa2 = "" e_group.comboa3 = "" '操作符 Combob1.Items.Add(">") Combob1.Items.Add("<") Combob1.Items.Add("=") Combob1.Items.Add("<>") Combob2.Items.Add(">") Combob2.Items.Add("<") Combob2.Items.Add("=") Combob2.Items.Add("<>") Combob3.Items.Add(">") Combob3.Items.Add("<") Combob3.Items.Add("=") Combob3.Items.Add("<>") '组合关系 Combod1.Items.Add("与") Combod1.Items.Add("或") Combod2.Items.Add("与") Combod2.Items.Add("或") '窗体加载后,后两组控件默认不可用 Comboa2.Enabled = False Comboa3.Enabled = False Combob2.Enabled = False Combob3.Enabled = False Combod2.Enabled = False txtc2.Enabled = False txtc3.Enabled = False '设置选中单元格就选中行 dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect Dim i As Integer For i = 0 To dgv.Columns.Count - 1 dgv.Columns(i).Width = DataGridViewAutoSizeColumnMode.AllCells Next End Sub</span></span>
(2)窗体的Click事件:
<span style="font-size:18px;"><span style="font-size:18px;"> Protected e_group As New Entity.GroupEntity ''' <summary> ''' 查询,Click事件 ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> ''' Private Sub btnCheck_Click(sender As Object, e As EventArgs) Handles btnCheck.Click dgv.DataSource = Nothing '单击查询按钮,清空控件 '限制第一行输入不为空 If Combod1.Text = "" Then If Comboa1.Text = "" Or Combob1.Text = "" Or txtc1.Text = "" Then MsgBox("请输入第一行全部内容") End If End If '若第一个组合关系不为空,则判断前两行文本框是否为空 If Combod1.Text <> "" Then If Comboa2.Text = "" Or Combob2.Text = "" Or txtc2.Text = "" Then MsgBox("请输入第二行全部内容") End If End If '若第二个组合关系不为空,则判断所有文本框是否为空 If Combod2.Text <> "" Then If Comboa3.Text = "" Or Combob3.Text = "" Or txtc3.Text = "" Then MsgBox("请输入第三行内容") End If End If '将参数传给实体 e_group.Listname = GetdbName() e_group.comboa1 = ToEnglish(Comboa1.Text) e_group.comboa2 = ToEnglish(Comboa2.Text) e_group.comboa3 = ToEnglish(Comboa3.Text) e_group.combob1 = Combob1.Text.Trim e_group.combob2 = Combob2.Text.Trim e_group.combob3 = Combob3.Text.Trim e_group.txtc1 = txtc1.Text.Trim e_group.txtc2 = txtc2.Text.Trim e_group.txtc3 = txtc3.Text.Trim '前者还是后者 e_group.combod1 = ToEnglish(Combod1.Text) e_group.combod2 = ToEnglish(Combod2.Text) Dim dt As New DataTable Dim ugroup As New Facade.GroupFacade '实例化外观层 dt = ugroup.Grouplist1(e_group) If dt Is Nothing Then MsgBox("该条件下没有记录") Else Call Todgv() End If End Sub</span></span>
(3)写出模板方法模式的虚方法:
<span style="font-size:18px;"><span style="font-size:18px;"> ''' <summary> ''' 模版方法,定义虚函数ToEnglish,查询字段转化为数据库字段 ''' </summary> ''' <param name="turnName"></param> ''' <returns></returns> ''' <remarks></remarks> Public Overridable Function ToEnglish(turnName As String) As String Return "" End Function </span></span>
<span style="font-size:18px;"><span style="font-size:18px;"> ''' <summary> ''' 获得数据库表名 ''' </summary> ''' <returns></returns> ''' <remarks></remarks> Public Overridable Function GetdbName() As String Return "" End Function </span></span>
<span style="font-size:18px;"><span style="font-size:18px;"> ''' <summary> ''' 将表显示到Datagridview中 ''' </summary> ''' <remarks></remarks> Protected Overridable Sub Todgv() End Sub</span></span>
(4)优化控件的可用性:
<span style="font-size:18px;"><span style="font-size:18px;">''' <summary> ''' 第一个组合关系不为空,则使控件可输入 ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub Combod1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles Combod1.SelectedIndexChanged If Combod1.Text = "" Then Comboa2.Enabled = False Comboa3.Enabled = False Combob2.Enabled = False Combob3.Enabled = False Combod2.Enabled = False txtc2.Enabled = False txtc3.Enabled = False Else Comboa2.Enabled = True Combob2.Enabled = True Combod2.Enabled = True txtc2.Enabled = True End If End Sub ''' <summary> ''' 第二个组合关系不为空,则使控件可输入 ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub Combod2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles Combod2.SelectedIndexChanged If Combod2.Text = "" Then Comboa3.Enabled = False Combob3.Enabled = False txtc3.Enabled = False Else Comboa3.Enabled = True Combob3.Enabled = True txtc3.Enabled = True End If End Sub End Class</span></span>
(1)添加单例模式:
<span style="font-size:18px;"><span style="font-size:18px;"> Private Shared Student As UStudentservice '声明一个静态变量,类似C#中static Private Sub New() '初始化为私有,外部代码不能直接New该窗体 ' 此调用是设计器所必需的。 InitializeComponent() ' 在 InitializeComponent() 调用之后添加任何初始化。 End Sub '写一个公有的方法检验这个类是否初始化以及被释放过 Public Shared Function GetInstance() As UStudentservice If Student Is Nothing OrElse Student.IsDisposed Then '当窗体被关闭时实例化该窗体,因为关闭后不会将变量设置为nothing,只是将窗体dispose掉 Student = New UStudentservice Student.MdiParent = frmMain.ActiveForm End If Return Student '如果已经实例化,则返回窗体本身 End Function</span></span>
注意,在主窗体frmMain中的实现:
<span style="font-size:18px;"><span style="font-size:18px;"> ''' <summary> ''' 学生基本信息维护窗体显示 ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub 学生基本信息维护ToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles 学生基本信息维护ToolStripMenuItem.Click UStudentservice.GetInstance.Show() End Sub</span></span>
(2)利用哈希表完美实现加载控件的Item,省去一个一个写进去的烦恼:
<span style="font-size:18px;"><span style="font-size:18px;"> ''' <summary> ''' 加载Combo的item ''' </summary> ''' <param name="sender"></param> ''' <param name="e"></param> ''' <remarks></remarks> Private Sub UStudentservice_Load(sender As Object, e As EventArgs) Handles MyBase.Load Dim turnField As New Hashtable '定义处理字符串转换的hashtable Dim FieldName() As String Dim FieldValue() As String '使用哈希表将数据库字段进行转换 '数据库中对应字段 FieldName = {"卡号", "姓名", "学号", "性别", "系别", "年级", "班级", "开户人"} FieldValue = {"Cardno", "Studentname", "Studentno", "Sex", "Department", "Grade", "Onclass", "Holder"} '放到Field字段中 Comboa1.Items.AddRange(FieldName) Comboa2.Items.AddRange(FieldName) Comboa3.Items.AddRange(FieldName) Comboa1.Items.Add("卡号") 'value添加到hashtable For i As Integer = 0 To FieldName.Count - 1 turnField.Add(FieldName(i), FieldValue(i)) Next End Sub</span></span>
(3)转换成数据库可识别的名称:
<span style="font-size:18px;"><span style="font-size:18px;"> ''' <summary> ''' 加载的汉字转换陈数据库的字段 ''' </summary> ''' <param name="turnName"></param> ''' <returns></returns> ''' <remarks></remarks> Public Overrides Function ToEnglish(turnName As String) As String 'Return MyBase.ToEnglish(comboa) Select Case turnName Case "卡号" Return "Cardno" Case "姓名" Return "Studentname" Case "学号" Return "Studentno" Case "性别" Return "Sex" Case "系别" Return "Department" Case "年级" Return "Grade" Case "班级" Return "Onclass" Case "开户人" Return "Holder" Case "与" Return "and" Case "或" Return "or" Case Else Return "" End Select End Function</span></span>
(4)重写具体的方法:
<span style="font-size:18px;"><span style="font-size:18px;"> ''' <summary> ''' 重写父类中方法,传数据库表名 ''' </summary> ''' <returns></returns> ''' <remarks></remarks> Public Overrides Function GetdbName() As String Return "T_Student" End Function </span></span>
<span style="font-size:18px;"><span style="font-size:18px;"> Protected Overrides Sub Todgv() dgv.DataSource = Nothing Dim UGroupQuery As New UGroupQuery '实例化一个窗体 Dim ugroup As New Facade.GroupFacade Dim table As DataTable Try table = ugroup.Grouplist1(e_group) If table.Rows.Count = 0 Then table.Clear() dgv.DataSource = Nothing dgv.Refresh() MsgBox("没有查询到内容") Else 'dgv.DataSource = Nothing dgv.DataSource = table dgv.Columns(0).HeaderText = "卡号" dgv.Columns(1).HeaderText = "姓名" dgv.Columns(2).HeaderText = "学号" dgv.Columns(3).HeaderText = "性别" dgv.Columns(4).HeaderText = "系别" dgv.Columns(5).HeaderText = "年级" dgv.Columns(6).HeaderText = "班级" dgv.Columns(7).HeaderText = "开户人" '删除组后空白行 dgv.AllowUserToAddRows = False End If Catch ex As Exception MessageBox.Show(ex.Message.ToString, "提示") End Try End Sub</span></span>
四、总结感受:
组合查询整体的思路和VB版的机房收费系统几乎一样,不一样的是这次我加入了设计模式,完美实现了代码复用,这两次做机房收费系统,感触最深的就是思路已经可以很容易找到,具体的模式使用还需要多锻炼,这次组合查询优化的亮点在于:
1.使用单例模式轻松搞定多窗体显示的问题,给用户带来极大方便;
2.使用模板方法模式将相同部分封装,完美实现代码复用,增加系统的性能,实现面向对象;
3.存储过程提高系统性能,使系统对数据库的访问变得简单;
4.哈希表实现控件的Item的添加,减少代码量,减少输入错误,提高工作效率。
组合查询看似复杂,但是只要找到总线,慢慢缕清思路,它便不是问题,所以写代码前最重要的过程是思考。
感谢您宝贵的时间,欢迎路过的大牛指正!