Files
Web_Faces_Prod/Face.Services/Extensions/LinqExtensions.cs

470 lines
23 KiB
C#
Raw Normal View History

2025-11-25 17:41:24 +08:00
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq.Expressions;
using System.Reflection;
namespace System.Linq
{
public static class LinqExtensions
{
/// <summary>通过页面控件动态构建查询</summary>
public static IQueryable<TSource> WhereDynamic<TSource>(this IQueryable<TSource> source,
NameValueCollection nameValues) where TSource : class
{
if (nameValues.Count > 0)
{
//构建 c=>Body中的c
ParameterExpression param = Expression.Parameter(typeof(TSource), "c");
//构建c=>Body中的Body
var body = GetExpressoinBody(param, nameValues);
if (body != null)
{
//将二者拼为c=>Body
var expression = Expression.Lambda<Func<TSource, bool>>(body, param);
//传到Where中当做参数类型为Expression<Func<T,bool>>
return source.Where(expression);
}
}
return source;
}
/// <summary>构建body</summary>
private static Expression GetExpressoinBody(ParameterExpression param, NameValueCollection nameValues)
{
var list = new List<Expression>();
if (nameValues.Count > 0)
{
var plist = param.Type.GetRuntimeProperties().ToDictionary(z => z.Name);//可以加缓存改善性能
foreach (var item in nameValues.AllKeys)
if (item.EndsWith(">") || item.EndsWith(">="))//可能大小查询
{
bool isEqual = item.EndsWith(">=");
string key = isEqual ? item.TrimEnd('=').TrimEnd('>') : item.TrimEnd('>');
if (!plist.ContainsKey(key) || nameValues[item].Length <= 0) continue;
var rType = plist[key].GetMethod.ReturnType;
if (rType == typeof(string)) continue;
var e1 = Expression.Property(param, key);
object dValue;
if (TryParser(nameValues[item], rType, out dValue))
//list.Add(Expression.GreaterThan(e1, Expression.Constant(dValue, rType)));
list.Add(AddGreaterGreaterThan(e1, Expression.Constant(dValue, rType), isEqual));
else if (plist[key].GetMethod.ReturnType.GenericTypeArguments.Count() > 0 && TryParser(nameValues[item], plist[key].GetMethod.ReturnType.GenericTypeArguments[0], out dValue))
//list.Add(Expression.GreaterThan(e1, Expression.Constant(dValue, rType)));
list.Add(AddGreaterGreaterThan(e1, Expression.Constant(dValue, rType), isEqual));
else if (rType == typeof(DateTime?))
{
DateTime enddate = nameValues[item].ToDateTime().GetValueOrDefault();
//list.Add(Expression.GreaterThan(e1, Expression.Constant(enddate, typeof(DateTime?))));
list.Add(AddGreaterGreaterThan(e1, Expression.Constant(enddate, typeof(DateTime?)), isEqual));
}
}
else if (item.EndsWith("<") || item.EndsWith("<="))//可能大小查询
{
bool isEqual = item.EndsWith("<=");
string key = isEqual ? item.TrimEnd('=').TrimEnd('<') : item.TrimEnd('<');
if (!plist.ContainsKey(key) || nameValues[item].Length <= 0) continue;
var rType = plist[key].GetMethod.ReturnType;
if (rType == typeof(string)) continue;
var e1 = Expression.Property(param, key);
object dValue;
if (TryParser(nameValues[item], rType, out dValue))
{
if (rType == typeof(DateTime)) dValue = ((DateTime)dValue).AddDays(1);
//list.Add(Expression.LessThan(e1, Expression.Constant(dValue, rType)));
list.Add(AddGreaterLessThan(e1, Expression.Constant(dValue, rType), isEqual));
}
else if (plist[key].GetMethod.ReturnType.GenericTypeArguments.Count() > 0 && TryParser(nameValues[item], plist[key].GetMethod.ReturnType.GenericTypeArguments[0], out dValue))
{
if (plist[key].GetMethod.ReturnType.GenericTypeArguments[0] == typeof(DateTime)) dValue = ((DateTime)dValue).AddDays(1);
//list.Add(Expression.LessThan(e1, Expression.Constant(dValue, rType)));
list.Add(AddGreaterLessThan(e1, Expression.Constant(dValue, rType), isEqual));
}
else if (rType == typeof(DateTime?))
{
DateTime enddate = nameValues[item].ToDateTime().GetValueOrDefault().AddDays(1);
//list.Add(Expression.LessThan(e1, Expression.Constant(enddate, typeof(DateTime?))));
list.Add(AddGreaterLessThan(e1, Expression.Constant(enddate, typeof(DateTime?)), isEqual));
}
}
else if (plist.ContainsKey(item) && nameValues[item].Length > 0)
{
var e1 = Expression.Property(param, item);
var rType = plist[item].GetMethod.ReturnType;
if (rType == typeof(string))//可能是like查询
{
var value = nameValues[item].Trim('%');
var e2 = Expression.Constant(value, rType);
if (nameValues[item].StartsWith("%") && nameValues[item].EndsWith("%"))
list.Add(Expression.Call(e1, "Contains", null, new Expression[] { e2 }));
else if (nameValues[item].StartsWith("%"))
list.Add(Expression.Call(e1, "EndsWith", null, new Expression[] { e2 }));
else if (nameValues[item].EndsWith("%"))
list.Add(Expression.Call(e1, "StartsWith", null, new Expression[] { e2 }));
else
list.Add(Expression.Equal(e1, e2));
}
else if (nameValues[item].IndexOf(",") > 0)//可能是in查询
{
if (rType == typeof(short))
{
var searchList = TryParser<short>(nameValues[item]);
if (searchList.Any())
list.Add(Expression.Call(Expression.Constant(searchList, rType), "Contains", null, new Expression[] { e1 }));
}
else if (rType == typeof(int))
{
var searchList = TryParser<int>(nameValues[item]);
if (searchList.Any())
list.Add(Expression.Call(Expression.Constant(searchList, rType), "Contains", null, new Expression[] { e1 }));
}
else if (rType == typeof(long))
{
var searchList = TryParser<long>(nameValues[item]);
if (searchList.Any())
list.Add(Expression.Call(Expression.Constant(searchList, rType), "Contains", null, new Expression[] { e1 }));
}
}
else
{
object dValue;
if (TryParser(nameValues[item], rType, out dValue))
list.Add(Expression.Equal(e1, Expression.Constant(dValue, rType)));
}
}
}
return list.Count > 0 ? list.Aggregate(Expression.AndAlso) : null;
}
private static List<T> TryParser<T>(string value)
{
string[] searchArray = value.Split(',');
List<T> dList = new List<T>();
foreach (var l in searchArray)
{
try
{
T dValue = (T)Convert.ChangeType(l, typeof(T));
dList.Add(dValue);
}
catch { }
}
return dList;
}
private static bool TryParser(string value, Type outType, out object dValue)
{
try
{
dValue = Convert.ChangeType(value, outType);
return true;
}
catch
{
dValue = null;
return false;
}
}
//大于
private static Expression AddGreaterGreaterThan(Expression exleft, Expression exright, bool Equal)
{
if (Equal)
{
return Expression.GreaterThanOrEqual(exleft, exright);
}
else
{
return Expression.GreaterThan(exleft, exright);
}
}
//大于
private static Expression AddGreaterLessThan(Expression exleft, Expression exright, bool Equal)
{
if (Equal)
{
return Expression.LessThanOrEqual(exleft, exright);
}
else
{
return Expression.LessThan(exleft, exright);
}
}
/// <summary>
/// 从 System.Collections.Generic.IQueryable`1 创建一个 System.Collections.Generic.List`1。并在集合末尾添加一个默认值为空的TSource实例
/// </summary>
/// <typeparam name="TSource">source 中的元素的类型。</typeparam>
/// <param name="source">要从其创建 System.Collections.Generic.List`1 的 System.Collections.Generic.IEnumerable`1。</param>
/// <returns>一个包含输入序列中元素的 System.Collections.Generic.List`1。</returns>
public static List<TSource> ToListAndAddEmpty<TSource>(this IQueryable<TSource> source) where TSource : class
{
List<TSource> list = source.ToList();
TSource addmodel = Activator.CreateInstance<TSource>();
list.Add(addmodel);
return list;
}
/// <summary>
/// 从 System.Collections.Generic.IEnumerable`1 创建一个 System.Collections.Generic.List`1。并在集合末尾添加一个默认值为空的TSource实例
/// </summary>
/// <typeparam name="TSource">source 中的元素的类型。</typeparam>
/// <param name="source">要从其创建 System.Collections.Generic.List`1 的 System.Collections.Generic.IEnumerable`1。</param>
/// <returns>一个包含输入序列中元素的 System.Collections.Generic.List`1。</returns>
public static List<TSource> ToListAndAddEmpty<TSource>(this IEnumerable<TSource> source) where TSource : class
{
List<TSource> list = source.ToList();
TSource addmodel = Activator.CreateInstance<TSource>();
list.Add(addmodel);
return list;
}
/// <summary>
/// 动态模糊查询
/// </summary>
/// <typeparam name="TSource">source 中的元素的类型。</typeparam>
/// <param name="source">一个要模糊查找的值序列。</param>
/// <typeparam name="TKey">由 keySelector 表示的函数返回的键类型。</typeparam>
/// <param name="keyword">查询关键字(动态模糊在首或尾部添加%)</param>
/// <param name="keyfiled">查询字段</param>
/// <param name="keySelector">查询字段Lamvda表达式(支持多表导航查询)</param>
/// <returns>一个 System.Linq.IOrderedQueryable`1根据键对其元素模糊查找。</returns>
public static IQueryable<TSource> LikeQueryable<TSource, TKey>(this IQueryable<TSource> source, string keyword, params Expression<Func<TSource, TKey>>[] keySelector)
{
try
{
var paramT = Expression.Parameter(typeof(TSource), "c");//c=>
Expression body = null;
var list = new List<Expression>();
foreach (var item in keySelector)
{
string[] paramKs = item.Body.ToString().Split('.');
var e1 = Expression.Property(paramT, paramKs[1]);//c.user
for (int i = 2; i < paramKs.Count(); i++)
{
e1 = Expression.Property(e1, paramKs[i]);//c.user.ID
}
if (e1.Type == typeof(string))
{
var value = keyword.Trim('%');
var e2 = Expression.Constant(value, typeof(string));
if (keyword.StartsWith("%") && keyword.EndsWith("%"))
list.Add(Expression.Call(e1, "Contains", null, new Expression[] { e2 }));
else if (keyword.StartsWith("%"))
list.Add(Expression.Call(e1, "EndsWith", null, new Expression[] { e2 }));
else if (keyword.EndsWith("%"))
list.Add(Expression.Call(e1, "StartsWith", null, new Expression[] { e2 }));
else
list.Add(Expression.Equal(e1, e2));
}
}
body = list.Count > 0 ? list.Aggregate(Expression.OrElse) : null;
//构建c=>Body中的Body
if (body != null)
{
//将二者拼为c=>Body
var expression = Expression.Lambda<Func<TSource, bool>>(body, paramT);
//传到Where中当做参数类型为Expression<Func<T,bool>>
source = source.Where(expression);
}
}
catch
{
}
return source;
}
/// <summary>
/// 动态模糊查询
/// </summary>
/// <typeparam name="TSource">source 中的元素的类型。</typeparam>
/// <param name="source">一个要模糊查找的值序列。</param>
/// <param name="keyword">查询关键字(动态模糊在首或尾部添加%)</param>
/// <param name="keyfiled">查询字段</param>
/// <param name="keySelector">查询字段Lamvda表达式(支持多表导航查询)</param>
/// <returns>一个 System.Linq.IOrderedQueryable`1根据键对其元素模糊查找。</returns>
public static IQueryable<TSource> LikeQueryable<TSource>(this IQueryable<TSource> source, string keyword, params string[] keyfiled)
{
try
{
var paramT = Expression.Parameter(typeof(TSource), "c");//c=>
Expression body = null;
var list = new List<Expression>();
foreach (var item in keyfiled)
{
string[] paramKs = item.Split('.');
var e1 = Expression.Property(paramT, paramKs[0]);//c.user
for (int i = 1; i < paramKs.Count(); i++)
{
e1 = Expression.Property(e1, paramKs[i]);//c.user.ID
}
if (e1.Type == typeof(string))
{
var value = keyword.Trim('%');
var e2 = Expression.Constant(value, typeof(string));
if (keyword.StartsWith("%") && keyword.EndsWith("%"))
list.Add(Expression.Call(e1, "Contains", null, new Expression[] { e2 }));
else if (keyword.StartsWith("%"))
list.Add(Expression.Call(e1, "EndsWith", null, new Expression[] { e2 }));
else if (keyword.EndsWith("%"))
list.Add(Expression.Call(e1, "StartsWith", null, new Expression[] { e2 }));
else
list.Add(Expression.Equal(e1, e2));
}
}
body = list.Count > 0 ? list.Aggregate(Expression.OrElse) : null;
//构建c=>Body中的Body
if (body != null)
{
//将二者拼为c=>Body
var expression = Expression.Lambda<Func<TSource, bool>>(body, paramT);
//传到Where中当做参数类型为Expression<Func<T,bool>>
source = source.Where(expression);
}
}
catch
{
}
return source;
}
/// <summary>
/// 外键表动态模糊查询
/// </summary>
/// <typeparam name="TSource">source 中的元素的类型。</typeparam>
/// <param name="source">一个要模糊查找的值序列。</param>
/// <typeparam name="TKey">由 keySelector 表示的函数返回的键类型。</typeparam>
/// <param name="keyword">查询关键字(动态模糊在首或尾部添加%)</param>
/// <param name="keyfiledn">查询字段</param>
/// <param name="keySelector">查询字段Lamvda表达式(支持多表导航查询)</param>
/// <returns>一个 System.Linq.IOrderedQueryable`1根据键对其元素模糊查找。</returns>
public static IQueryable<TSource> LikeQueryable<TSource, TKey>(this IQueryable<TSource> source, string keyword, string keyfiled, params Expression<Func<TSource, TKey>>[] keySelector)
{
try
{
var paramT = Expression.Parameter(typeof(TSource), "c");//c=>
Expression body = null;
var list = new List<Expression>();
foreach (var item in keySelector)
{
string[] paramKs = item.Body.ToString().Split('.');
var e1 = Expression.Property(paramT, paramKs[1]);//c.user
for (int i = 2; i < paramKs.Count(); i++)
{
e1 = Expression.Property(e1, paramKs[i]);//c.user.ID
}
e1 = Expression.Property(e1, keyfiled);//c.user.ID
if (e1.Type == typeof(string))
{
var value = keyword.Trim('%');
var e2 = Expression.Constant(value, typeof(string));
if (keyword.StartsWith("%") && keyword.EndsWith("%"))
list.Add(Expression.Call(e1, "Contains", null, new Expression[] { e2 }));
else if (keyword.StartsWith("%"))
list.Add(Expression.Call(e1, "EndsWith", null, new Expression[] { e2 }));
else if (keyword.EndsWith("%"))
list.Add(Expression.Call(e1, "StartsWith", null, new Expression[] { e2 }));
else
list.Add(Expression.Equal(e1, e2));
}
}
body = list.Count > 0 ? list.Aggregate(Expression.OrElse) : null;
//构建c=>Body中的Body
if (body != null)
{
//将二者拼为c=>Body
var expression = Expression.Lambda<Func<TSource, bool>>(body, paramT);
//传到Where中当做参数类型为Expression<Func<T,bool>>
source = source.Where(expression);
}
}
catch
{
}
return source;
}
/// <summary>
/// 动态排序
/// </summary>
/// <typeparam name="TSource">source 中的元素的类型。</typeparam>
/// <param name="source">一个要排序查找的值序列。</param>
/// <param name="keyfiled">排序字段</param>
/// <param name="type">排序类型0不排序1升序2降序</param>
/// <returns>一个 System.Linq.IOrderedQueryable`1根据键对其元素模糊查找。</returns>
public static IQueryable<TSource> OrderByQueryable<TSource>(this IQueryable<TSource> source, string keyfiled, int type)
{
try
{
if (type == 0) return source;//不排序
var paramT = Expression.Parameter(typeof(TSource), "c");//c=>
string[] paramKs = keyfiled.Split('.');
var e1 = Expression.Property(paramT, paramKs[0]);//c.user
for (int i = 1; i < paramKs.Count(); i++)
{
e1 = Expression.Property(e1, paramKs[i]);//c.user.ID
}
dynamic expression = Expression.Lambda(e1, paramT);
switch (type)
{
case 1:
source = Queryable.OrderBy(source, expression);
break;
case 2:
source = Queryable.OrderByDescending(source, expression);
break;
default:
break;
}
}
catch
{
}
return source;
}
/// <summary>
/// 动态排序
/// </summary>
/// <typeparam name="TSource">source 中的元素的类型。</typeparam>
/// <param name="source">一个要排序查找的值序列。</param>
/// <param name="keyfiled">排序字段</param>
/// <param name="type">排序类型0不排序1升序2降序</param>
/// <returns>一个 System.Linq.IOrderedQueryable`1根据键对其元素模糊查找。</returns>
public static IEnumerable<TSource> OrderByQueryable<TSource>(this IEnumerable<TSource> source, string keyfiled, int type)
{
try
{
if (type == 0) return source;//不排序
var paramT = Expression.Parameter(typeof(TSource), "c");//c=>
string[] paramKs = keyfiled.Split('.');
var e1 = Expression.Property(paramT, paramKs[0]);//c.user
for (int i = 1; i < paramKs.Count(); i++)
{
e1 = Expression.Property(e1, paramKs[i]);//c.user.ID
}
dynamic expression = Expression.Lambda(e1, paramT);
switch (type)
{
case 1:
source = Queryable.OrderBy(source.AsQueryable(), expression);
break;
case 2:
source = Queryable.OrderByDescending(source.AsQueryable(), expression);
break;
default:
break;
}
}
catch
{
}
return source;
}
}
}