WinForm动态查询

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参数标识符 @.
原文地址:https://www.cnblogs.com/aning2015/p/8087006.html