亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

java動(dòng)態(tài)構(gòu)建數(shù)據(jù)庫復(fù)雜查詢教程

 更新時(shí)間:2021年11月25日 14:10:30   作者:廈門在乎科技  
這篇文章主要介紹了java動(dòng)態(tài)構(gòu)建數(shù)據(jù)庫復(fù)雜查詢的實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

有的時(shí)候,你需要?jiǎng)討B(tài)構(gòu)建一個(gè)比較復(fù)雜的查詢條件,傳入數(shù)據(jù)庫中進(jìn)行查詢。而條件本身可能來自前端請(qǐng)求或者配置文件。那么這個(gè)時(shí)候,表達(dá)式樹,就可以幫助到你。

Where當(dāng)中可以傳入固定的條件

以下是一個(gè)簡單的單元測(cè)試用例。接下來,我們將這個(gè)測(cè)試用例改的面目全非。

[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就是一種表達(dá)式樹

由于是 Queryable 的關(guān)系,所以Where當(dāng)中的其實(shí)是一個(gè)表達(dá)式,那么我們把它單獨(dú)定義出來,順便水一下文章的長度。

[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);
}

表達(dá)式可以通過Lambda隱式轉(zhuǎn)換

Expression 右側(cè)是一個(gè) Lambda ,所以可以捕獲上下文中的變量。
這樣你便可以把 minValue 和 maxValue 單獨(dú)定義出來。
于是乎你可以從其他地方來獲取 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);
}

可以使用方法創(chuàng)建表達(dá)式

那既然這樣,我們也可以使用一個(gè)方法來創(chuàng)建 Expression。
這個(gè)方法,實(shí)際上就可以認(rèn)為是這個(gè) 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 作為參數(shù)來制作工廠方法,那么用委托當(dāng)然也可以。
于是,我們可以把左邊和右邊分別定義成兩個(gè) 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);
    }
}

也可以手動(dòng)構(gòu)建表達(dá)式

實(shí)際上,左右兩個(gè)不僅僅是兩個(gè)Func,其實(shí)也可以直接是兩個(gè)表達(dá)式。
不過稍微有點(diǎn)不同的是,表達(dá)式的合并需要用 Expression 類型中的相關(guān)方法創(chuàng)建。
我們可以發(fā)現(xiàn),調(diào)用的地方這次其實(shí)沒有任何改變,因?yàn)?Lambda 既可以隱式轉(zhuǎn)換為 Func 也可以隱式轉(zhuǎn)換為 Expression。
每個(gè)方法的意思可以從注釋中看出。

[Test]
public void Expression04()
{
    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<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;
    }
}

引入表達(dá)式的解構(gòu)

使其更加簡單

但是,上面的方法,其實(shí)可以再優(yōu)化一下。避免對(duì)左右表達(dá)式的直接調(diào)用。
使用一個(gè)叫做 Unwrap 的方法,可以將 Lambda Expression 解構(gòu)成只包含 Body 部分的表達(dá)式。
這是一個(gè)自定義的擴(kuò)展方法,你可以通過?ObjectVisitor?來引入這個(gè)方法。

[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<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;
    }
}

可以拼接更多的表達(dá)式

我們可以再優(yōu)化以下,把 CreateFilter 方法擴(kuò)展為支持多個(gè)子表達(dá)式和可自定義子表達(dá)式的連接方式。
于是,我們就可以得到一個(gè) 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;
    }
}

使用工廠方法來代替固定的子表達(dá)式

有了前面的經(jīng)驗(yàn),我們知道。其實(shí)x => x >= 1這個(gè)表達(dá)式可以通過一個(gè)工廠方法來建。
所以,我們使用一個(gè) CreateMinValueFilter 來創(chuàng)建這個(gè)表達(dá)式。

[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;
    }
}

工廠方法內(nèi)部也可以使用Expression手動(dòng)創(chuàng)建

當(dāng)然,可以只使用 Expression 相關(guān)的方法來創(chuàng)建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;
    }
}

同理,子表達(dá)式都可以如此創(chuàng)建

那既然都用了 Expression 來創(chuàng)建子表達(dá)式了,那就干脆再做一點(diǎn)點(diǎn)改進(jìn),把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);
        } 
        return result;
    }
}

加入一點(diǎn)點(diǎn)配置,就完成了

最后,我們?cè)诎炎颖磉_(dá)式的創(chuàng)建通過一點(diǎn)點(diǎn)小技巧。通過外部參數(shù)來決定。就基本完成了一個(gè)多 And 的值比較查詢條件的動(dòng)態(tài)構(gòu)建。

