C# Expression使用实践——为FreeSql增加WhereLike方法

2022/7/7 2:20:17

本文主要是介绍C# Expression使用实践——为FreeSql增加WhereLike方法,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1.背景

前端有一个是否模糊查询的参数,当未勾选时,所有字符串类型的值使用a = 'xxx',勾选后使用a like '%xxx%'
如果使用WhereIf来写,每一个判断条件都需要写两行

.WhereIf(!request.IsLike && request.A.HasValue(), (i, o) => o.A== request.A)
.WhereIf(request.IsLike && request.A.HasValue(), (i, o) => o.A.Contains(request.A))

2.初次尝试

public static ISelect<T1, T2> WhereLike<T1, T2>(this ISelect<T1, T2> query, Func<HzyTuple<T1, T2>, string> filed, string value, bool isLike = false) 
    where T2 : class
{
    if (isLike)
    {
        query = query.Where(x => filed(x).Contains(value));
    }
    else
    {
        query = query.Where(x => filed(x) == value);
    }

    return query;
}

public static ISelect<T1, T2> WhereLike<T1, T2>(this ISelect<T1, T2> query, Func<T1, T2, string> filed, string value, bool isLike = false) where T2 : class
{
    if (isLike)
    {
        query = query.Where(x => filed(x.t1, x.t2).Contains(value));
    }
    else
    {
        query = query.Where(x => filed(x.t1, x.t2) == value);
    }

    return query;
}

执行后,发现生成的sql语句不正确where = 'xxx',少了字段名,猜测FreeSql底层表达式解析可能不支持这种写法

3.解决办法

开始大量Google Expression 相关资料,最终找到了解决办法

public static ISelect<T1> WhereLike<T1>(this ISelect<T1> query, Expression<Func<T1, string>> filed, string value, bool isLike = false) where T1 : class
{
    var valueExp = Expression.Constant(value);
    if (isLike)
    {
        var method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
        query = query.Where(Expression.Lambda<Func<T1, bool>>(Expression.Call(filed.Body, method, valueExp), filed.Parameters));
    }
    else
    {
        query = query.Where(Expression.Lambda<Func<T1, bool>>(Expression.Equal(filed.Body, valueExp), filed.Parameters));
    }

    return query;
}


#region HzyTuple

public static ISelect<T1, T2> WhereLike<T1, T2>(this ISelect<T1, T2> query, Expression<Func<HzyTuple<T1, T2>, string>> filed, string value, bool isLike = false)
        where T2 : class

{
    var valueExp = Expression.Constant(value);
    if (isLike)
    {
        var method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
        query = query.Where(Expression.Lambda<Func<HzyTuple<T1, T2>, bool>>(Expression.Call(filed.Body, method, valueExp), filed.Parameters));
    }
    else
    {
        query = query.Where(Expression.Lambda<Func<HzyTuple<T1, T2>, bool>>(Expression.Equal(filed.Body, valueExp), filed.Parameters));
    }

    return query;
}

#endregion

#region Not HzyTuple

public static ISelect<T1, T2> WhereLike<T1, T2>(this ISelect<T1, T2> query, Expression<Func<T1, T2, string>> filed, string value, bool isLike = false)
        where T2 : class

{
    var valueExp = Expression.Constant(value);
    if (isLike)
    {
        var method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
        query = query.Where(Expression.Lambda<Func<T1, T2, bool>>(Expression.Call(filed.Body, method, valueExp), filed.Parameters));
    }
    else
    {
        query = query.Where(Expression.Lambda<Func<T1, T2, bool>>(Expression.Equal(filed.Body, valueExp), filed.Parameters));
    }

    return query;
}

#endregion

4.附

以上表达式代码有一定规律,一个个写太费时间了,所以搞了个python脚本生成代码

脚本如下

max = 16

def PrintHzyTuple(number):
    TValue = ', '.join(['T'+str(i+1) for i in range(number)])
    TWhere = ''
    for i in range(number-1):
        TWhere += f'            where T{str(i+2)} : class\n'
    template = f'''
    public static ISelect<{TValue}> WhereLike<{TValue}>(this ISelect<{TValue}> query, Expression<Func<HzyTuple<{TValue}>, string>> filed, string value, bool isLike = false)
{TWhere}
        {{
            var valueExp = Expression.Constant(value);
            if (isLike)
            {{
                var method = typeof(string).GetMethod("Contains", new[] {{ typeof(string) }});
                query = query.Where(Expression.Lambda<Func<HzyTuple<{TValue}>, bool>>(Expression.Call(filed.Body, method, valueExp), filed.Parameters));
            }}
            else
            {{
                query = query.Where(Expression.Lambda<Func<HzyTuple<{TValue}>, bool>>(Expression.Equal(filed.Body, valueExp), filed.Parameters));
            }}

            return query;
        }}
    '''
    print(template)

def PrintNotHzyTuple(number):
    TValue = ', '.join(['T'+str(i+1) for i in range(number)])
    TWhere = ''
    for i in range(number-1):
        TWhere += f'            where T{str(i+2)} : class\n'
    template = f'''
    public static ISelect<{TValue}> WhereLike<{TValue}>(this ISelect<{TValue}> query, Expression<Func<{TValue}, string>> filed, string value, bool isLike = false)
{TWhere}
        {{
            var valueExp = Expression.Constant(value);
            if (isLike)
            {{
                var method = typeof(string).GetMethod("Contains", new[] {{ typeof(string) }});
                query = query.Where(Expression.Lambda<Func<{TValue}, bool>>(Expression.Call(filed.Body, method, valueExp), filed.Parameters));
            }}
            else
            {{
                query = query.Where(Expression.Lambda<Func<{TValue}, bool>>(Expression.Equal(filed.Body, valueExp),  filed.Parameters));
            }}

            return query;
        }}
    '''
    print(template)
def RunHzyTuple(num,start = 2):
    if start < num:
        PrintHzyTuple(start)
        start += 1
        RunHzyTuple(num,start)
    else:
        PrintHzyTuple(start)


def RunNotHzyTuple(num,start = 2):
    if start < num:
        PrintNotHzyTuple(start)
        start += 1
        RunNotHzyTuple(num,start)
    else:
        PrintNotHzyTuple(start)
if __name__=="__main__":
    print('''
        public static ISelect<T1> WhereLike<T1>(this ISelect<T1> query, Expression<Func<T1, string>> filed, string value, bool isLike = false) where T1 : class
        {
            var valueExp = Expression.Constant(value);
            if (isLike)
            {
                var method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
                query = query.Where(Expression.Lambda<Func<T1, bool>>(Expression.Call(filed.Body, method, valueExp), filed.Parameters));
            }
            else
            {
                query = query.Where(Expression.Lambda<Func<T1, bool>>(Expression.Equal(filed.Body, valueExp), filed.Parameters));
            }

            return query;
        }

''')
    print("        #region HzyTuple")
    RunHzyTuple(16)
    print("        #endregion\n\n")
    print("        #region Not HzyTuple")
    RunNotHzyTuple(16)
    print("        #endregion")


这篇关于C# Expression使用实践——为FreeSql增加WhereLike方法的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程