欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

通用查询类封装之Mongodb篇

程序员文章站 2022-04-28 13:02:46
查询在应用程序中很重要,花样也特别多,不同得业务需求需要不同的查询条件,还要支持and、or ……事实上也确实如此,程序中有N多个查询类,并且很可能其中有多个类查询同一张表,所以特别想弄一个通用的查询类。 前几天也是因为讨论有关查询的问题,想到了一个点子觉得可行,最近就抓紧实现了一下来验证想法的可行 ......

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

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

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

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

通用查询类封装之Mongodb篇
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、至此,圆括号已不再,只是简单的表达式,这就简单了

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