OpenAuth.Net/Infrastructure/DynamicLinq.cs
2024-06-13 20:19:40 +08:00

335 lines
12 KiB
C#
Raw Permalink 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.

// ***********************************************************************
// Assembly : FairUtility
// Author : Yubao Li
// Created : 08-18-2015
//
// Last Modified By : Yubao Li
// Last Modified On : 08-18-2015
// ***********************************************************************
// <copyright file="DynamicLinq.cs" company="">
// Copyright (c) . All rights reserved.
// </copyright>
// <summary>动态linq</summary>
// ***********************************************************************
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using SqlSugar;
namespace Infrastructure
{
public static class DynamicLinq
{
public static ParameterExpression CreateLambdaParam<T>(string name)
{
return Expression.Parameter(typeof(T), name);
}
/// <summary>
/// 创建linq表达示的body部分
/// </summary>
public static Expression GenerateBody<T>(this ParameterExpression param, Filter filterObj)
{
PropertyInfo property = typeof(T).GetProperty(filterObj.Key);
Expression left = null; //组装左边
//组装右边
Expression right = null;
if (property != null)
{
left = Expression.Property(param, property);
if (property.PropertyType == typeof(int))
{
right = Expression.Constant(int.Parse(filterObj.Value));
}
else if (property.PropertyType == typeof(DateTime))
{
right = Expression.Constant(DateTime.Parse(filterObj.Value));
}
else if (property.PropertyType == typeof(string))
{
right = Expression.Constant(filterObj.Value);
}
else if (property.PropertyType == typeof(decimal))
{
right = Expression.Constant(decimal.Parse(filterObj.Value));
}
else if (property.PropertyType == typeof(Guid))
{
right = Expression.Constant(Guid.Parse(filterObj.Value));
}
else if (property.PropertyType == typeof(bool))
{
right = Expression.Constant(filterObj.Value.Equals("1"));
}
else if (property.PropertyType == typeof(Guid?))
{
left = Expression.Property(left, "Value");
right = Expression.Constant(Guid.Parse(filterObj.Value));
}
else
{
throw new Exception("暂不能解析该Key的类型");
}
}
else //如果左边不是属性,直接是值的情况
{
left = Expression.Constant(filterObj.Key);
right = Expression.Constant(filterObj.Value);
}
//c.XXX=="XXX"
Expression filter = Expression.Equal(left, right);
switch (filterObj.Contrast)
{
case "<=":
filter = Expression.LessThanOrEqual(left, right);
break;
case "<":
filter = Expression.LessThan(left, right);
break;
case ">":
filter = Expression.GreaterThan(left, right);
break;
case ">=":
filter = Expression.GreaterThanOrEqual(left, right);
break;
case "!=":
filter = Expression.NotEqual(left, right);
break;
case "contains":
filter = Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] {typeof(string)}),
Expression.Constant(filterObj.Value));
break;
case "in":
var lExp = Expression.Constant(filterObj.Value.Split(',').ToList()); //数组
var methodInfo = typeof(List<string>).GetMethod("Contains",
new Type[] {typeof(string)}); //Contains语句
filter = Expression.Call(lExp, methodInfo, left);
break;
case "not in":
var listExpression = Expression.Constant(filterObj.Value.Split(',').ToList()); //数组
var method = typeof(List<string>).GetMethod("Contains", new Type[] {typeof(string)}); //Contains语句
filter = Expression.Not(Expression.Call(listExpression, method, left));
break;
//交集,使用交集时左值必须时固定的值
case "intersect": //交集
if (property != null)
{
throw new Exception("交集模式下,表达式左边不能为变量,请调整数据规则,如:c=>\"A,B,C\" intersect \"B,D\"");
}
var rightval = filterObj.Value.Split(',').ToList();
var leftval = filterObj.Key.Split(',').ToList();
var val = rightval.Intersect(leftval);
filter = Expression.Constant(val.Count() > 0);
break;
}
return filter;
}
public static Expression<Func<T, bool>> GenerateTypeBody<T>(this ParameterExpression param, Filter filterObj)
{
return (Expression<Func<T, bool>>) (param.GenerateBody<T>(filterObj));
}
/// <summary>
/// 创建完整的lambda
/// </summary>
public static LambdaExpression GenerateLambda(this ParameterExpression param, Expression body)
{
//c=>c.XXX=="XXX"
return Expression.Lambda(body, param);
}
public static Expression<Func<T, bool>> GenerateTypeLambda<T>(this ParameterExpression param, Expression body)
{
return (Expression<Func<T, bool>>) (param.GenerateLambda(body));
}
public static Expression AndAlso(this Expression expression, Expression expressionRight)
{
return Expression.AndAlso(expression, expressionRight);
}
public static Expression Or(this Expression expression, Expression expressionRight)
{
return Expression.Or(expression, expressionRight);
}
public static Expression And(this Expression expression, Expression expressionRight)
{
return Expression.And(expression, expressionRight);
}
public static IQueryable<T> GenerateFilter<T>(this IQueryable<T> query, string parametername, string filterjson)
{
if (!string.IsNullOrEmpty(filterjson))
{
var filterGroup = JsonHelper.Instance.Deserialize<QueryObject>(filterjson);
query = GenerateFilter(query, parametername, filterGroup);
}
return query;
}
public static ISugarQueryable<T> GenerateFilter<T>(this ISugarQueryable<T> query, string parametername, string filterjson)
{
if (!string.IsNullOrEmpty(filterjson))
{
var filterGroup = JsonHelper.Instance.Deserialize<QueryObject>(filterjson);
query = GenerateFilter(query, parametername, filterGroup);
}
return query;
}
/// <summary>
/// 转换FilterGroup为Lambda表达式
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="query"></param>
/// <param name="parametername"></param>
/// <param name="queryObject"></param>
/// <returns></returns>
public static IQueryable<T> GenerateFilter<T>(this IQueryable<T> query, string parametername,
QueryObject queryObject)
{
var param = CreateLambdaParam<T>(parametername);
Expression result = ConvertGroup<T>(queryObject, param);
query = query.Where(param.GenerateTypeLambda<T>(result));
return query;
}
/// <summary>
/// 转换FilterGroup为Lambda表达式
/// </summary>
/// <param name="query"></param>
/// <param name="parametername"></param>
/// <param name="queryObject"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static ISugarQueryable<T> GenerateFilter<T>(this ISugarQueryable<T> query, string parametername,
QueryObject queryObject)
{
var param = CreateLambdaParam<T>(parametername);
Expression result = ConvertGroup<T>(queryObject, param);
query = query.Where(param.GenerateTypeLambda<T>(result));
return query;
}
/// <summary>
/// 转换filtergroup为表达式
/// </summary>
/// <param name="queryObject"></param>
/// <param name="param"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static Expression ConvertGroup<T>(QueryObject queryObject, ParameterExpression param)
{
if (queryObject == null) return null;
if (queryObject.Filters.Length == 1 &&(queryObject.Children == null || !queryObject.Children.Any())) //只有一个条件
{
return param.GenerateBody<T>(queryObject.Filters[0]);
}
Expression result = ConvertFilters<T>(queryObject.Filters, param, queryObject.Operation);
Expression gresult = ConvertGroup<T>(queryObject.Children, param, queryObject.Operation);
if (gresult == null) return result;
if (result == null) return gresult;
if (queryObject.Operation == "and")
{
return result.AndAlso(gresult);
}
else //or
{
return Expression.OrElse( result, gresult);
}
}
/// <summary>
/// 转换FilterGroup[]为表达式不管FilterGroup里面的Filters
/// </summary>
/// <param name="queryObjs"></param>
/// <param name="param"></param>
/// <param name="operation"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
private static Expression ConvertGroup<T>(QueryObject[] queryObjs, ParameterExpression param, string operation)
{
if (queryObjs == null || !queryObjs.Any()) return null;
Expression result = ConvertGroup<T>(queryObjs[0], param);
if (queryObjs.Length == 1) return result;
if (operation == "and")
{
foreach (var filter in queryObjs.Skip(1))
{
result = result.AndAlso(ConvertGroup<T>(filter, param));
}
}
else
{
foreach (var filter in queryObjs.Skip(1))
{
result = Expression.OrElse(result, ConvertGroup<T>(filter, param));
}
}
return result;
}
/// <summary>
/// 转换Filter数组为表达式
/// </summary>
/// <param name="filters"></param>
/// <param name="param"></param>
/// <param name="operation"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
private static Expression ConvertFilters<T>(Filter[] filters, ParameterExpression param, string operation)
{
if (filters == null || !filters.Any())
{
return null;
}
Expression result = param.GenerateBody<T>(filters[0]);
if (filters.Length == 1)
{
return result;
}
if (operation == "and")
{
foreach (var filter in filters.Skip(1))
{
result = result.AndAlso(param.GenerateBody<T>(filter));
}
}
else
{
foreach (var filter in filters.Skip(1))
{
result = Expression.OrElse(result, param.GenerateBody<T>(filter));
}
}
return result;
}
}
}