做完第一遍机房后对组合查询有种心有余悸的感觉,但这次有设计模式来帮我们就不用在害怕了。在机房收费中有三个组合查询的窗体,它们的外表一样,只是各自的下拉框中的内容不一样,所以从设计模式中来讲模板模式就能解决这个难题。
所谓模板就像是我们折纸一样,有一个参照物,做出来的成品就相当于对参照物的复制品。所以这里的组合查询就需要一个父类窗体:用来承载所有的控件和代码中需要用到的方法,“子”窗体就来继承并且对一些方法进行重写,完成自己的特殊化构造,那么先来看窗体的建造过程:
先将一个具有基本骨架的窗体建立好,我在这里命名为frmGroupQuery。其中有用到的方法:GetEnglish(用来将字段名转换为对应的英文名称,同数据库中字段名一致),GetTable(每个窗体获取各自需要的数据库名称);如下图所示:
其中代码:可以看做是对每个窗体的代码进行提取公因式的操作。
Imports Facade.FadGroupQuery Public Class frmGroupQuery Public groupQuery As New Model.GroupQueryModel '定义一个实体参数 '主要是用来判断界面的控件中是否已经填入数据 Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btnQuery.Click '第一行组合关系为空 If cbxRelation1.Text = "" Then If cbxString1.Text = "" Then MsgBox("请输入字段名") ElseIf cbxOperate1.Text = "" Then MsgBox("请输入操作符") ElseIf txtQuery1.Text = "" Then MsgBox("请输入要查询的内容") End If End If '当第一个组合关系不为空时,就要求前两行的文本都不为空,所以要一一进行判断 If cbxRelation1.Text <> "" Then If cbxString1.Text = "" Then MsgBox("请输入字段名") ElseIf cbxOperate1.Text = "" Then MsgBox("请输入操作符") ElseIf txtQuery1.Text = "" Then MsgBox("请输入查询内容") ElseIf cbxString2.Text = "" Then MsgBox("请输入字段名") ElseIf cbxOperate2.Text = "" Then MsgBox("请输入操作符") ElseIf txtQuery2.Text = "" Then MsgBox("请输入查询内容") End If End If '当第二个组合关系不为空时 If cbxRelation2.Text <> "" Then If cbxString1.Text = "" Then MsgBox("请输入字段名") ElseIf cbxOperate1.Text = "" Then MsgBox("请输入操作符") ElseIf txtQuery1.Text = "" Then MsgBox("请输入查询内容") ElseIf cbxString2.Text = "" Then MsgBox("请输入字段名") ElseIf cbxOperate2.Text = "" Then MsgBox("请输入操作符") ElseIf txtQuery2.Text = "" Then MsgBox("请输入查询内容") ElseIf cbxString2.Text = "" Then MsgBox("请输入字段名") ElseIf cbxOperate2.Text = "" Then MsgBox("请输入操作符") ElseIf txtQuery2.Text = "" Then MsgBox("请输入查询内容") ElseIf cbxString3.Text = "" Then MsgBox("请输入字段名") ElseIf cbxOperate3.Text = "" Then MsgBox("请输入操作符") ElseIf txtQuery3.Text = "" Then MsgBox("请输入查询内容") End If End If Dim MgroupQuery As New Model.GroupQueryModel MgroupQuery.cbxString1 = GetEnglish(cbxString1.Text.Trim()) MgroupQuery.cbxString2 = GetEnglish(cbxString2.Text.Trim()) MgroupQuery.cbxString3 = GetEnglish(cbxString3.Text.Trim()) MgroupQuery.cbxOperate1 = cbxOperate1.Text.Trim MgroupQuery.cbxOperate2 = cbxOperate2.Text.Trim MgroupQuery.cbxOperate3 = cbxOperate3.Text.Trim MgroupQuery.txtQuery1 = txtQuery1.Text MgroupQuery.txtQuery2 = txtQuery2.Text MgroupQuery.txtQuery3 = txtQuery3.Text MgroupQuery.cbxRelation1 = GetEnglish(cbxRelation1.Text.Trim) MgroupQuery.cbxRelation2 = GetEnglish(cbxRelation2.Text.Trim) MgroupQuery.gettable = GetTable() '实例化外观层 Dim fadGroups As New Facade.FadGroupQuery '定义一个载体 Dim endResult As New DataTable '获取从外观层传出的数据值 endResult = fadGroups.F_GroupQuery(MgroupQuery) '将传到载体中的数据传达给控件,显示在控件中 dtGroupQuery.DataSource = endResult End Sub Private Sub frmGroupQuery_Load(sender As Object, e As EventArgs) Handles MyBase.Load '操作符内容的加载 cbxOperate1.Items.Add(">") cbxOperate1.Items.Add("<") cbxOperate1.Items.Add("=") cbxOperate2.Items.Add(">") cbxOperate2.Items.Add("<") cbxOperate2.Items.Add("=") cbxOperate3.Items.Add(">") cbxOperate3.Items.Add("<") cbxOperate3.Items.Add("=") '组合关系 cbxRelation1.Items.Add("与") cbxRelation1.Items.Add("或") cbxRelation2.Items.Add("或") cbxRelation2.Items.Add("与") '控件的可用性:窗体加载时,第二行、第三行以及第二个组合关系都不能用 cbxOperate2.Enabled = False cbxOperate3.Enabled = False txtQuery2.Enabled = False txtQuery3.Enabled = False cbxString2.Enabled = False cbxString3.Enabled = False cbxRelation2.Enabled = False End Sub '声明一个函数用来将控件中的文字转换为数据库中需要的英文字段名 Protected Overridable Function GetEnglish(cbxString As String) As String Return "" End Function Public Overridable Function GetTable() As String Return "" End Function Private Sub cbxRelation1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbxRelation1.SelectedIndexChanged '只有当第一个关系选择不为空才能使第二行的控件enabled cbxRelation2.Enabled = True cbxOperate2.Enabled = True cbxString2.Enabled = True txtQuery2.Enabled = True End Sub Private Sub cbxRelation2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbxRelation2.SelectedIndexChanged cbxOperate3.Enabled = True cbxString3.Enabled = True txtQuery3.Enabled = True End Sub Private Sub btnOutPut_Click(sender As Object, e As EventArgs) Handles btnOutPut.Click End Sub End Class
父类窗体设计好后,开始设计子窗体,让三个“子”从“父”那里继承自己该有的东西;
点击“添加”后会出现下面的窗口:
这样,子类窗体对父类的继承就完成了,相比较而言,子类窗体的各个控件都加上了一把锁,也就是不能修改,能修改的只是对父类中方法和加载的东西进行重写,说白了就是一种个性化的设置,比如学生个人信息维护:
像这张图中显示的,父类窗体都只是给定一个基本框架,然后该窗体对它进行个性化:combox加载出自己需要显示的,GetEnglish函数转换自己对应的数据库:T_StuInfo中的字段名,GetTable调取T_StuInfo中的数据。
然而需要重写的只是U层的代码,其他层都和父类窗体使用一样的代码,也就是包括父类窗体在内的四个窗体都调取同一个B、D、IDAL、Factory。这里主要是B层和D层的代码:
B层:
Public Class GroupQueryBLL Public Function GroupQuery(ByVal groups As Model.GroupQueryModel) As DataTable Dim IGroupQuery As IDAL.IGroupQuery Dim factory As New Factory.LoginFacy IGroupQuery = factory.CreateGroupQuery Dim table As New DataTable table = IGroupQuery.GroupQuery(groups) If Not IsNothing(table) Then Return table Else MsgBox("没有查到相关数据") Return Nothing End If End Function End Class
D层:
Imports IDAL Imports System.Data Imports System.Data.SqlClient Public Class GroupQueryDAL : Implements IDAL.IGroupQuery Public Function GroupQuery(groups As Model.GroupQueryModel) As DataTable Implements IGroupQuery.GroupQuery Dim cmdText As String = "PROC_GroupQuery" Dim sqlparams As SqlParameter() = {New SqlParameter("@cbxString1", groups.cbxString1), New SqlParameter("@cbxString2", groups.cbxString2), New SqlParameter("@cbxString3", groups.cbxString3), New SqlParameter("@cbxOperate1", groups.cbxOperate1), New SqlParameter("@cbxOperate2", groups.cbxOperate2), New SqlParameter("@cbxOperate3", groups.cbxOperate3), New SqlParameter("@txtQuery1", groups.txtQuery1), New SqlParameter("@txtQuery2", groups.txtQuery2), New SqlParameter("@txtQuery3", groups.txtQuery3), New SqlParameter("@gettable", groups.gettable), New SqlParameter("@cbxRelation1", groups.cbxRelation1), New SqlParameter("@cbxRelation2", groups.cbxRelation2)} Dim helper As New SqlHelper Dim table As New DataTable table = helper.ExecSelect(cmdText, CommandType.StoredProcedure, sqlparams) If table.Rows.Count <> 0 Then Return table Else Return Nothing End If End Function End Class
值得注意的是:由于这层用到的存储过程所以sqlparams中不再是cmdType,而是commandType.StoreProcedures 。
提到存储过程,存储过程就是对一堆sql语句的封装和集结,为了省去过多的sql语句,所以使用存储过程,下面就是存储过程的语句:
现在组合查询的大部分都在这里了,虽然组合查询的功能实现了,但是有一个地方我一直不明白,在父类的U层中有这么几行代码:
这段代码是将控件中的值进行存储传递的过程,框中的是组合关系,按理说这里是应该有GetEnglish函数,毕竟组合关系控件中的文本也是汉语,但是有几个同学的都没有这个函数却都能行通,而我的如果没有这个函数那就出现下面的结果:
难道是VS2012和2013的区别???有待探究。。。。
也许这里的代码不是多精简,但凡事一步一个脚印,努力去做,做得多了也就知道哪些可以合并封装了,如果有什么不对的地方欢迎大家指正。