前端有一个是否模糊查询的参数,当未勾选时,所有字符串类型的值使用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))
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底层表达式解析可能不支持这种写法
开始大量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
以上表达式代码有一定规律,一个个写太费时间了,所以搞了个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")