[Test]
public void Expression10()
{
    var config = new Dictionary<string, int>
    {
        { ">=", 1 },
        { "<", 5 }
    };
    var subFilters = config.Select(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動(dòng)態(tài)構(gòu)建數(shù)據(jù)庫復(fù)雜查詢實(shí)現(xiàn)示例的詳細(xì)內(nèi)容,更多關(guān)于動(dòng)態(tài)構(gòu)建數(shù)據(jù)庫復(fù)雜查詢的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java中的transient關(guān)鍵字介紹

    Java中的transient關(guān)鍵字介紹

    這篇文章主要介紹了Java中的transient關(guān)鍵字介紹,需要的朋友可以參考下
    2015-03-03
  • @Autowired注入為null的原因與解決方法

    @Autowired注入為null的原因與解決方法

    我們經(jīng)常會(huì)通過@Autowired注解將某個(gè)類注到另一個(gè)類中,但是會(huì)發(fā)現(xiàn)注不進(jìn)去,報(bào)NULL,所以本文就給大家分析了@Autowired 注入為null 的原因與解決方法,需要的朋友可以參考下
    2023-09-09
  • 詳解如何解決SSM框架前臺(tái)傳參數(shù)到后臺(tái)亂碼的問題

    詳解如何解決SSM框架前臺(tái)傳參數(shù)到后臺(tái)亂碼的問題

    這篇文章主要介紹了詳解如何解決SSM框架前臺(tái)傳參數(shù)到后臺(tái)亂碼的問題,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-12-12
  • Java實(shí)現(xiàn)高并發(fā)秒殺的七種方式

    Java實(shí)現(xiàn)高并發(fā)秒殺的七種方式

    本文主要介紹了Java實(shí)現(xiàn)高并發(fā)秒殺的六種方式,包括使用緩存、數(shù)據(jù)庫樂觀鎖、數(shù)據(jù)庫悲觀鎖、分布式鎖、隊(duì)列限流、令牌桶算法和限流器,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • SpringBoot2.0 整合 SpringSecurity 框架實(shí)現(xiàn)用戶權(quán)限安全管理方法

    SpringBoot2.0 整合 SpringSecurity 框架實(shí)現(xiàn)用戶權(quán)限安全管理方法

    Spring Security是一個(gè)能夠?yàn)榛赟pring的企業(yè)應(yīng)用系統(tǒng)提供聲明式的安全訪問控制解決方案的安全框架。這篇文章主要介紹了SpringBoot2.0 整合 SpringSecurity 框架,實(shí)現(xiàn)用戶權(quán)限安全管理 ,需要的朋友可以參考下
    2019-07-07
  • spring學(xué)習(xí)之util:properties的使用

    spring學(xué)習(xí)之util:properties的使用

    這篇文章主要介紹了spring學(xué)習(xí)之util:properties的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • springboot中引入日志文件生成的配置詳解

    springboot中引入日志文件生成的配置詳解

    本文主要介紹了springboot中引入日志文件生成的配置詳解,包括日志級(jí)別的設(shè)置、日志格式的配置以及日志輸出的位置等,從而幫助開發(fā)者更好地進(jìn)行開發(fā)與調(diào)試
    2023-10-10
  • java中MultipartFile和File最簡單的互相轉(zhuǎn)換示例

    java中MultipartFile和File最簡單的互相轉(zhuǎn)換示例

    這篇文章主要給大家介紹了關(guān)于java中MultipartFile和File最簡單的互相轉(zhuǎn)換的相關(guān)資料,MultipartFile和File都是Java中用于處理文件上傳的類,MultipartFile用于處理上傳的文件,File用于處理本地磁盤上的文件,需要的朋友可以參考下
    2023-09-09
  • JavaCV實(shí)現(xiàn)照片馬賽克效果

    JavaCV實(shí)現(xiàn)照片馬賽克效果

    這篇文章主要介紹了如何通過JavaCV實(shí)現(xiàn)照片馬賽克效果,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)JavaCV有一定的幫助,感興趣的小伙伴可以跟隨小編一起動(dòng)手試一試
    2022-01-01
  • SpringBoot中的JPA(Java?Persistence?API)詳解

    SpringBoot中的JPA(Java?Persistence?API)詳解

    這篇文章主要介紹了SpringBoot中的JPA(Java?Persistence?API)詳解,JPA用于將?Java?對(duì)象映射到關(guān)系型數(shù)據(jù)庫中,它提供了一種面向?qū)ο蟮姆绞絹聿僮鲾?shù)據(jù)庫,使得開發(fā)者可以更加方便地進(jìn)行數(shù)據(jù)持久化操作,需要的朋友可以參考下
    2023-07-07

最新評(píng)論