历经n多天,组合查询模板终于做完了,总结一下这几天的成果,和大家一起学习交流。
先看一下父窗体的关键代码:
父窗体代码:
Public Class frmComboQuery Protected Overridable Sub frmComboQuery_Load(sender As Object, e As EventArgs) Handles MyBase.Load Dim ComboxArray(4) As ComboBox '定义控件数组,获取组合框 ComboxArray(0) = cboOperator1 ComboxArray(1) = cboOperator2 ComboxArray(2) = cboOperator3 ComboxArray(3) = cboRelation1 ComboxArray(4) = cboRelation2 CommonMethod.SelectIndex(ComboxArray) '设置combox默认显示第一项 Dim ControlArray(6) As Control '定义控件数组,获取组合2和组合3的控件 ControlArray(0) = cboField2 ControlArray(1) = cboOperator2 ControlArray(2) = txtContent2 ControlArray(3) = cboRelation2 ControlArray(4) = cboField3 ControlArray(5) = cboOperator3 ControlArray(6) = txtContent3 CommonMethod.LockControlArray(ControlArray) '调用共有方法,锁定控件 End Sub Private Sub btnQuery_Click(sender As Object, e As EventArgs) Handles btnQuery.Click Try Dim ControlArray(2) As Control '定义控件数组,获取组合1的控件 ControlArray(0) = cboField1 ControlArray(1) = cboOperator1 ControlArray(2) = txtContent1 If CommonMethod.IsEmptyControlArray(ControlArray) = False Then '判断组合1的控件是否为空 Exit Sub End If If cboRelation1.Text.Trim <> "<请选择>" Then '组合关系1不为空时 ControlArray(0) = cboField2 '获取组合2的控件 ControlArray(1) = cboOperator2 ControlArray(2) = txtContent2 If CommonMethod.IsEmptyControlArray(ControlArray) = False Then '判断组合2的条件是否为空 Exit Sub End If If cboRelation2.Text.Trim <> "<请选择>" Then '组合关系2不为空时 ControlArray(0) = cboField3 '获取组合3的控件 ControlArray(1) = cboOperator3 ControlArray(2) = txtContent3 If CommonMethod.IsEmptyControlArray(ControlArray) = False Then '判断组合3的条件是否为空 Exit Sub End If End If End If Dim eComboQuery1 As New Entity.ComboQueryEntity '定义组合查询实体,将条件传入实体 eComboQuery1.dbName = GetdbName() eComboQuery1.Field1 = cboField1.Text.Trim eComboQuery1.Field2 = cboField2.Text.Trim eComboQuery1.Field3 = cboField3.Text.Trim eComboQuery1.Operator1 = cboOperator1.Text.Trim eComboQuery1.Operator2 = cboOperator2.Text.Trim eComboQuery1.Operator3 = cboOperator3.Text.Trim eComboQuery1.Content1 = txtContent1.Text.Trim eComboQuery1.Content2 = txtContent2.Text.Trim eComboQuery1.Content3 = txtContent3.Text.Trim eComboQuery1.Relation1 = cboRelation1.Text.Trim eComboQuery1.Relation2 = cboRelation2.Text.Trim Dim dtComboQuery As New DataTable Dim mgr As New BLL.ComboQueryBLL dtComboQuery = mgr.ComboQuery(eComboQuery1) dgvRecord.DataSource = dtComboQuery Catch ex As Exception MessageBox.Show(ex.Message.ToString()) dgvRecord.DataSource = Nothing End Try End Sub Protected Overridable Function GetdbName() As String Return "" End Function Private Sub cboRelation1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboRelation1.SelectedIndexChanged Dim ControlArray(3) As Control '定义控件数组,获取组合2的控件和组合关系2的控件, ControlArray(0) = cboField2 ControlArray(1) = cboOperator2 ControlArray(2) = txtContent2 ControlArray(3) = cboRelation2 If cboRelation1.SelectedIndex = 0 Then '如果组合关系1为空,清空组合2和组合关系2 CommonMethod.ClearControlArray(ControlArray) CommonMethod.LockControlArray(ControlArray) Else CommonMethod.UnLockControlArray(ControlArray) '否则,解锁组合2和组合关系2 End If End Sub Private Sub cboRelation2_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboRelation2.SelectedIndexChanged Dim ControlArray(2) As Control '定义控件数组,获取组合3的控件 ControlArray(0) = cboField3 ControlArray(1) = cboOperator3 ControlArray(2) = txtContent3 If cboRelation2.SelectedIndex = 0 Then '如果组合关系2为空,清空组合2,锁定组合3 CommonMethod.ClearControlArray(ControlArray) CommonMethod.LockControlArray(ControlArray) Else CommonMethod.UnLockControlArray(ControlArray) '否则,解锁组合3 End If End Sub End Class
文中调用的公共方法上篇博客已写,这里不再重复。
现在以查询操作员工作记录为例:
Public Class frmWorkLog Protected Overrides Sub frmComboQuery_Load(sender As Object, e As EventArgs) MyBase.frmComboQuery_Load(sender, e) Dim ComboxArray(2) As ComboBox '定义控件数组,获取组合框 ComboxArray(0) = cboField1 ComboxArray(1) = cboField2 ComboxArray(2) = cboField3 CommonMethod.SelectIndex(ComboxArray) '设置combox默认显示第一项 End Sub Protected Overrides Function GetdbName() As String Return "WorkLog" End Function End Class
说明:1.设置默认第一项在父窗体添加了一部分,这里是字段的那部分,因为字段是在子窗体添加,所以如果这段代码也放父窗体会报错。2.这里通过传递一个字符串来通知D层确定哪一个数据表,这里是我感觉不好的地方,但是暂时没有想到其他方法,只能先这么写。
B层代码:
Public Class ComboQueryBLL Dim factory As New Factory.DataAccess Public Function ComboQuery(ByVal cboworklog As Entity.ComboQueryEntity) As DataTable Dim iComboQuery As IDAL.IComboQuery iComboQuery = factory.CreateComboQuery Dim dtComboQuery As New DataTable dtComboQuery = iComboQuery.ComboQuery(cboworklog) If dtComboQuery.Rows.Count = 0 Then Throw New Exception("没有记录") Else Return dtComboQuery End If End Function End Class
D层代码:
Imports System.Data.SqlClient Public Class SqlServerComboQueryDAL : Implements IDAL.IComboQuery Dim sqlhelper As New SqlHelper Public Function ComboQuery1(cboworklog As Entity.ComboQueryEntity) As DataTable Implements IDAL.IComboQuery.ComboQuery Dim ecboworklog As New Entity.ComboQueryEntity Select Case cboworklog.dbName Case "WorkLog" ecboworklog = Method.SwitchWorklogField(cboworklog) '调用方法,转换字段,以匹配数据库 Case "StudentAccount" ecboworklog = Method.SwitchStudentAccount(cboworklog) End Select Dim sqlParameter As SqlParameter() sqlParameter = New SqlParameter() { New SqlParameter("@dbName", ecboworklog.dbName), New SqlParameter("@Field1", ecboworklog.Field1), New SqlParameter("@Field2", ecboworklog.Field2), New SqlParameter("@Field3", ecboworklog.Field3), New SqlParameter("@Operator1", ecboworklog.Operator1), New SqlParameter("@Operator2", ecboworklog.Operator2), New SqlParameter("@Operator3", ecboworklog.Operator3), New SqlParameter("@Content1", ecboworklog.Content1), New SqlParameter("@Content2", ecboworklog.Content2), New SqlParameter("@Content3", ecboworklog.Content3), New SqlParameter("@Relation1", ecboworklog.Relation1), New SqlParameter("@Relation2", ecboworklog.Relation2)} Dim dtComboQuery As New DataTable dtComboQuery = sqlhelper.Query("sp_ComboQuery", CommandType.StoredProcedure, sqlParameter) Return dtComboQuery End Function End Class
D层转换字段的方法:
Function SwitchWorklogField(ByVal eworklog As Entity.ComboQueryEntity) Dim strField(2) As String '字符串数组,临时存放字段值 Dim Field(2) As String Field(0) = eworklog.Field1 Field(1) = eworklog.Field2 Field(2) = eworklog.Field3 For i = 0 To 2 '通过一个循环对字段进行匹配 Select Case Field(i) Case "职工ID" strField(i) = "UserID" Case "登陆日期" strField(i) = "LoginDate" Case "登陆时间" strField(i) = "LoginTime" Case "注销日期" strField(i) = "LogOffDate" Case "注销时间" strField(i) = "LogOffTime" Case "电脑名" strField(i) = "ComputerName" Case Else strField(i) = "" End Select Field(i) = strField(i) Next eworklog.Field1 = Field(0) '将字段值进行匹配,并赋值给组合查询实体 eworklog.Field2 = Field(1) eworklog.Field3 = Field(2) Dim strRelation(1) As String '定义字符串数组,临时存在关系值 Dim Relation(1) As String Relation(0) = eworklog.Relation1 Relation(1) = eworklog.Relation2 For i = 0 To 1 '循环匹配字段 Select Case Relation(i) Case "或" strRelation(i) = "OR" Case "且" strRelation(i) = "AND" Case Else strRelation(i) = "" End Select Relation(i) = strRelation(i) Next eworklog.Relation1 = Relation(0) '组合查询实体赋值 eworklog.Relation2 = Relation(1) eworklog.dbName = "T_WorkLog" Return eworklog '返回实体 End Function
存储过程代码:
USE [ChargeSystem] GO /****** Object: StoredProcedure [dbo].[sp_ComboQuery] Script Date: 2014/6/22 16:40:59 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: 刘晓春 -- Create date: 2014年6月17日 -- Description: 组合查询 -- ============================================= CREATE PROCEDURE [dbo].[sp_ComboQuery] @dbName varchar(20), @field1 varchar(20),@operator1 varchar(20),@content1 varchar(20), @relation1 varchar(10), @field2 varchar(20),@operator2 varchar(20),@content2 varchar(20), @relation2 varchar(20), @field3 varchar(20),@operator3 varchar(20),@content3 varchar(20) AS BEGIN DECLARE @sqlText varchar(200) SET @sqlText='SELECT * FROM '+@dbName+' WHERE ' +@field1 +@operator1+char(39) + @content1 + char(39) if @relation1<>'' BEGIN SET @sqlText=@sqlText+@relation1+CHAR(32)+@field2+@operator2+CHAR(39)+@content2+CHAR(39) if @relation2<>'' BEGIN SET @sqlText=@sqlText+@relation2+CHAR(32)+@field3+@operator3+CHAR(39)+@content3+CHAR(39) END END EXECUTE(@sqlText) END
效果如下:
题外话:
因为系统多次用到组合查询,而且各个窗体非常类似,所以最初只是想到用窗体的继承,免得做重复的窗体。后来父窗体做好之后,发现那些判断是否为空、清空等代码可以写到父窗体,然后子窗体写关于查询的代码。
紧接着就出现了一个问题,使用窗体继承,对于同一个事件而言,程序会先执行父窗体中的代码,后执行子窗体中的代码。在我的程序里,当执行按钮的click事件时,父窗体会先判断组合框是否为空,如果判断出为空,给出了提示,当点完确定后,程序并没有像想象中那样停下来让你选择组合框,而是接着执行子窗体的查询。
后来只好请教师父和师哥,得到一个解决办法,就是声明一个全局变量,由它通知子窗体是否执行,同时师哥指出,其实子窗体的代码也可以放在父窗体中,我自己也觉得声明全局变量感觉不好,所以就演化到现在的样子了,后来才知道,不知不觉还用了一个设计模式,模板方法模式。
不过这个模式依然需要子窗体去传递一个参数,让D层去判断是用的哪一个数据库,感觉不好,但是也没有想出好的办法,如果大家有什么好的建议,望不吝奉献。