You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

480 lines
15 KiB
C#

2 months ago

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using AddWhere;
namespace LinqDemo
{
public static class QueryBuilder
{
public static IQueryBuilder<T> Create<T>()
{
return new QueryBuilder<T>();
}
}
class QueryBuilder<T> : IQueryBuilder<T>
{
private Expression<Func<T, bool>> predicate;
Expression<Func<T, bool>> IQueryBuilder<T>.Expression
{
get
{
return predicate;
}
set
{
predicate = value;
}
}
//public List<ParameterExpression> Parameters { get; set; }
public QueryBuilder()
{
predicate = PredicateExtensions.True<T>();
//Parameters = new List<ParameterExpression>();
}
}
/// <summary>
/// 动态查询条件创建者
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IQueryBuilder<T>
{
Expression<Func<T, bool>> Expression { get; set; }
//List<ParameterExpression> Parameters { get; set; }
}
public static class IQueryBuilderExtensions
{
/// <summary>
/// 建立 Between 查询条件
/// </summary>
/// <typeparam name="T">实体</typeparam>
/// <param name="q">动态查询条件创建者</param>
/// <param name="property">属性</param>
/// <param name="from">开始值</param>
/// <param name="to">结束值</param>
/// <returns></returns>
public static IQueryBuilder<T> Between<T, P>(this IQueryBuilder<T> q, Expression<Func<T, P>> property, P from, P to)
{
var parameter = property.GetParameters();
var constantFrom = Expression.Constant(from);
var constantTo = Expression.Constant(to);
Type type = typeof(P);
Expression nonNullProperty = property.Body;
//如果是Nullable<X>类型则转化成X类型
if (IsNullableType(type))
{
type = GetNonNullableType(type);
nonNullProperty = Expression.Convert(property.Body, type);
}
System.Linq.Expressions.BinaryExpression c1=null;
System.Linq.Expressions.BinaryExpression c2=null;
System.Linq.Expressions.BinaryExpression c=null;
if (from != null)
c1 = Expression.GreaterThanOrEqual(nonNullProperty, constantFrom);
if (to != null)
c2 = Expression.LessThanOrEqual(nonNullProperty, constantTo);
if(from !=null && to != null)
c = Expression.AndAlso(c1, c2);
if (from != null && to == null)
c = c1;
if (from == null && to != null)
c = c2;
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(c, parameter);
q.Expression = q.Expression.And(lambda);
return q;
}
/// <summary>
/// 建立 Like ( 模糊 ) 查询条件
/// </summary>
/// <typeparam name="T">实体</typeparam>
/// <param name="q">动态查询条件创建者</param>
/// <param name="property">属性</param>
/// <param name="value">查询值</param>
/// <returns></returns>
#region
public static IQueryBuilder<T> Like<T>(this IQueryBuilder<T> q, Expression<Func<T, string>> property, string value)
{
value = value.Trim();
if (!string.IsNullOrEmpty(value))
{
var parameter = property.GetParameters();
Expression<Func<T, bool>> lambda = null;
//MethodCallExpression methodExp = Expression.Call(property.Body,
// typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),
// Expression.Constant(value)
//);
var c = typeof(string).GetMethod("IndexOf", new[] { typeof(string) });
MethodCallExpression methodExp = Expression.Call(property.Body,
c,
Expression.Constant(value)
);
var condition = Expression.NotEqual(Expression.Convert(methodExp, typeof(int)), Expression.Constant(-1));
lambda = Expression.Lambda<Func<T, bool>>(condition, parameter);
//MethodCallExpression methodExp = Expression.Call(null, typeof(SqlMethods).GetMethod("Like",
// new Type[] { typeof(string), typeof(string) }), property.Body, constant);
//Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(methodExp, parameter);
//Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(methodExp, parameter);
q.Expression = q.Expression.And(lambda);
}
return q;
}
#endregion
/// <summary>
/// 建立 OrLike ( 模糊 ) 查询条件
/// </summary>
/// <typeparam name="T">实体</typeparam>
/// <param name="q">动态查询条件创建者</param>
/// <param name="property">属性</param>
/// <param name="value">查询值</param>
/// <returns></returns>
private static Expression<Func<T, bool>> OrLike<T>(this IQueryBuilder<T> q, Expression<Func<T, string>> property, string value)
{
#region
//List<Expression> Expressions = new List<Expression>();
var parameter = property.GetParameters();
Expression<Func<T, bool>> lambda = null;
if (!string.IsNullOrEmpty(value))
{
//var propertyBody = GetMemberExpression(q, property);
MethodCallExpression methodExp = Expression.Call(property.Body,
typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),
Expression.Constant(value)
//typeof(LinqToSqlShared).GetMethod("IndexOf", new[] { typeof(string) }), Expression.Constant(value)
);
//Expressions.Add(methodExp);
//var condition = Expression.GreaterThan(methodExp, Expression.Constant(0));
lambda = Expression.Lambda<Func<T, bool>>(methodExp, parameter);
}
//Expression<Func<T, bool>> lambda = null;
//if (Expressions.Count != 0)
//{
// Expression expression = Expressions.Aggregate((e1, e2) => Expression.Or(e1, e2));
// lambda = Expression.Lambda<Func<T, bool>>(expression, parameter);
// //q.Expression = q.Expression.And(lambda);
//}
return lambda;
#endregion
}
private static Expression<Func<T, bool>> OrCharIndex<T>(this IQueryBuilder<T> q, Expression<Func<T, string>> property, string value)
{
#region
var parameter = property.GetParameters();
Expression<Func<T, bool>> lambda = null;
if (!string.IsNullOrEmpty(value))
{
var c = typeof(string).GetMethod("IndexOf", new[] { typeof(string) });
MethodCallExpression methodExp = Expression.Call(property.Body,
c,
Expression.Constant(value)
);
var condition = Expression.NotEqual(Expression.Convert(methodExp, typeof(int)), Expression.Constant(-1));
lambda = Expression.Lambda<Func<T, bool>>(condition, parameter);
}
return lambda;
#endregion
}
/// <summary>
/// 建立 Equals ( 相等 ) 查询条件
/// </summary>
/// <typeparam name="T">实体</typeparam>
/// <param name="q">动态查询条件创建者</param>
/// <param name="property">属性</param>
/// <param name="value">查询值</param>
/// <returns></returns>
public static IQueryBuilder<T> Equals<T, P>(this IQueryBuilder<T> q, Expression<Func<T, P>> property, P value)
{
var parameter = property.GetParameters();
var constant = Expression.Constant(value);
Type type = typeof(P);
Expression nonNullProperty = property.Body;
//如果是Nullable<X>类型则转化成X类型
if (IsNullableType(type))
{
type = GetNonNullableType(type);
nonNullProperty = Expression.Convert(property.Body, type);
}
var methodExp = Expression.Equal(nonNullProperty, constant);
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(methodExp, parameter);
q.Expression = q.Expression.And(lambda);
return q;
}
/// <summary>
/// 建立 In 查询条件
/// </summary>
/// <typeparam name="T">实体</typeparam>
/// <param name="q">动态查询条件创建者</param>
/// <param name="property">属性</param>
/// <param name="valuse">查询值</param>
/// <returns></returns>
public static IQueryBuilder<T> In<T, P>(this IQueryBuilder<T> q, Expression<Func<T, P>> property, IEnumerable<P> values)
{
if (values != null )
{
var parameter = property.GetParameters();
var constant = Expression.Constant(values);
Type type = typeof(P);
Expression nonNullProperty = property.Body;
//如果是Nullable<X>类型则转化成X类型
if (IsNullableType(type))
{
type = GetNonNullableType(type);
nonNullProperty = Expression.Convert(property.Body, type);
}
Expression<Func<IEnumerable<P>, P, bool>> InExpression = (list, el) => list.Contains(el);
var methodExp = InExpression;
var invoke = Expression.Invoke(methodExp, constant, property.Body);
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(invoke, parameter);
q.Expression = q.Expression.And(lambda);
}
return q;
}
/// <summary>
/// 建立 NotIn 查询条件
/// </summary>
/// <typeparam name="T">实体</typeparam>
/// <param name="q">动态查询条件创建者</param>
/// <param name="property">属性</param>
/// <param name="valuse">查询值</param>
/// <returns></returns>
public static IQueryBuilder<T> NotIn<T, P>(this IQueryBuilder<T> q, Expression<Func<T, P>> property, IEnumerable<P> values)
{
if (values != null )
{
var parameter = property.GetParameters();
var constant = Expression.Constant(values);
Type type = typeof(P);
Expression nonNullProperty = property.Body;
//如果是Nullable<X>类型则转化成X类型
if (IsNullableType(type))
{
type = GetNonNullableType(type);
nonNullProperty = Expression.Convert(property.Body, type);
}
Expression<Func<IEnumerable<P>, P, bool>> InExpression = (list, el) => !list.Contains(el);
var methodExp = InExpression;
var invoke = Expression.Invoke(methodExp, constant, property.Body);
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(invoke, parameter);
q.Expression = q.Expression.And(lambda);
}
return q;
}
/// <summary>
/// FullText查询多字段 多字符串
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="q"></param>
/// <param name="expression">支持1 2 3 以空格作为分隔符</param>
/// <param name="properties">查询字段属性 o => o.xxx1,o => o.xxx2...</param>
/// <returns></returns>
public static IQueryBuilder<T> FullText<T>(this IQueryBuilder<T> q, string expression, List<Expression<Func<T, string>>> properties)
{
if (string.IsNullOrEmpty(expression))
return q;
if (properties == null || properties.Count() == 0 )
return q;
string[] es = expression.Split(' ');
List<Expression<Func<T, bool>>> lambda1 = new List<Expression<Func<T,bool>>>();
foreach (var str in es)
{
List<Expression<Func<T, bool>>> lambda2 = new List<Expression<Func<T,bool>>>();
foreach (var property in properties)
{
var a = q.OrCharIndex(property, str);
if(a != null)
lambda2.Add(a);
}
if (lambda2.Count != 0)
lambda1.Add(lambda2.Aggregate((e1, e2) => e1.Or(e2)));
}
//var b = lambda1.Aggregate((e1, e2) => e1.Or(e2));
//q.Expression = q.Expression.And(b);
foreach (var b in lambda1)
q.Expression = q.Expression.And(b);
return q;
}
private static ParameterExpression[] GetParameters<T, S>(this Expression<Func<T, S>> expr)
{
return expr.Parameters.ToArray();
}
static bool IsNullableType(Type type)
{
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
}
static Type GetNonNullableType(Type type)
{
return type.GetGenericArguments()[0];
//return IsNullableType(type) ? type.GetGenericArguments()[0] : type;
}
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (T element in source)
action(element);
}
//EF参数重写
//private static Expression GetMemberExpression<T, P>(IQueryBuilder<T> q, Expression<Func<T, P>> property)
//{
// if (q.Parameters == null || q.Parameters.Count == 0)
// {
// property.Parameters.ForEach(
// p =>
// {
// q.Parameters.Add(p);
// }
// );
// return property.Body;
// }
// ParameterExpressionVisitor visitor = new ParameterExpressionVisitor(q.Parameters[0]);
// Expression memberExpr = visitor.ChangeParameter(property.Body);
// return memberExpr;
//}
//public class ParameterExpressionVisitor : ExpressionVisitor
//{
// private ParameterExpression newParameterExpression;
// public ParameterExpressionVisitor(ParameterExpression p)
// {
// newParameterExpression = p;
// }
// public Expression ChangeParameter(Expression exp)
// {
// return Visit(exp);
// }
// protected override Expression VisitParameter(ParameterExpression p)
// {
// return newParameterExpression;
// }
//}
}
}