查询在应用程序中很重要,花样也特别多,不同得业务需求需要不同的查询条件,还要支持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 != -)
{
// 截取括号中的表达式
int endIndex = logicalExpression.IndexOf(")", startIndex);
int len = endIndex - startIndex - ;
string simpleExpress = logicalExpression.Substring(startIndex + , len);
// 处理简单的表达式并结果保存到字典中
string tempGuid = Guid.NewGuid().ToString();
FilterDefinition<BsonDocument> fd1 = ToMongodbFilterSimpleLogicalExpression(simpleExpress, queryModel);
ParenthesesExpressionDic.Add(tempGuid, fd1);
// 继续处理剩余表达式
string leftStr = logicalExpression.Substring(, startIndex);
string rightStr = logicalExpression.Substring(endIndex + );
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 >= )
{
string tempV = qVariable.Dequeue();
filter = ParenthesesExpressionDic.ContainsKey(tempV) ? ParenthesesExpressionDic[tempV] : QueryFactorToMogodbFilter(queryModel.DCQueryFactor[tempV]);
while (qVariable.Count > )
{
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、至此,圆括号已不再,只是简单的表达式,这就简单了

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

通用查询类封装之Mongodb篇的更多相关文章

  1. .Net Core ORM选择之路,哪个才适合你 通用查询类封装之Mongodb篇 Snowflake(雪花算法)的JavaScript实现 【开发记录】如何在B/S项目中使用中国天气的实时天气功能 【开发记录】微信小游戏开发入门——俄罗斯方块

    .Net Core ORM选择之路,哪个才适合你   因为老板的一句话公司项目需要迁移到.Net Core ,但是以前同事用的ORM不支持.Net Core 开发过程也遇到了各种坑,插入条数多了也特别 ...

  2. salesforce 零基础学习(四十八)自定义列表分页之Pagination基类封装 ※※※

    我们知道,salesforce中系统标准列表页面提供了相应的分页功能,如果要使用其分页功能,可以访问http://www.cnblogs.com/zero-zyq/p/5343287.html查看相关 ...

  3. (转载) 百度地图工具类封装(包括定位,附近、城市、范围poi检索,反地理编码)

    目录视图 摘要视图 订阅 赠书 | 异步2周年,技术图书免费选      程序员8月书讯      项目管理+代码托管+文档协作,开发更流畅 百度地图工具类封装(包括定位,附近.城市.范围poi检索, ...

  4. 关于TornadoFx和Android的全局配置工具类封装实现及思路解析

    原文地址: 关于TornadoFx和Android的全局配置工具类封装实现及思路解析 - Stars-One的杂货小窝 目前个人开发软件存在设置页面,可以让用户自定义些设置,但我发现,存储数据的代码逻 ...

  5. Redis操作Set工具类封装,Java Redis Set命令封装

    Redis操作Set工具类封装,Java Redis Set命令封装 >>>>>>>>>>>>>>>>& ...

  6. Redis操作List工具类封装,Java Redis List命令封装

    Redis操作List工具类封装,Java Redis List命令封装 >>>>>>>>>>>>>>>> ...

  7. Redis操作Hash工具类封装,Redis工具类封装

    Redis操作Hash工具类封装,Redis工具类封装 >>>>>>>>>>>>>>>>>> ...

  8. Redis操作字符串工具类封装,Redis工具类封装

    Redis操作字符串工具类封装,Redis工具类封装 >>>>>>>>>>>>>>>>>>& ...

  9. java中基于TaskEngine类封装实现定时任务

    主要包括如下几个类: 文章标题:java中基于TaskEngine类封装实现定时任务 文章地址: http://blog.csdn.net/5iasp/article/details/10950529 ...

随机推荐

  1. 《HelloGitHub》第 35 期

    <HelloGitHub>第 35 期 兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这是一个面向编程新手.热爱编程. ...

  2. SpringCloud学习系列之五-----配置中心(Config)和消息总线(Bus)完美使用版

    前言 在上篇中介绍了SpringCloud Config的使用,本篇则介绍基于SpringCloud(基于SpringBoot2.x,.SpringCloud Finchley版)中的分布式配置中心( ...

  3. 论JVM爆炸的几种姿势及自救方法

    前言 如今不管是在面试还是在我们的工作中,OOM总是不断的出现在我们的视野中,所以我们有必要去了解一下导致OOM的原因以及一些基本的调整方法,大家可以通过下面的事例来了解一下什么样的代码会导致OOM, ...

  4. 【4】Asp.Net Core2.2中间件多扩展对应应用

    [前言] 上一篇完成了Asp.Net Core 2.2全新的管道处理模型解析,“俄罗斯套娃”式的委托嵌套和传递,组建了扩展性无与伦比的管道模型!与此同时,委托嵌套过于复杂,使用起来并不友好,然后多种扩 ...

  5. docker(1)应用场景以及安装

    今年来了新公司,公司没有用什么新技术,架构就简单的前后分离,但是我推一下新的技术,在这基础上我要培训一下同事,让他们能接受,对新技术不感到陌生,并且认可愿意去学习.其实在这个过程中也能让他们认同我这个 ...

  6. 第一课《.net之--泛型》

    今天我来学习泛型,泛型是编程入门学习的基础类型,从.net诞生2.0开始就出现了泛型,今天我们开始学习泛型的语法和使用. 什么是泛型? 泛型(generic)是C#语言2.0和通用语言运行时(CLR) ...

  7. js数组中的find(), findIndex(), filter(), forEach(), some(), every(), map(), reduce()方法的详解和应用实例

    1. find()与findIndex() find()方法,用于找出第一个符合条件的数组成员.它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该 ...

  8. iOS 字典转模型Model

    基本原理 利用 runtime 原理,获取模型中所有实例变量列表,根据实例变量以此获取模型中成员变量的名称和属性类型,区分Foundation和自定义属性,需要对NSDictionary和NSArra ...

  9. VIVADO时序约束及STA基础

    一.前言 无论是FPGA应用开发还是数字IC设计,时序约束和静态时序分析(STA)都是十分重要的设计环节.在FPGA设计中,可以在综合后和实现后进行STA来查看设计是否能满足时序上的要求.本文阐述基本 ...

  10. php原生代码实现explode函数功能

    在开始代码前要先介绍几个PHP函数: explode()   把字符串打散成数组 strpos()     返回字符串在另一个字符串第一次出现的位置(对大小写敏感) strstr()       查找 ...