在第一次做机房收费系统的时候,有一大“难题”就是组合查询,有3个框架相同的窗体,基本同样的功能,在机房重构的时候,用到模板方法来进行对组合查询的实现,这种方法很方便也很高效,同样,其中也涉及到一些有用的知识,下面我来梳理一下组合查询是如何实现的。
【功能概况】
有3个这样的窗体,都是类似的功能和窗体界面,当一件事情重复3遍的时候,我们就要好好思考一下,如何减轻代码量,实现高效率。那么,下面我来说说模板方法的具体应用。
【具体实现】
首先,先建立一个窗体当模板。
里面的代码如下:
Public Class frmGroupQuery
'定义一个实体来传递参数,同7层其他窗体
Public egroupquery As New Entity.GroupQueryInfo
'查询按钮下的代码,做逻辑判断
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
DataGridView1.AllowUserToAddRows = False
If cmbRelation1.Text = "" Then
If cmbField1.Text = "" Then
MsgBox("请输入字段名")
Exit Sub
ElseIf cmbOperation1.Text = "" Then
MsgBox("请输入操作符")
Exit Sub
ElseIf txtContent1.Text = "" Then
MsgBox("请输入要查询的内容")
Exit Sub
End If
End If
If cmbRelation1.Text <> "" Then
If cmbField1.Text = "" Then
MsgBox("请输入第一行字段名")
Exit Sub
ElseIf cmbOperation1.Text = "" Then
MsgBox("请输入第一行操作符")
Exit Sub
ElseIf txtContent1.Text = "" Then
MsgBox("请输入第一行要查询的内容")
Exit Sub
ElseIf cmbField2.Text = "" Then
MsgBox("请输入第二行字段名")
Exit Sub
ElseIf cmbOperation2.Text = "" Then
MsgBox("请输入第二行操作符")
Exit Sub
ElseIf txtContent2.Text = "" Then
MsgBox("请输入第二行要查询的内容")
Exit Sub
End If
End If
If cmbRelation2.Text <> "" Then
If cmbField1.Text = "" Then
MsgBox("请输入字段名")
ElseIf cmbOperation1.Text = "" Then
MsgBox("请输入操作符")
ElseIf txtContent1.Text = "" Then
MsgBox("请输入要查询的内容")
ElseIf cmbField2.Text = "" Then
MsgBox("请输入字段名")
ElseIf cmbOperation2.Text = "" Then
MsgBox("请输入操作符")
ElseIf txtContent2.Text = "" Then
MsgBox("请输入要查询的内容")
ElseIf cmbField3.Text = "" Then
MsgBox("请输入字段名")
ElseIf cmbOperation3.Text = "" Then
MsgBox("请输入操作符")
ElseIf txtContent3.Text = "" Then
MsgBox("请输入要查询的内容")
End If
End If
<pre name="code" class="vb" style="font-size: 24px;"> '定义一个实体参数
Dim egroupquery As New Entity.GroupQueryInfo
'GetDBName在这里是用了下面的虚方法(可以在子窗体重写)
egroupquery.cmbFied1 = GetDBName(cmbField1.Text.Trim)
egroupquery.cmbFied2 = GetDBName(cmbField2.Text.Trim)
egroupquery.cmbFied3 = GetDBName(cmbField3.Text.Trim)
egroupquery.cmbOperation1 = cmbOperation1.Text.Trim
egroupquery.cmbOperation2 = cmbOperation2.Text.Trim
egroupquery.cmbOperation3 = cmbOperation3.Text.Trim
egroupquery.txtContent1 = txtContent1.Text.Trim
egroupquery.txtContent2 = txtContent2.Text.Trim
egroupquery.txtContent3 = txtContent3.Text.Trim
egroupquery.cmbRelation1 = GetDBName(cmbRelation1.Text.Trim)
egroupquery.cmbRelation2 = GetDBName(cmbRelation2.Text.Trim)
'这里的GetTable也是一个虚方法的使用
egroupquery.GetTable = GetTable()
'经典7层的套路
Dim fa As New Facade.LoginFacade
Dim table = fa.GroupQuery(egroupquery)
If table Is Nothing Then
MsgBox("该条件下无记录~")
'设置datagridview控件的数据源
DataGridView1.DataSource = Nothing
Else
'这里也是一个虚方法
Todgv(table)
End If
End Sub
' 定义虚函数GetDBName,获取不同数据库的字段名
Protected Overridable Function GetDBName(ByVal control As String) As String
Return ""
End Function
' 定义虚函数GetTable,获取不同数据库的表名
Protected Overridable Function GetTable() As String
Return ""
End Function
'定义一个虚函数,设置不同的显示标题
Protected Overridable Sub Todgv(ByVal table As DataTable)
End Sub
End Class
其他的小功能这里就不一一写了,很简单,这里只把一些重要的思想方法分析一下~
【子窗体的实现】
创建一个子窗体,为继承的窗体。
接下来选择要继承哪个窗体:
之后就会出现一个一模一样的窗体。
在子窗体里怎么实现继承呢?那就是重写方法,来实现个性化
Public Class frmStudentInfo
'重写方法——在datagridview里面显示不同的标题
Protected Overrides Sub Todgv(table As DataTable)
'从DAL层返回的table来赋给datagridview的数据源
DataGridView1.DataSource = table
DataGridView1.Columns(0).HeaderCell.Value = "卡号"
DataGridView1.Columns(1).HeaderText = "类型"
DataGridView1.Columns(2).HeaderText = "是否使用"
DataGridView1.Columns(3).HeaderText = "学号"
DataGridView1.Columns(4).HeaderText = "姓名"
DataGridView1.Columns(5).HeaderText = "性别"
DataGridView1.Columns(6).HeaderText = "系别"
DataGridView1.Columns(7).HeaderText = "余额"
DataGridView1.Columns(8).HeaderText = "注册日期"
DataGridView1.Columns(9).HeaderText = "操作员"
DataGridView1.Columns(10).HeaderText = "年级"
DataGridView1.Columns(11).HeaderText = "班级"
DataGridView1.Columns(12).HeaderText = "备注"
DataGridView1.Columns(12).Visible = False
End Sub
'重写方法——将用户选择的不同的字段名称转换成数据库中的字段,返回父窗体进行交流
Protected Overrides Function GetDBName(control As String) As String
Select Case (control)
Case "卡号"
Return "Chr_CardID"
Case "类型"
Return "Chr_Type"
Case "姓名"
Return "Chr_Name"
Case "性别"
Return "Chr_Sex"
Case "系别"
Return "Chr_Department"
Case "注册日期"
Return "EnrollDate"
Case "操作员"
Return "Chr_Operator"
Case "与"
Return "and"
Case "或"
Return "or"
Case Else
Return ""
End Select
End Function
'重写方法——赋值给DAL层要查哪个表的名称,返回父窗体
Protected Overrides Function GetTable() As String
egroupquery.GetTable = "View_CS"
Return egroupquery.GetTable
End Function
'界面上的个性化显示
Private Sub frmStudentInfo_Load(sender As Object, e As EventArgs) Handles MyBase.Load
cmbField1.Items.Add("卡号")
cmbField1.Items.Add("类型")
cmbField1.Items.Add("姓名")
cmbField1.Items.Add("性别")
cmbField1.Items.Add("系别")
'cmbField1.Items.Add("机器号")
cmbField1.Items.Add("注册日期")
cmbField1.Items.Add("操作员")
cmbField2.Items.Add("卡号")
cmbField2.Items.Add("类型")
cmbField2.Items.Add("姓名")
cmbField2.Items.Add("性别")
cmbField2.Items.Add("系别")
'cmbField2.Items.Add("机器号")
cmbField2.Items.Add("注册日期")
cmbField2.Items.Add("操作员")
cmbField3.Items.Add("卡号")
cmbField3.Items.Add("类型")
cmbField3.Items.Add("姓名")
cmbField3.Items.Add("性别")
cmbField3.Items.Add("系别")
'cmbField3.Items.Add("机器号")
cmbField3.Items.Add("注册日期")
cmbField3.Items.Add("操作员")
'cmbOperation1.Items.Add("<")
'cmbOperation1.Items.Add(">")
cmbOperation1.Items.Add("=")
cmbOperation1.Items.Add("<>")
'cmbOperation2.Items.Add("<")
'cmbOperation2.Items.Add(">")
cmbOperation2.Items.Add("=")
cmbOperation2.Items.Add("<>")
'cmbOperation3.Items.Add("<")
'cmbOperation3.Items.Add(">")
cmbOperation3.Items.Add("=")
cmbOperation3.Items.Add("<>")
cmbRelation1.Items.Add("与")
cmbRelation1.Items.Add("或")
cmbRelation2.Items.Add("与")
cmbRelation2.Items.Add("或")
End Sub
子窗体的功能就是下面这样与父窗体进行交流的:
第一个,GetTable()方法:
Protected Overrides Function GetTable() As String
egroupquery.GetTable = "View_CS"
Return egroupquery.GetTable
End Function
不用传递参数,直接返回,所以括号里面没有东西,直接定义返回的类型string。
告诉父窗体,我在这个子窗体里面要用哪个数据库的表。
第二个,GetDBName():
Protected Overrides Function GetDBName(control As String) As String
Select Case (control)
Case "卡号"
Return "Chr_CardID"
需要从父窗体里取值再返回,取值直接定义一个control这样的参数,给他string类型,再定义返回的类型string.
让父窗体知道,用户选择什么字段,我应该传递什么样的数据库的字段名称。
第三个,Todgv方法
Protected Overrides Sub Todgv(table As DataTable)
这里跟前两个也不同,就是只取出父窗体的table的值,不返回,所以就没有后面的as string 这样的字。
【存储过程】
USE [Charge]
GO
/****** Object: StoredProcedure [dbo].[PROC_GroupQuery] Script Date: 03/26/2016 13:44:31 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[PROC_GroupQuery]
@cmbField1 varchar(20),
@cmbField2 varchar(20),
@cmbField3 varchar(20),
@cmbOperation1 varchar(20),
@cmbOperation2 varchar(20),
@cmbOperation3 varchar(20),
@txtContent1 varchar(20),
@txtContent2 varchar(20),
@txtContent3 varchar(20),
@tableName varchar(20),
@cmbRelation1 varchar(20),
@cmbRelation2 varchar(20)
as
declare @TempSql varchar(500)
begin
SET @TempSql='SELECT * FROM '+@tableName +' WHERE ' +@cmbField1 +@cmbOperation1+char(39) + @txtContent1 + char(39)
if @cmbRelation1 != ''
BEGIN
SET @TempSql=@TempSql+@cmbRelation1+CHAR(32)+@cmbField2 +@cmbOperation2+CHAR(39)+@txtContent2+CHAR(39)
if @cmbRelation2!= ''
BEGIN
SET @TempSql=@TempSql+@cmbRelation2+CHAR(32)+@cmbField3+@cmbOperation3+CHAR(39)+@txtContent3+CHAR(39)
END
END
EXECUTE(@TempSql)
END
【小结】
在组合查询的模板方法的应用里,如何在父窗体里写虚方法,如何做子窗体里继承重写方法,实现用一个父窗体模板,来让子窗体实现自己的个性化表现,很实用的功能。