在第一次做机房收费系统的时候,有一大“难题”就是组合查询,有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
【小结】
在组合查询的模板方法的应用里,如何在父窗体里写虚方法,如何做子窗体里继承重写方法,实现用一个父窗体模板,来让子窗体实现自己的个性化表现,很实用的功能。