Winform開發框架之通用高級查詢模塊

最近一直忙於公司的事情,雖然一直在作一些相關的技術研究,可是好久沒能靜下心來好好寫寫博客文章了,想一想也有半個月之多了,這半個月來,也一直致力於改善個人WInform開發框架,使得本身及客戶使用起來更加方便,更加友好,更加高效。本篇文章就是介紹最近框架改善的其中一個閃光點"通用高級查詢模塊",高級查詢模塊,在不少程序模塊中都很常見,也是給客戶擴展查詢的一個很好的補充,因爲我一直但願個人Winform開發框架可以精益求精,因此作了這個模塊,但願對從此我本身全部的項目以及框架自己,都能高效的使用。sql

一、通用高級查詢模塊的用途及介紹

既然稱之爲通用查詢模塊,那麼他就不能與具體的表字段有耦合關係,可是要實現具體的查詢,必須經過某種方式進行屬性傳遞,實現更直觀友好的字段查詢功能。高級查詢模塊,在不少完善的程序上都會提供,用於知足用戶對特定的字段,添加特定的條件進行,由於通常狀況下,因爲版面的限制界面上查詢的內容比較有限,只是把一些很常見、重要的字段做爲查詢輸入,若是表字段比較多,那麼對有些特殊的字段就無所適從。數據庫

例如,我一個病人資料管理系統的界面以下所示框架

這個界面已經放置的比較多輸入控件進行查詢了,若是放置更多,超過3行就會致使感受比較臃腫了。因此合理的應該是把不經常使用的放到高級查詢裏面,這樣用戶須要更多條件的定製,能夠在高級查詢中對每一個字段都能進行搜索,常規的在主界面便可查詢。ide

個人高級查詢查詢模塊也是基於這個道理,所以,在主界面增長一個高級查詢按鈕入口,如上圖所示,單擊後,顯示一個全部字段的列表,以下界面。函數

這樣全部表的字段都可進行查詢了,可是咱們注意到,這個界面並無輸入條件的地方,沒錯,這個只是顯示條件內容,浮在主界面的查詢列表上面,若是設置條件後,主界面的列表會根據高級查詢條件進行查詢,這樣也是符合客戶實際的指望的。ui

在介紹輸入條件的時候,咱們注意到,查詢輸入,基本上能夠分爲幾類:其一是常規的文本類型,使用文本框替代便可;其二是下拉列表類型,用戶從列表下面選擇內容;其三是日期類型,須要用戶指定開始日期和結束日期;其四是數字類型,須要用戶指定起始和結束的數值。this

剛纔說到,上面的高級查詢界面,只是顯示,但用戶雙擊列表或者按下回車鍵,那麼根據字段類型,彈出對應上面說到的四種輸入框,用於接收用戶的輸入。spa

1)常規的文本類型條件輸入界面:3d

下拉列表類型條件輸入界面:code

日期類型條件輸入界面:

數字類型條件輸入界面:

輸入以上幾種條件後,高級查詢界面裏面會顯示友好的條件內容,確保用戶可以看懂輸入的條件,以下所示是輸入幾個不一樣類型的條件的顯示內容。

日期類型和數字類型,爲了方便,均可以單獨輸入其中的一部分做爲條件進行高級查詢。

爲了方便,高級查詢模塊的內容,能夠進行查詢後在主界面列表中顯示,也可使用傳統的查詢按鈕進行查詢,使用傳統查詢按鈕後,高級查詢條件將失效,可是保留用戶的輸入,第二次打開界面後,會加載以前的輸入條件,這樣比較人性化一些,用戶能夠隨時自由切換兩種查詢方式。

對於一些字段多的歷史資料表,這種高級查詢模式更加可以發揮其做用,用戶能夠在幾十個甚至上百個字段中選擇合適的條件,而後輸入進行查詢,這樣可以使得客戶更加有認同感,例以下面是一個病人歷史檔案資料表的高級查詢界面,裏面不少字段,使用這個擴展查詢就是最合適不過了。

