组合查询这个功能的实现,在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控件中需要自动加载出应有的查询字段:
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
(2)窗体的Click事件:
Protected e_group As New Entity.GroupEntity
'''
''' 查询,Click事件
'''
'''
'''
'''
'''
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
(3)写出模板方法模式的虚方法:
'''
''' 模版方法,定义虚函数ToEnglish,查询字段转化为数据库字段
'''
'''
'''
'''
Public Overridable Function ToEnglish(turnName As String) As String
Return ""
End Function
'''
''' 获得数据库表名
'''
'''
'''
Public Overridable Function GetdbName() As String
Return ""
End Function
'''
''' 将表显示到Datagridview中
'''
'''
Protected Overridable Sub Todgv()
End Sub
(4)优化控件的可用性:
'''
''' 第一个组合关系不为空,则使控件可输入
'''
'''
'''
'''
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
'''
''' 第二个组合关系不为空,则使控件可输入
'''
'''
'''
'''
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
(1)添加单例模式:
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
注意,在主窗体frmMain中的实现:
'''
''' 学生基本信息维护窗体显示
'''
'''
'''
'''
Private Sub 学生基本信息维护ToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles 学生基本信息维护ToolStripMenuItem.Click
UStudentservice.GetInstance.Show()
End Sub
(2)利用哈希表完美实现加载控件的Item,省去一个一个写进去的烦恼:
'''
''' 加载Combo的item
'''
'''
'''
'''
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
(3)转换成数据库可识别的名称:
'''
''' 加载的汉字转换陈数据库的字段
'''
'''
'''
'''
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
(4)重写具体的方法:
'''
''' 重写父类中方法,传数据库表名
'''
'''
'''
Public Overrides Function GetdbName() As String
Return "T_Student"
End Function
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
四、总结感受:
组合查询整体的思路和VB版的机房收费系统几乎一样,不一样的是这次我加入了设计模式,完美实现了代码复用,这两次做机房收费系统,感触最深的就是思路已经可以很容易找到,具体的模式使用还需要多锻炼,这次组合查询优化的亮点在于:
1.使用单例模式轻松搞定多窗体显示的问题,给用户带来极大方便;
2.使用模板方法模式将相同部分封装,完美实现代码复用,增加系统的性能,实现面向对象;
3.存储过程提高系统性能,使系统对数据库的访问变得简单;
4.哈希表实现控件的Item的添加,减少代码量,减少输入错误,提高工作效率。
组合查询看似复杂,但是只要找到总线,慢慢缕清思路,它便不是问题,所以写代码前最重要的过程是思考。
感谢您宝贵的时间,欢迎路过的大牛指正!