目标封装通用格式的ORM数据库驱动(MongoDB篇)
这篇文章主要说明Where函数的实现
参考了一片文章<<通用查询类封装之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. 至此,圆括号已不再,只是简单的表达式,这就简单了
这篇文章跟我的思路很接近,但是从优先级上我还是按照从左到右的逻辑,并不是先去寻找最后的一个"("
步骤一:(定义一个入口函数Where)
//保存结果
FilterDefinition<BsonDocument> filter = null;
//用来保存需要合成的公式
private Dictionary<int, string> formulas = new Dictionary<int, string>();
//入口函数
public void Where(string condition)
{
condition = "(" + condition.Replace(" ", "") + ")";
var index = 0;
formulas = new Dictionary<int, string>();
while (true)
{
index++;
var end = condition.IndexOf(")");
if (end < 0)
{
break;
}
var start = condition.Substring(0, end).LastIndexOf("(");
var find = condition.Substring(start + 1, end - start - 1);
formulas.Add(index, find);
condition = condition.Substring(0, start) + "$" + index + "$" + condition.Substring(end + 1);
}
List<int> list = new List<int>(formulas.Keys);
var target = formulas[list[list.Count - 1]];
filter = whereTool(target);
}
步骤二:(定义一个辅助函数whereTool)
private FilterDefinition<BsonDocument> whereTool(string target)
{
FilterDefinition<BsonDocument> f = null;
var charIndex = 0;
var lastCharIndex = 0;
char last = '&';
foreach (var c in target)
{
if (c == '&' || c == '|')
{
var formula = target.Substring(lastCharIndex, charIndex - lastCharIndex);
lastCharIndex = charIndex + 1;
last = c;
whereToolLogic(formula, last, ref f);
}
charIndex++;
}
if (lastCharIndex < target.Length - 1)
{
var formula = target.Substring(lastCharIndex, charIndex - lastCharIndex);
whereToolLogic(formula, last, ref f);
}
return f;
}
private FilterDefinition<BsonDocument> whereToolLogic(string formula, char c, ref FilterDefinition<BsonDocument> f)
{
if (c == '&')
{
if (formula.IndexOf("$") == 0 && formula.LastIndexOf("$") == formula.Length - 1)
{
var i = Convert.ToInt32(formula.Substring(1, formula.Length - 2));
f = f == null ? whereTool(formulas[i]) : f & whereTool(formulas[i]);
}
else
{
f = f == null ? GetFilter(formula) : f & GetFilter(formula);
}
}
else if (c == '|')
{
if (formula.IndexOf("$") == 0 && formula.LastIndexOf("$") == formula.Length - 1)
{
var i = Convert.ToInt32(formula.Substring(1, formula.Length - 2));
f = f == null ? whereTool(formulas[i]) : f | whereTool(formulas[i]);
}
else
{
f = f == null ? GetFilter(formula) : f | GetFilter(formula);
}
}
return f;
}
使用实例
Where("((a=1)&b=2) | c=3 | (((d=4) | e=5) & f=6)")
示例结果
{"$or":[{"a":"1","b":"2"},{"c":"3"},{"$or":[{"d":"4"},{"e":"5"}],"f":"6"}]}