欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#表達(dá)式樹(shù)Expression動(dòng)態(tài)創(chuàng)建表達(dá)式

 更新時(shí)間:2021年12月25日 11:54:23   作者:阿波Plus  
這篇文章介紹了C#表達(dá)式樹(shù)Expression動(dòng)態(tài)創(chuàng)建表達(dá)式的方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

上一篇中說(shuō)到了 Expression 的一些概念性東西,其實(shí)也是為了這一篇做知識(shí)準(zhǔn)備。為了實(shí)現(xiàn) EFCore 的多條件、連表查詢(xún),簡(jiǎn)化查詢(xún)代碼編寫(xiě),也就有了這篇文章。

在一些管理后臺(tái)中,對(duì)數(shù)據(jù)進(jìn)行多條件查詢(xún)是一件很普遍的事情,比如在用戶(hù)列表需要實(shí)現(xiàn)可以對(duì) "用戶(hù)名"、"手機(jī)號(hào)"、"賬戶(hù)是否凍結(jié)" 等等一系列的條件查詢(xún),常見(jiàn)的處理方式就是通過(guò)一系列 if...else... 來(lái)對(duì)條件進(jìn)行拼接。這會(huì)導(dǎo)致查詢(xún)接口實(shí)現(xiàn)起來(lái)堆疊了一堆看起來(lái)有用但實(shí)際很繁瑣的代碼。所以根據(jù)前后端請(qǐng)求報(bào)文協(xié)商,我們就可以按照一定的格式來(lái)動(dòng)態(tài)創(chuàng)建表達(dá)式樹(shù)。

創(chuàng)建 QueryEntity 類(lèi)

QueryEntity 是前端向 API 傳遞的參數(shù)列表,通過(guò)這個(gè)類(lèi),服務(wù)端可以知道前端需要查詢(xún)哪個(gè)字段,使用什么方法(Equals、Contains)過(guò)濾。

/// <summary>
/// 查詢(xún)實(shí)體
/// </summary>
public class QueryEntity
{
    /// <summary>
    /// 字段名稱(chēng)
    /// </summary>
    public string Key { get; set; }

    /// <summary>
    /// 值
    /// </summary>
    public string Value { get; set; }

    /// <summary>
    /// 操作方法,對(duì)應(yīng)OperatorEnum枚舉類(lèi)
    /// </summary>
    public string Operator { get; set; }

    /// <summary>
    /// 邏輯運(yùn)算符,只支持AND、OR
    /// </summary>
    public string LogicalOperator { get; set; }
}

創(chuàng)建 OperatorEnum 類(lèi)

OperatorEnum 這是一個(gè)操作方法的枚舉類(lèi),規(guī)定了 API 允許的查詢(xún)方法,比如 Equals、Contains 等等。

/// <summary>
/// 操作方法枚舉
/// </summary>
public enum OperatorEnum
{
    /// <summary>
    /// 等于
    /// </summary>
    Equals,

    /// <summary>
    /// 不等于
    /// </summary>
    NotEqual,

    /// <summary>
    /// 包含
    /// </summary>
    Contains,

    /// <summary>
    /// 由什么開(kāi)始
    /// </summary>
    StartsWith,

    /// <summary>
    /// 由什么結(jié)束
    /// </summary>
    EndsWith,

    /// <summary>
    /// 大于
    /// </summary>
    Greater,

    /// <summary>
    /// 大于等于
    /// </summary>
    GreaterEqual,

    /// <summary>
    /// 小于
    /// </summary>
    Less,

    /// <summary>
    /// 小于等于
    /// </summary>
    LessEqual,
}

創(chuàng)建 ExpressionExtension 類(lèi)

ExpressionExtension 類(lèi)實(shí)現(xiàn)了表達(dá)式樹(shù)的動(dòng)態(tài)創(chuàng)建,將前端傳入的多條件查詢(xún)轉(zhuǎn)換成表達(dá)式,用于 EFCore 的查詢(xún)。

/// <summary>
/// 表達(dá)式擴(kuò)展
/// </summary>
/// <typeparam name="T">泛型</typeparam>
public static class ExpressionExtension<T> where T : class, new()
{
    /// <summary>
    /// 表達(dá)式動(dòng)態(tài)拼接
    /// </summary>
    public static Expression<Func<T, bool>> ExpressionSplice(List<QueryEntity> entities)
    {
        if (entities.Count < 1)
        {
            return ex => true;
        }
        var expression_first = CreateExpressionDelegate(entities[0]);
        foreach (var entity in entities.Skip(1))
        {
            var expression = CreateExpressionDelegate(entity);
            InvocationExpression invocation = Expression.Invoke(expression_first, expression.Parameters.Cast<Expression>());
            BinaryExpression binary;
            // 邏輯運(yùn)算符判斷
            if (entity.LogicalOperator.ToUpper().Equals("OR"))
            {
                binary = Expression.Or(expression.Body, invocation);
            }
            else
            {
                binary = Expression.And(expression.Body, invocation);
            }
            expression_first = Expression.Lambda<Func<T, bool>>(binary, expression.Parameters);
        }
        return expression_first;
    }

