• 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参数标识符 @.
  • 相关阅读:
    解决electron-vue中无法使用Element的Tooltip组件
    解决Electron安装包下载慢的问题
    虚拟机VirtualBox 共享挂载问题:mount: /mnt/xxx: wrong fs type, bad option, bad superblock on xxx
    git 设置和取消代理
    (转载)数据库连接池到底应该设多大?这篇文章可能会颠覆你的认知
    MySQL主主复制+MMM实现高可用
    Mysql5.6主从热备配置
    java 启动 shell脚本
    redis批量删除key
    spring mvc异常统一处理(ControllerAdvice注解)
  • 原文地址:https://www.cnblogs.com/aning2015/p/8087006.html
Copyright © 2020-2023  润新知