二、通用高級查詢模塊的實現思路

1)獲取數據庫字段名稱和類型列表

首先前面說到,我是根據字段類型進行不一樣的控件顯示並輸入的,所以須要一個通用的函數獲取字段的名稱和類型,做爲參考,因爲這個功能比較通用,所以把它放在個人Winform開發框架的數據庫基類的抽象類裏面,全部的數據庫訪問類均繼承不用重複寫代碼。

        /// <summary>
        /// 獲取表的字段名稱和數據類型列表。
        /// </summary>
        /// <returns></returns>
        public DataTable GetFieldTypeList()
        {
            DataTable dt = DataTableHelper.CreateTable("ColumnName,DataType");
            DataTable schemaTable = GetReaderSchema(tableName);
            if (schemaTable != null)
            {
                foreach (DataRow dr in schemaTable.Rows)
                {
                    string columnName = dr["ColumnName"].ToString().ToUpper();
                    string netType = dr["DataType"].ToString().ToLower();

                    DataRow row = dt.NewRow();
                    row["ColumnName"] = columnName;
                    row["DataType"] = netType;

                    dt.Rows.Add(row);
                }
            }
            return dt;
        }

        /// <summary>
        /// 獲取指定表的元數據,包括字段名稱、類型等等
        /// </summary>
        /// <param name="tableName">數據庫表名</param>
        /// <returns></returns>
        private DataTable GetReaderSchema(string tableName)
        {
            DataTable schemaTable = null;

            string sql = string.Format("Select * FROM {0}", tableName);
            Database db = CreateDatabase();
            DbCommand command = db.GetSqlStringCommand(sql);
            try
            {
                using (IDataReader reader = db.ExecuteReader(command))
                {
                    schemaTable = reader.GetSchemaTable();
                }
            }
            catch (Exception ex)
            {
                LogTextHelper.Error(ex);
            }

            return schemaTable;
        }

2)設置高級查詢的字段顯示(有時候可能須要過濾部分字段)

3)指定下拉列表的數據內容

剛纔說到,有一些下拉列表字段的輸入,那麼下拉列表也就須要指定裏面的列表內容了,高級查詢模塊,指定下拉列表的代碼以下所示。

         dlg.AddColumnListItem("MidVideo", GetFieldListItem("MidVideo"));
                dlg.AddColumnListItem("InDiagnosis", GetFieldListItem("InDiagnosis"));
                dlg.AddColumnListItem("DirectorSurgeon", GetFieldListItem("DirectorSurgeon"));
                dlg.AddColumnListItem("TumorPart", GetFieldListItem("TumorPart"));
                dlg.AddColumnListItem("LeaveDiagnosis", GetFieldListItem("LeaveDiagnosis"));
                dlg.AddColumnListItem("IsFirstTime", GetFieldListItem("IsFirstTime"));
                dlg.AddColumnListItem("Professor", GetFieldListItem("Professor"));

對於一些固定的列表項目,咱們也能夠經過下面代碼進行綁定。

                dlg.AddColumnListItem("Sex", new List<CListItem>() { new CListItem(""), new CListItem("") });
                dlg.AddColumnListItem("HasReferral", new List<CListItem>() { new CListItem(""), new CListItem("") });

4)和普通查詢功能並存

