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#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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;
// }
//}
}
}