1. 程式人生 > >WinForm動態查詢

WinForm動態查詢

while esp tex 集合 play server emp 操作 num

WinForm 動態查詢

1. 使用場景

在對數據進行篩選, 包含多個篩選字段時適用.

技術分享圖片

2. 接口設計

    /// <summary>
    /// 定義可作為追加到 WHERE 子句的控件接口
    /// </summary>
    internal interface IWhereSentence
    {
        /// <summary>
        /// 當前控件名稱
        /// </summary>
        string Name { get; }

        /// <summary>
        /// 對應數據表中的字段名稱
/// </summary> string FieldName { get; set; } /// <summary> /// 操作符 /// </summary> string Operator { get; set; } /// <summary> /// 是否作為查詢條件 /// </summary> bool AsQuery { get; set; } } /// <summary> /// 定義可追加到 WHERE 子句的控件泛型接口
/// </summary> /// <typeparam name="T">值的類型</typeparam> internal interface IWhereSentence<T> : IWhereSentence { /// <summary> /// 實際值 /// </summary> T Value { get; set; } }

3. 接口實現, 以常見的 DateTimePickerTextox 控件舉例

  • 自定義控件, 繼承框架提供的 DateTimePicker

    類和 IWhereSentence<DateTime> 接口:

    /// <summary>
    /// 可追加到查詢條件的日期選擇器
    /// </summary>
    public partial class QueryDataTimerPicker : DateTimePicker, IWhereSentence<DateTime>
    {
        public QueryDataTimerPicker() : base() { }
    
        /// <summary>
        /// 是否作為查詢條件
        /// </summary>
        [DisplayName("是否作為查詢條件")]
        public bool AsQuery { get; set; }
    
        /// <summary>
        /// 字段名
        /// </summary>
        [DisplayName("字段名稱")]
        public string FieldName { get; set; }
    
        /// <summary>
        /// 操作符
        /// </summary>
        [DisplayName("操作符")]
        public string Operator { get; set; }
    }
  • 自定義控件,繼承框架提供的 TextBox 控件和 IWhereSentence<string> 接口. AsQuery屬性可根據文本框是否有值, 返回是否作為查詢條件, Value 屬性與文本框自身的 Text 屬性綁定

    /// <summary>
    /// 可追加到查詢條件的文本框
    /// </summary>
    public class QueryTextBox : TextBox, IWhereSentence<string>
    {
        private bool _asQuery;
        public QueryTextBox() : base() { }
    
        /// <summary>
        /// 是否作為查詢條件
        /// </summary>
        [DisplayName("是否作為查詢條件")]
        public bool AsQuery
        {
            get { return this._asQuery && !string.IsNullOrWhiteSpace(this.Text); }
            set { this._asQuery = value; }
        }
    
        /// <summary>
        /// 字段名
        /// </summary>
        [DisplayName("字段名稱")]
        public string FieldName { get; set; }
    
        /// <summary>
        /// 操作符
        /// </summary>
        [DisplayName("操作符")]
        public string Operator { get; set; }
    
        /// <summary>
        /// 實際值
        /// </summary>
        public string Value { get { return this.Text; } set { this.Text = value; } }
    }

4. 運用

將自定義控件放置在目標窗體上, 可在屬性窗口設置相關屬性:

技術分享圖片
技術分享圖片

  • 定義查詢控件集合

    private IWhereSentence[] _queryControls;
    this._queryControls = new IWhereSentence[]
    {
        this.queryDataTimerPickerStart,
        this.queryDataTimerPickerEnd,
        this.queryTextBoxTemp
    };
  • 獲取WHERE子句

        /// <summary>
        /// 根據查詢條件生成WHERE字符串, 用於SQL查詢
        /// </summary>
        /// <returns>包含WHERE的SQL字符串</returns>
        private string GetWhereString()
        {
            var builderInst = PooledStringBuilder.GetInstance();
            var builder = builderInst.Builder;
            builder.Append("WHERE ");
    
            using (var enumerator = this._queryControls.Where(p => p.AsQuery).GetEnumerator())
            {
                if (!enumerator.MoveNext())
                {
                    builder.Clear();
                    return builderInst.ToStringAndFree();
                }
                AppendWhere(builder, enumerator.Current);
    
                while (enumerator.MoveNext())
                {
                    builder.Append(" AND ");
                    AppendWhere(builder, enumerator.Current);
                }
            }
            return builderInst.ToStringAndFree();
        }
    
        /// <summary>
        /// 將當前查詢控件追加到WHERE字符串中
        /// </summary>
        /// <param name="builder"><see cref="StringBuilder"/>對象</param>
        /// <param name="item">當前查詢控件</param>
        private void AppendWhere(StringBuilder builder, IWhereSentence item)
        {
            builder.Append(item.FieldName);
            if (_formatRegex.IsMatch(item.Operator))
                builder.Append(" ").AppendFormat(item.Operator, $"‘ + @{item.Name} + ‘");
            else
                builder.Append(" ").Append(item.Operator).Append(" ").Append("@").Append(item.Name);
        }
    
        /// <summary>
        /// 獲取查詢參數實際值
        /// </summary>
        /// <returns>查詢參數組成的匿名對象</returns>
        private object GetQueryParam()
        {
            return new
            {
                queryDataTimerPickerStart = this.queryDataTimerPickerStart.Value,
                queryDataTimerPickerEnd = this.queryDataTimerPickerEnd.Value,
                queryTextBoxTemp = this.queryTextBoxTemp.Value
            };
        }
  • 查詢

    var sql = "...";
    sql = sql + GetWhereString();
    var param = GetQueryParam();
    var result = conn.Query(sql, param);    //使用Dapper

5. 問題

  • 當前接口的定義了操作符屬性, 在拼接SQL時, 未實現面對復雜運算符的情況, 目前支持 LIKE(‘{0}‘)運算符.
  • 多個條件之間默認使用 AND 連接, 若要擴展到使用 OR 或者其他運算符, 可在IWhereSentence接口中添加屬性
  • 針對SQL Server數據庫, 若要針對MySQL或Oracle等其他數據庫, 需更改SQL參數標識符 @.

WinForm動態查詢