    /// <summary>
    /// 創(chuàng)建 Expression<TDelegate>
    /// </summary>
    private static Expression<Func<T, bool>> CreateExpressionDelegate(QueryEntity entity)
    {
        ParameterExpression param = Expression.Parameter(typeof(T));

        Expression key = param;
        var entityKey = entity.Key.Trim();
        // 包含'.',說(shuō)明是父表的字段
        if (entityKey.Contains('.'))
        {
            var tableNameAndField = entityKey.Split('.');
            key = Expression.Property(key, tableNameAndField[0].ToString());
            key = Expression.Property(key, tableNameAndField[1].ToString());
        }
        else
        {
            key = Expression.Property(key, entityKey);
        }

        Expression value = Expression.Constant(ParseType(entity));
        Expression body = CreateExpression(key, value, entity.Operator);
        var lambda = Expression.Lambda<Func<T, bool>>(body, param);
        return lambda;
    }

    /// <summary>
    /// 屬性類(lèi)型轉(zhuǎn)換
    /// </summary>
    /// <param name="entity">查詢(xún)實(shí)體</param>
    /// <returns></returns>
    private static object ParseType(QueryEntity entity)
    {
            try
            {
                PropertyInfo property;
                // 包含'.',說(shuō)明是子類(lèi)的字段
                if (entity.Key.Contains('.'))
                {
                    var tableNameAndField = entity.Key.Split('.');

                    property = typeof(T).GetProperty(tableNameAndField[0], BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
                    property = property.PropertyType.GetProperty(tableNameAndField[1], BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
                }
                else
                {
                    property = typeof(T).GetProperty(entity.Key, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
                }

                return Convert.ChangeType(entity.Value, property.PropertyType);
            }
            catch (Exception)
            {
                throw new ArgumentException("字段類(lèi)型轉(zhuǎn)換失?。鹤侄蚊e(cuò)誤或值類(lèi)型不正確");
            }
    }

    /// <summary>
    /// 創(chuàng)建 Expression
    /// </summary>
    private static Expression CreateExpression(Expression left, Expression value, string entityOperator)
    {
        if (!Enum.TryParse(entityOperator, true, out OperatorEnum operatorEnum))
        {
            throw new ArgumentException("操作方法不存在,請(qǐng)檢查operator的值");
        }

        return operatorEnum switch
        {
                OperatorEnum.Equals => Expression.Equal(left, Expression.Convert(value, left.Type)),
                OperatorEnum.NotEqual => Expression.NotEqual(left, Expression.Convert(value, left.Type)),
                OperatorEnum.Contains => Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), value),
                OperatorEnum.StartsWith => Expression.Call(left, typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }), value),
                OperatorEnum.EndsWith => Expression.Call(left, typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) }), value),
                OperatorEnum.Greater => Expression.GreaterThan(left, Expression.Convert(value, left.Type)),
                OperatorEnum.GreaterEqual => Expression.GreaterThanOrEqual(left, Expression.Convert(value, left.Type)),
                OperatorEnum.Less => Expression.LessThan(left, Expression.Convert(value, left.Type)),
                OperatorEnum.LessEqual => Expression.LessThanOrEqual(left, Expression.Convert(value, left.Type)),
                _ => Expression.Equal(left, Expression.Convert(value, left.Type)),
        };
    }
}

使用示例

例如有以下兩個(gè)實(shí)體類(lèi),Address 是 User 的子類(lèi)

public class User
{
    public int Id { get; set; }

    public string Name { get; set; } = string.Empty;

    public int Age { get; set; }

    public DateTime CreateTime { get; set; }

    public Address Address { get; set; }

}

public class Address
{
    public string Province { get; set; }

    public string City { get; set; }
}

單條件查詢(xún)

查詢(xún)用戶(hù)表中名稱(chēng)(name) 包含 "chen" :

List<QueryEntity> list = new List<QueryEntity>
{
    new QueryEntity
    {
        Key = "name",
        Value = "chen",
        Operator = "Contains"
    }
};
var expression = ExpressionExtension<User>.ExpressionSplice(list);
// expression = Param_0 => Param_0.Name.Contains("chen")

查詢(xún)用戶(hù)表中年齡(age) 大于等于 18:

List<QueryEntity> list = new List<QueryEntity>
{
    new QueryEntity
    {
        Key = "age",
        Value = "18",
        Operator = "GreaterEqual"
    }
};
var expression = ExpressionExtension<User>.ExpressionSplice(list);
// expression = Param_0 => Param_0.Name.GreaterThanOrEqual(18)

多條件查詢(xún)

查詢(xún)用戶(hù)表中名稱(chēng)(name) 包含 "chen" 并且年齡(age) 大于等于 18:

List<QueryEntity> list = new List<QueryEntity>
{
    new QueryEntity
    {
        Key = "name",
        Value = "chen",
        Operator = "Contains"
    },
    new QueryEntity
    {
        Key = "age",
        Value = "18",
        Operator = "GreaterEqual",
        // 注意:這里得填入 "AND",代表兩個(gè)條件是并且的關(guān)系,如果需要查詢(xún)名稱(chēng)包含 "chen" 或者 年齡大于等于18,則填入 "OR"
        "logicalOperator": "AND"
    }
};
var expression = ExpressionExtension<User>.ExpressionSplice(list);
// expression = Param_0 => ((Param_0.Status >= Convert(1, Int32)) And Invoke(Param_1 => Param_1.OpenId.Contains("9JJdFTVt6oimCgdbW61sk"), Param_0))

