首页 > 作文

java动态构建数据库复杂查询教程

更新时间:2023-04-03 23:09:33 阅读: 评论:0

有的时候,你需要动态构建一个比较复杂的查询条件,传入数据库中进行查询。而条件本身可能来自前端请求或者配置文件。那么这个时候,表达式树,就可以帮助到你。

where当中可以传入固定的条件

以下是一个简单的单元测试用例。接下来,我们将这个测试用例改的面目全非。

[test]public void normal(){    var re = enumerable.range(0, 10).asqueryable() // 0-9        .where(x => x >= 1 && x < 5).tolist(); // 1 2 3 4    var expectation = enumerable.range(1, 4); // 1 2 3 4    re.should().beequivalentto(expectation);}

queryable中的where就是一种表达式树

由于是 queryable 的关系,所以where当中的其实是一个表达式,那么我们把它单独定义出来,顺便水一下文章的长度。

[test]public void expression00(){    expression<func<int, bool>> filter = x => x >= 1 && x < 5;    var re = enumerable.range(0, 10).asqueryable()        .where(filter).tolist();    var expectation = enumerable.range(1, 4);    re.should().beequivalentto(expectation);}

表达式可以通过lambda隐式转换

expression 右侧是一个 lambda ,所以可以捕获上下文中的变量。
这样你便可以把 minvalue 和 maxvalue 单独定义出来。
于是乎你可以从其他地方来获取 minvalue 和 maxvalue 来改变 filter。

[test]public void expression01(){    var minvalue = 1;    var maxvalue = 5;    expression<func<int, bool>> filter = x => x >= minvalue && x < maxvalue;    var re = enumerable.range(0, 10).asqueryable()        .where(filter).tolist();    var expectation = enumerable.range(1, 4);    re.should().beequivalentto(expectation);}

可以使用方法创建表达式

那既然这样,我们也可以使用一个方法来创建 expression。
这个方法,实际上就可以认为是这个 expression 的工厂方法。

[test]public void expression02(){    var filter = createfilter(1, 5);    var re = enumerable.range(0, 10).asqueryable()        .where(filter).tolist();    var expectation = enumerable.range(1, 4);    re.should().beequivalentto(expectation);     expression<func<int, bool>> createfilter(int minvalue, int maxvalue)    {        return x => x >= minvalue && x < maxvalue;    }}

通过func可以更加灵活的组合条件

那可以使用 minvalue 和 maxvalue 作为参数来制作工厂方法,那么用委托当然也可以。
于是,我们可以把左边和右边分别定义成两个 func,从而由外部来决定左右具体的比较方式。

[test]public void expression03(){    var filter = createfilter(x => x >= 1, x => x < 5);    var re = enumerable.range(0, 10).asqueryable()        .where(filter).tolist();    var expectation = enumerable.range(1, 4);    re.should().beequivalentto(expectation);     expression<func<int, bool>> createfilter(func<int, bool> leftfunc, func<int, bool> rightfunc)    {        return x => leftfunc.invoke(x) && rightfunc.invoke(x);    }}

也可以手动构建表达式

实际上,左右两个不仅仅是两个func,其实也可以直接是两个表达式。
不过稍微有点不同的是,表达式的合并需要用 expression 类型中的相关方法创建。
我们可以发现,调用的地方这次其实没有任何改变,因为 lambda 既可以隐式转换为 func 也可以隐式转换为 expression。
每个方法的意思可以从注释中看出。

[test]public void expression04(){    var filter = createfil十一国庆节活动策划ter(x => x >= 1, x => x < 5);    var re = enumerable.range(0, 10).asqueryable()        .where(filter).tolist();    var expectation = enumerable.range(1, 4);    re.should().beequivalentto(expectation);     expression<func<int, bool>> createfilter(expression<func<int, bool>> leftfunc,        expression<func<int, bool>> rightfunc)    {        // x        var pexp = expression.parameter(typeof(int), "x");        // (a => leftfunc(a))(x)        var leftexp = expression.invoke(leftfunc, pexp);        // (a => rightfunc(a))(x)        var rightexp = expression.invoke(rightfunc, pexp);        // (a => leftfunc(a))(x) && (a => rightfunc(a))(x)        var bodyexp = expression.andalso(leftexp, rightexp);        // x => (a => leftfunc(a))(x) && (a => rightfunc(a))(x)        var resultexp = expression.lambda<func<int, bool>>(bodyexp, pexp);        return resultexp;    }}

引入表达式的解构

使其更加简单

但是,上面的方法,其实可以再优化一下。避免对左右表达式的直接调用。
使用一个叫做 unwrap 的方法,可以将 lambda expression 解构成只包含 body 部分的表达式。
这是一个自定义的扩展方法,你可以通过objectvisitor来引入这个方法。

[test]public void expression05(){    var filter = createfilter(x => x >= 1, x => x < 5);    var re = enumerable.range(0, 10).asqueryable()        .where(filter).tolist();    var expectation = enumerable.range(1, 4);    re.should().beequivalentto(expectation);     expression<func<int, bool>> createfilter(expression&l成绩分析t;func<int, bool>> leftfunc,        expression<func<int, bool>> rightfunc)    {        // x        var pexp = expression.parameter(typeof(int), "x");        // leftfunc(x)        var leftexp = leftfunc.unwrap(pexp);        // rightfunc(x)        var rightexp = rightfunc.unwrap(pexp);        // leftfunc(x) && rightfunc(x)        var bodyexp = expression.andalso(leftexp, rightexp);        // x => leftfunc(x) && rightfunc(x)        var resultexp = expression.lambda<func<int, bool>>(bodyexp, pexp);        return resultexp;    }}

可以拼接更多的表达式

我们可以再优化以下,把 createfilter 方法扩展为支持多个子表达式和可自定义子表达式的连接方式。
于是,我们就可以得到一个 joinsubfilters 方法。

[test]public void expression06(){    var filter = joinsubfilters(expression.andalso, x => x >= 1, x => x < 5);    var re = enumerable.range(0, 10).asqueryable()        .where(filter).tolist();    var expectation = enumerable.range(1, 4);    re.should().beequivalentto(expectation);     expression<func<int, bool>> joinsubfilters(func<expression, expression, expression> expjoiner,        params expression<func<int, bool>>[] subfilters)    {        // x        var pexp = expression.parameter(typeof(int), "x");        var result = subfilters[0];        foreach (var sub in subfilters[1..])        {            var leftexp = result.unwrap(pexp);            var rightexp = sub.unwrap(pexp);            var bodyexp = expjoiner(leftexp, rightexp);            result = expression.lambda<func<int, bool>>(bodyexp, pexp);        }        return result;    }}

使用工厂方法来代替固定的子表达式

有了前面的经验,我们知道。其实x => x >= 1这个表达式可以通过一个工厂方法来建。
所以,苏州大学排名我们使用一个 createminvaluefilter 来创建这个表达式。

[test]public void expression07(){    var filter = joinsubfilters(expression.andalso,        createminvaluefilter(1),        x => x < 5);    var re = enumerable.range(0, 10).asqueryable()        .where(filter).tolist();    var expectation = enumerable.range(1, 4);    re.should().beequivalentto(expectation);     expression<func<int, bool>> createminvaluefilter(int minvalue)    {        return x => x >= minvalue;    }    expression<func<int, bool>> joinsubfilters(func<expression, expression, expression> expjoiner,        params expression<func<int, bool>>[] subfilters)    {        // x        var pexp = expression.parameter(typeof(int), "x");        var result = subfilters[0];        foreach (var sub in subfilters[1..])        {            var leftexp = result.unwrap(pexp);            var rightexp = sub.unwrap(pexp);            var bodyexp = expjoiner(leftexp, rightexp);             result = expression.lambda<func<int, bool>>(bodyexp, pexp);        }         return result;    }}

工厂方法内部也可以使用expression手动创建

当然,可以只使用 expression 相关的方法来创建x => x >= 1。

[test]public void expression08(){    var filter = joinsubfilters(expression.andalso,        createminvaluefilter(1),        x => x < 5);    var re = enumerable.range(0, 10).asqueryable()        .where(filter).tolist();    var expectation = enumerable.range(1, 4);    re.should().beequivalentto(expectation);     expression<func<int, bool>> createminvaluefilter(int minvalue)    {        // x        var pexp = expression.parameter(typeof(int), "x");        // minvalue        var rightexp = expression.constant(minvalue);        // x >= minvalue        var bodyexp = expression.greaterthanorequal(pexp, rightexp);        var result = expression.lambda<func<int, bool>>(bodyexp, pexp);        return result;    }     expression<func<int, bool>> joinsubfilters(func<expression, expression, expression> expjoiner,        params expression<func<int, bool>>[] subfilters)    {        // x        var pexp = expression.parameter(typeof(int), "x");        var result = subfilters[0];        foreach (var sub in subfilters[1..])        {            var leftexp = result.unwrap(pexp);            var rightexp = sub.unwrap(pexp);            var bodyexp = expjoiner(leftexp, rightexp);             result = expression.lambda<func<int, bool>>(bodyexp, pexp);        }         return result;    }}

同理,子表达式都可以如此创建

那既然都用了 expression 来创建子表达式了,那就干脆再做一点点改进,把x => x < 5也做成从工厂方法获取。

[test]public void expression09(){    var filter = joinsubfilters(expression.andalso,        createvaluecomparefilter(expression.greaterthanorequal, 1),        createvaluecomparefilter(expression.lessthan, 5));    var re = enumerable.range(0, 10).asqueryable()        .where(filter).tolist();    var expectation = enumerable.range(1, 4);    re.should().beequivalentto(expectation);    expression<func<int, bool>> createvaluecomparefilter(func<expression, expression, expression> comparerfunc,        int rightvalue)    {        var pexp = expression.parameter(typeof(int), "x");        var rightexp = expression.constant(rightvalue);        var bodyexp = comparerfunc(pexp, rightexp);        var result = expression.lambda<func<int, bool>>(bodyexp, pexp);        return result;    }     expression<func<int, bool>> joinsubfilters(func<expression, expression, expression> expjoiner,        params expression<func<int, bool>>[] subfilters)    {        // x        var pexp = expression.parameter(typeof(int), "x");        var result = subfilters[0];        foreach (var sub in subfilters[1..])        {            var leftexp = result.unwrap(pexp);            var rightexp = sub.unwrap(pexp);            var bodyexp = expjoiner(leftexp, rightexp);             result = expression.lambda<func<int, bool>>(bodyexp, pexp);        }         retur标准情人n result;    }}

加入一点点配置,就完成了

最后,我们在把子表达式的创建通过一点点小技巧。通过外部参数来决定。就基本完成了一个多 and 的值比较查询条件的动态构建。

[test]public void expression10(){    var config = new dictionary<string, int>    {        { ">=", 1 },        { "<", 5 }    };    var subfilters = config.lect(x => createvaluecomparefilter(mapconfig(x.key), x.value)).toarray();    var filter = joinsubfilters(expression.andalso, subfilters);    var re = enumerable.range(0, 10).asqueryable()        .where(filter).tolist();    var expectation = enumerable.range(1, 4);    re.should().beequivalentto(expectation);     func<expression, expression, expression> mapconfig(string op)    {        return op switch        {            ">=" => expression.greaterthanorequal,            "<" => expression.lessthan,            _ => throw new argumentoutofrangeexception(nameof(op))        };    }     expression<func<int, bool>> createvaluecomparefilter(func<expression, expression, expression> comparerfunc,        int rightvalue)    {        var pexp = expression.parameter(typeof(int), "x");        var rightexp = expression.constant(rightvalue);        var bodyexp = comparerfunc(pexp, rightexp);        var result = expression.lambda<func<int, bool>勒仕垃圾处理器;>(bodyexp, pexp);        return result;    }    expression<func<int, bool>> joinsubfilters(func<expression, expression, expression> expjoiner,        params expression<func<int, bool>>[] subfilters)    {        // x        var pexp = expression.parameter(typeof(int), "x");        var result = subfilters[0];        foreach (var sub in subfilters[1..])        {            var leftexp = result.unwrap(pexp);            var rightexp = sub.unwrap(pexp);            var bodyexp = expjoiner(leftexp, rightexp);             result = expression.lambda<func<int, bool>>(bodyexp, pexp);        }         return result;    }}

以上就是java动态构建数据库复杂查询实现示例的详细内容,更多关于动态构建数据库复杂查询的资料请关注www.887551.com其它相关文章!

本文发布于:2023-04-03 23:09:32,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/5f56671baa16c0be9cf2dea78b2aadda.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:java动态构建数据库复杂查询教程.doc

本文 PDF 下载地址:java动态构建数据库复杂查询教程.pdf

标签:表达式   方法   是一个   工厂
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图