爲了使得傳統查詢按鈕,和高級查詢可以並存,咱們須要存儲一個高級查詢的查詢對象,但傳統查詢的時候,咱們把高級查詢對象設置爲空便可屏蔽高級查詢的條件了。

        /// <summary>
        /// 高級查詢條件語句對象
        /// </summary>
        private SearchCondition advanceCondition;

        /// <summary>
        /// 根據查詢條件構造查詢語句
        /// </summary> 
        private string GetConditionSql()
        {
            //若是存在高級查詢對象信息,則使用高級查詢條件,不然使用主表條件查詢
            SearchCondition condition = advanceCondition;
            if (condition == null)
            {
                condition = new SearchCondition();
                condition.AddCondition("BedNo", this.txtBedNo.Text.Trim(), SqlOperator.Like);
                condition.AddCondition("TumorPart", this.txtTumorPart.Text.Trim(), SqlOperator.Like);
                condition.AddCondition("MidVideo", this.txtMidVideo.Text.Trim(), SqlOperator.Like);
                condition.AddCondition("Name", this.txtName.Text.Trim(), SqlOperator.Like);
                condition.AddCondition("HospitalNo", this.txtHospitalNo.Text.Trim(), SqlOperator.Like);
                condition.AddCondition("IDNumber", this.txtIDNumber.Text.Trim(), SqlOperator.Like);
                condition.AddCondition("InDiagnosis", this.txtInDiagnosis.Text.Trim(), SqlOperator.Like);
                condition.AddCondition("LeaveDiagnosis", this.txtLeaveDiagnosis.Text.Trim(), SqlOperator.Like);
                condition.AddCondition("LeaveSpecimens", this.txtLeaveSpecimens.Text.Trim(), SqlOperator.Like);
                condition.AddCondition("Professor", this.txtProfessor.Text.Trim(), SqlOperator.Like);
                condition.AddCondition("Note", this.txtNote.Text.Trim(), SqlOperator.Like);
                condition.AddCondition("Pathology", this.txtPathology.Text.Trim(), SqlOperator.Like);
                condition.AddCondition("IsFirstTime", this.txtIsFirstTime.Text.Trim(), SqlOperator.Like);
..................              

            }

            string where = condition.BuildConditionSql().Replace("Where", "");

            return where;
        }
        /// <summary>
        /// 查詢數據操做
        /// </summary>
        private void btnSearch_Click(object sender, EventArgs e)
        {
            advanceCondition = null;//必須重置查詢條件,不然可能會使用高級查詢條件了
            BindData();
        }

5)根據類型轉換不一樣的窗體

爲了輸入方便,我定義了幾個不一樣輸入內容的窗體,而後根據不一樣的字段類型,構造不一樣的窗體並進行顯示,這樣比較合理顯示並接收客戶的條件輸入。

        private void gridControl1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            int[] rowSelected = this.gridView1.GetSelectedRows();
            if (rowSelected.Length == 0) return;

            string fieldName = this.gridView1.GetFocusedRowCellValue("字段").ToString();
            string fieldDisplay = this.gridView1.GetFocusedRowCellValue("字段名稱").ToString();
            FieldType fieldType = (FieldType)this.gridView1.GetFocusedRowCellValue("字段類型");
            string fieldValue = this.gridView1.GetFocusedRowCellValue("查詢條件值").ToString();
            #region 根據類型轉換不一樣的窗體
            FrmQueryBase dlg = null;
            if (fieldType == FieldType.Text)
            {
                dlg = new FrmQueryTextEdit();
            }
            else if (fieldType == FieldType.Numeric)
            {
                dlg = new FrmQueryNumericEdit();
            }
            else if (fieldType == FieldType.DateTime)
            {
                dlg = new FrmQueryDateEdit();
            }
            else if (fieldType == FieldType.DropdownList)
            {
                dlg = new FrmQueryDropdown();
            }
            #endregion

6)主窗體的事件響應

因爲彈出的高級查詢窗體,裏面的查詢以及清除操做,都是經過主窗體的事件進行處理,所以,彈出的高級查詢窗體,只須要調用相應的事件便可。

            dlg.DataClear += new FrmQueryBase.DataClearEventHandler(dlg_DataClear);
            if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                //更新查詢界面顯示
                UpdateFieldValue(fieldName, dlg.ReturnValue, dlg.ReturnDisplay);

                //更新父窗體的數據顯示
                ProcessDataSearch(null, null);
            }

這樣咱們就能把傳統查詢功能和高級查詢功能合併一塊兒,發揮最大的做用,是咱們的程序可以儘可能知足客戶的需求,得到更加好的反饋和支持了。

相關文章
相關標籤/搜索