• 通用查询类封装之Mongodb篇


      查询在应用程序中很重要,花样也特别多,不同得业务需求需要不同的查询条件,还要支持and、or ……事实上也确实如此,程序中有N多个查询类,并且很可能其中有多个类查询同一张表,所以特别想弄一个通用的查询类。

      前几天也是因为讨论有关查询的问题,想到了一个点子觉得可行,最近就抓紧实现了一下来验证想法的可行性……

      思路:其实查询类很简单,无非就是你要查询哪个字段—字段名称(Key)、你想搜索的值—字段值(Value)、以及如何进行比较—查询类型(QueryType),这是单个查询条件(之后都叫做查询因子,不知道合适不合适,也是突然间想起来的),如果是多个条件,弄了一个集合就是好了,问题就在于这些查询因子之间的关系(and、or)……既然叫做查询因子,这个集合我们不管他们之间的关系,只是简单的查询因子的集合,我们在弄一个字段来存储他们之间的关系,这里暂时叫做逻辑表达式,例如:((a|b)&c)|((a&b&d)|e),最后我就解析这个表达式就可以了,a、b、c、d、e只要在集合中找到具体的哪个查询因子就可以了,就是这样了。说通用查询类有点惭愧,目前只是在Mongodb下弄了一个简单的实现(重点是思路了,嘿嘿),因为项目上用的是Mongodb所以先实现的肯定是他了,其他的数据库同理……

    /// <summary>
    /// 通用查询类
    /// </summary>
    public class QueryModel
    {
        /// <summary>
        /// 逻辑表达式
        /// </summary>
        public string FilterStr { get; set; }
    
        /// <summary>
        /// 查询因子字典集合
        /// </summary>
        public Dictionary<string, QueryFactor> DCQueryFactor { get; set; }
    }
    /// <summary>
    /// 查询因子类
    /// </summary>
    public class QueryFactor
    {
        /// <summary>
        /// 查询字段的名称
        /// </summary>
        public string Key { get; set; }
    
        /// <summary>
        /// 查询字段的值
        /// </summary>
        public object Value { get; set; }
    
        /// <summary>
        /// 比较类型,支持的类型有:
        /// eq:等于,
        /// ne:不等于
        /// gt:大于
        /// lt:小于
        /// gte:大于等于
        /// lte:小于等于
        /// in:范围查询
        /// like:模糊查询
        /// </summary>
        public string QueryType { get; set; } = "eq";
    }
    查询类

      这个倒是没有什么,关键是这个所谓的逻辑表达式不知道如何解析,真是废了半天劲儿……什么类似的堆栈实现计算器、逆波兰式等弄了一大堆,感觉都没有用上,最后对一个例子做了一些改进,才完成的……

    public class QueryModelForMongodb
    {
        private Dictionary<string, FilterDefinition<BsonDocument>> ParenthesesExpressionDic = new Dictionary<string, FilterDefinition<BsonDocument>>();
    
        /// <summary>
        /// 入口方法
        /// </summary>
        /// <param name="logicalExpression">逻辑表达式</param>
        /// <param name="queryModel">查询类</param>
        /// <returns></returns>
        public FilterDefinition<BsonDocument> ToMongodbFilter(string logicalExpression, QueryModel queryModel)
        {
            int startIndex = logicalExpression.LastIndexOf("(");
            if (startIndex != -1)
            {
                //  截取括号中的表达式
                int endIndex = logicalExpression.IndexOf(")", startIndex);
                int len = endIndex - startIndex - 1;
                string simpleExpress = logicalExpression.Substring(startIndex + 1, len);
                //  处理简单的表达式并结果保存到字典中
                string tempGuid = Guid.NewGuid().ToString();
                FilterDefinition<BsonDocument> fd1 = ToMongodbFilterSimpleLogicalExpression(simpleExpress, queryModel);
                ParenthesesExpressionDic.Add(tempGuid, fd1);
                //  继续处理剩余表达式
                string leftStr = logicalExpression.Substring(0, startIndex);
                string rightStr = logicalExpression.Substring(endIndex + 1);
                return ToMongodbFilter($"{leftStr}{tempGuid}{rightStr}", queryModel);
            }
            return ToMongodbFilterSimpleLogicalExpression(logicalExpression, queryModel);
        }
    
        /// <summary>
        /// 处理简单的逻辑表达式(不包含圆括号)
        /// </summary>
        /// <param name="logicalExpression"></param>
        /// <param name="queryModel"></param>
        /// <returns></returns>
        private FilterDefinition<BsonDocument> ToMongodbFilterSimpleLogicalExpression(string logicalExpression, QueryModel queryModel)
        {
            //  1、筛选出操作符:&、|
            Queue<char> qOperator = new Queue<char>();
            //Regex regexOperator = new Regex("[&|]");
            //foreach (Match item in regexOperator.Matches(logicalExpression))
            //{
            //    qOperator.Enqueue(item.Value);
            //}
            foreach (char c in logicalExpression)
            {
                if (c == '&' || c == '|')
                {
                    qOperator.Enqueue(c);
                }
            }
            //  2、筛选出所有的变量
            Queue<string> qVariable = new Queue<string>();
            string[] tempVariables = logicalExpression.Replace("&", ",").Replace("|", ",").Split(",");
            foreach (string v in tempVariables)
            {
                qVariable.Enqueue(v);
            }
            //  3、返回结果组装
            FilterDefinition<BsonDocument> filter = null;
            if (qVariable.Count >= 1)
            {
                string tempV = qVariable.Dequeue();
                filter = ParenthesesExpressionDic.ContainsKey(tempV) ? ParenthesesExpressionDic[tempV] : QueryFactorToMogodbFilter(queryModel.DCQueryFactor[tempV]);
                while (qVariable.Count > 0)
                {
                    string rightV = qVariable.Dequeue();
                    var tempFilter = ParenthesesExpressionDic.ContainsKey(rightV) ? ParenthesesExpressionDic[rightV] : QueryFactorToMogodbFilter(queryModel.DCQueryFactor[rightV]);
                    char tempOperator = qOperator.Dequeue();
                    switch (tempOperator)
                    {
                        case '&':
                            {
                                filter = filter & tempFilter;
                                break;
                            }
                        case '|':
                            {
                                filter = filter | tempFilter;
                                break;
                            }
                    }
                }
                filter = Builders<BsonDocument>.Filter.Empty & (filter);
            }
            return filter ?? Builders<BsonDocument>.Filter.Empty;
        }
    
        /// <summary>
        /// 将查询因子转换成Mongodb的Filter
        /// </summary>
        /// <param name="queryFactor"></param>
        /// <returns></returns>
        private FilterDefinition<BsonDocument> QueryFactorToMogodbFilter(QueryFactor queryFactor)
        {
            /// <summary>
            /// 比较类型,支持的类型有:
            /// eq:等于,
            /// ne:不等于
            /// gt:大于
            /// lt:小于
            /// gte:大于等于
            /// lte:小于等于
            /// in:范围查询
            /// like:模糊查询
            /// </summary>
            if (queryFactor == null) return Builders<BsonDocument>.Filter.Empty;
            FilterDefinition<BsonDocument> filter = null;
            switch (queryFactor.QueryType.ToLower())
            {
                case "ne":
                    {
                        filter = Builders<BsonDocument>.Filter.Ne(queryFactor.Key, queryFactor.Value);
                        break;
                    }
                case "gt":
                    {
                        filter = Builders<BsonDocument>.Filter.Gt(queryFactor.Key, queryFactor.Value);
                        break;
                    }
                case "gte":
                    {
                        filter = Builders<BsonDocument>.Filter.Gte(queryFactor.Key, queryFactor.Value);
                        break;
                    }
                case "lt":
                    {
                        filter = Builders<BsonDocument>.Filter.Lt(queryFactor.Key, queryFactor.Value);
                        break;
                    }
                case "lte":
                    {
                        filter = Builders<BsonDocument>.Filter.Lte(queryFactor.Key, queryFactor.Value);
                        break;
                    }
                case "in":
                    {
                        filter = Builders<BsonDocument>.Filter.In(queryFactor.Key, JsonConvert.DeserializeObject<IList<String>>(JsonConvert.SerializeObject(queryFactor.Value)));
                        break;
                    }
                case "like":
                    {
                        //filter = filter & Builders<BsonDocument>.Filter.Regex(queryFactor.Key, new BsonRegularExpression(new Regex(Regex.Escape(queryFactor.Value.ToString()), RegexOptions.IgnoreCase)));
                        filter = Builders<BsonDocument>.Filter.Regex(queryFactor.Key, new BsonRegularExpression(new Regex(".*" + Regex.Escape(queryFactor.Value.ToString()) + ".*", RegexOptions.IgnoreCase)));
                        break;
                    }
                case "eq":
                default:
                    {
                        filter = Builders<BsonDocument>.Filter.Eq(queryFactor.Key, queryFactor.Value);
                        break;
                    }
            }
            return filter ?? Builders<BsonDocument>.Filter.Empty;
        }
    }
    Mongodb实现

      具体的实现思路是这样的,就是逐个的消除表达式中的括号,直到表达式中不包含圆括号,就用上面的表达式来举个例子,((a|b)&c)|((a&b&d)|e)

      1、找到最后一个“(”,之后寻找与之匹配的“)”,处理这对圆括号中的简单表达式,这里是a&b&d,处理完之后将结果放在一个字典之中<guid,filter>,记作<1,filter1>,之后字符串变为((a|b)&c)|(1|e)

      2、参照1的顺序再次处理表达式((a|b)&c)|(1|e),这次处理1|e,字典中添加一项<2,filter2>,字符串变为((a|b)&c)|2

      3、处理a|b,字典中添加一项<3,filter3>,字符串变为(3&c)|2

      4、处理3&c,字典中添加一项<4,filter4>,字符串变为4|2

      5、至此,圆括号已不再,只是简单的表达式,这就简单了

      结束了,欢迎大家提供更好的办法来处理这个问题,共同努力,哈哈!

  • 相关阅读:
    推荐系统(Recommender System)
    Mac OS X安装OpenGL
    KMeans实现
    Principal Component Analysis(PCA)
    ReactiveX 学习笔记(15)使用 Rx.NET + Json.NET 调用 REST API
    ReactiveX 学习笔记(14)使用 RxJava2 + Retrofit2 调用 REST API
    Haskell语言学习笔记(91)Comprehension Extensions
    Go语言学习笔记(2)
    Go语言学习笔记(1)
    Rust语言学习笔记(6)
  • 原文地址:https://www.cnblogs.com/du-blog/p/10211141.html
Copyright © 2020-2023  润新知