Files
Web_AUTSDATA_Mvc_Prod/AUTS.Services/Extensions/LinqExtensions.cs
2025-11-20 13:11:05 +08:00

470 lines
23 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
}
}