多表查詢(xún)

查詢(xún)用戶(hù)表中名稱(chēng)(name) 包含 "chen" 并且 地址(address)在廣東省:

List<QueryEntity> list = new List<QueryEntity>
{
    new QueryEntity
    {
        Key = "name",
        Value = "chen",
        Operator = "Contains"
    },
    new QueryEntity
    {
        Key = "address.Province",
        Value = "廣東省",
        Operator = "Equals",
        // 注意:這里得填入 "AND",代表兩個(gè)條件是并且的關(guān)系,如果需要查詢(xún)名稱(chēng)包含 "chen" 或者 年齡大于等于18,則填入 "OR"
        "logicalOperator": "AND"
    }
};

var expression = ExpressionExtension<BookingRecord>.ExpressionSplice(list);
// expression = {Param_0 => ((Param_0.Address.Province == Convert("廣東省", String)) And Invoke(Param_1 => Param_1.Name.Contains("chen"), Param_0))}

到此這篇關(guān)于C#表達(dá)式樹(shù)Expression動(dòng)態(tài)創(chuàng)建表達(dá)式的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • CPF?使用C#的Native?AOT?發(fā)布程序的詳細(xì)過(guò)程

    CPF?使用C#的Native?AOT?發(fā)布程序的詳細(xì)過(guò)程

    這篇文章主要介紹了CPF?使用C#的Native?AOT?發(fā)布程序,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具體一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • C#如何實(shí)現(xiàn)對(duì)sql server數(shù)據(jù)庫(kù)的增刪改查

    C#如何實(shí)現(xiàn)對(duì)sql server數(shù)據(jù)庫(kù)的增刪改查

    本文的主要內(nèi)容是C#實(shí)現(xiàn)對(duì)sql server數(shù)據(jù)庫(kù)的增刪改查,示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2015-08-08
  • C#中Trim()、TrimStart()、TrimEnd()的用法介紹

    C#中Trim()、TrimStart()、TrimEnd()的用法介紹

    這篇文章主要介紹了C#中Trim()、TrimStart()、TrimEnd()的用法,有需要的朋友可以參考一下
    2014-01-01
  • 深入解析C#中的abstract抽象類(lèi)

    深入解析C#中的abstract抽象類(lèi)

    這篇文章主要介紹了深入解析C#中的abstract抽象類(lèi),包括定義抽象類(lèi)等C#面相對(duì)象編程中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2016-01-01
  • C#利用ms office實(shí)現(xiàn)office轉(zhuǎn)pdf的示例代碼

    C#利用ms office實(shí)現(xiàn)office轉(zhuǎn)pdf的示例代碼

    這篇文章主要介紹了C#利用ms office實(shí)現(xiàn)office轉(zhuǎn)pdf的詳細(xì)方法,文中通過(guò)代碼示例和圖文講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-09-09
  • 深入理解C♯ 7.0中的Tuple特性

    深入理解C♯ 7.0中的Tuple特性

    這篇文章主要介紹了C#7中Tuple特性的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),相信對(duì)大家具有一定的參考價(jià)值,需要的朋友可以們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-03-03
  • C#實(shí)現(xiàn)微信分賬功能的完整步驟

    C#實(shí)現(xiàn)微信分賬功能的完整步驟

    這篇文章主要給大家介紹了關(guān)于C#實(shí)現(xiàn)微信分賬功能的完整步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • C#中實(shí)現(xiàn)深度優(yōu)先搜索

    C#中實(shí)現(xiàn)深度優(yōu)先搜索

    深度優(yōu)先搜索(DFS)是一種遍歷或搜索圖或樹(shù)的算法,廣泛應(yīng)用于迷宮尋路、圖像處理、路徑規(guī)劃、模式識(shí)別、社交網(wǎng)絡(luò)分析等領(lǐng)域,學(xué)習(xí)DFS有助于理解圖結(jié)構(gòu),解決回溯問(wèn)題,提升算法設(shè)計(jì)與分析能力,下面就來(lái)介紹一下
    2024-10-10
  • C#實(shí)現(xiàn)自定義光標(biāo)并動(dòng)態(tài)切換

    C#實(shí)現(xiàn)自定義光標(biāo)并動(dòng)態(tài)切換

    這篇文章主要為大家詳細(xì)介紹了如何利用C#語(yǔ)言實(shí)現(xiàn)自定義光標(biāo)、并動(dòng)態(tài)切換光標(biāo)類(lèi)型,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下
    2022-07-07
  • Unity3D基于OnGUI實(shí)時(shí)顯示FPS

    Unity3D基于OnGUI實(shí)時(shí)顯示FPS

    這篇文章主要介紹了Unity3D基于OnGUI實(shí)時(shí)顯示FPS,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-11-11

最新評(píng)論