XIKEW.COM - 公读宝典 - NetCore ORM 数据库驱动封装(MongoDB篇) - 公读宝典,一片文章<<通用查询类封装之Mongodb篇>>中间提到的算法思路 - 目标封装通用格式的ORM数据库驱动(MongoDB篇)

NetCore ORM 数据库驱动封装(MongoDB篇)
NETCORE MONGODB 4/16/2020 11:59:29 PM 阅读:2

image

目标封装通用格式的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"}]}