初始提交
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Hncore.Infrastructure.EntitiesExtension
|
||||
{
|
||||
public class CommonEqualityComparer<T, V> : IEqualityComparer<T>
|
||||
{
|
||||
private Func<T, V> keySelector;
|
||||
private IEqualityComparer<V> comparer;
|
||||
|
||||
public CommonEqualityComparer(Func<T, V> keySelector, IEqualityComparer<V> comparer)
|
||||
{
|
||||
this.keySelector = keySelector;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public CommonEqualityComparer(Func<T, V> keySelector)
|
||||
: this(keySelector, EqualityComparer<V>.Default)
|
||||
{ }
|
||||
|
||||
public bool Equals(T x, T y)
|
||||
{
|
||||
return comparer.Equals(keySelector(x), keySelector(y));
|
||||
}
|
||||
|
||||
public int GetHashCode(T obj)
|
||||
{
|
||||
return comparer.GetHashCode(keySelector(obj));
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 扩展类
|
||||
/// </summary>
|
||||
public static class DistinctExtensions
|
||||
{
|
||||
public static IEnumerable<T> Distinctx<T, V>(this IEnumerable<T> source, Func<T, V> keySelector)
|
||||
{
|
||||
return source.Distinct(new CommonEqualityComparer<T, V>(keySelector));
|
||||
}
|
||||
|
||||
public static IEnumerable<T> Distinctx<T, V>(this IEnumerable<T> source, Func<T, V> keySelector, IEqualityComparer<V> comparer)
|
||||
{
|
||||
return source.Distinct(new CommonEqualityComparer<T, V>(keySelector, comparer));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Hncore.Infrastructure.EntitiesExtension
|
||||
{
|
||||
internal class ConditionBuilder : ExpressionVisitor
|
||||
{
|
||||
private List<object> m_arguments;
|
||||
private Stack<string> m_conditionParts;
|
||||
|
||||
public string Condition { get; private set; }
|
||||
|
||||
public object[] Arguments { get; private set; }
|
||||
|
||||
public void Build(Expression expression)
|
||||
{
|
||||
PartialEvaluator evaluator = new PartialEvaluator();
|
||||
Expression evaluatedExpression = evaluator.Eval(expression);
|
||||
|
||||
this.m_arguments = new List<object>();
|
||||
this.m_conditionParts = new Stack<string>();
|
||||
|
||||
this.Visit(evaluatedExpression);
|
||||
|
||||
this.Arguments = this.m_arguments.ToArray();
|
||||
this.Condition = this.m_conditionParts.Count > 0 ? this.m_conditionParts.Pop() : null;
|
||||
}
|
||||
|
||||
protected override Expression VisitBinary(BinaryExpression b)
|
||||
{
|
||||
if (b == null) return b;
|
||||
|
||||
string opr;
|
||||
switch (b.NodeType)
|
||||
{
|
||||
case ExpressionType.Equal:
|
||||
opr = "=";
|
||||
break;
|
||||
case ExpressionType.NotEqual:
|
||||
opr = "<>";
|
||||
break;
|
||||
case ExpressionType.GreaterThan:
|
||||
opr = ">";
|
||||
break;
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
opr = ">=";
|
||||
break;
|
||||
case ExpressionType.LessThan:
|
||||
opr = "<";
|
||||
break;
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
opr = "<=";
|
||||
break;
|
||||
case ExpressionType.AndAlso:
|
||||
opr = "AND";
|
||||
break;
|
||||
case ExpressionType.OrElse:
|
||||
opr = "OR";
|
||||
break;
|
||||
case ExpressionType.Add:
|
||||
opr = "+";
|
||||
break;
|
||||
case ExpressionType.Subtract:
|
||||
opr = "-";
|
||||
break;
|
||||
case ExpressionType.Multiply:
|
||||
opr = "*";
|
||||
break;
|
||||
case ExpressionType.Divide:
|
||||
opr = "/";
|
||||
break;
|
||||
default:
|
||||
throw new NotSupportedException(b.NodeType + "is not supported.");
|
||||
}
|
||||
|
||||
this.Visit(b.Left);
|
||||
this.Visit(b.Right);
|
||||
|
||||
string right = this.m_conditionParts.Pop();
|
||||
string left = this.m_conditionParts.Pop();
|
||||
|
||||
string condition = String.Format("({0} {1} {2})", left, opr, right);
|
||||
this.m_conditionParts.Push(condition);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
protected override Expression VisitConstant(ConstantExpression c)
|
||||
{
|
||||
if (c == null) return c;
|
||||
|
||||
this.m_arguments.Add(c.Value);
|
||||
this.m_conditionParts.Push(String.Format("{{{0}}}", this.m_arguments.Count - 1));
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
protected override Expression VisitMemberAccess(MemberExpression m)
|
||||
{
|
||||
if (m == null) return m;
|
||||
|
||||
PropertyInfo propertyInfo = m.Member as PropertyInfo;
|
||||
if (propertyInfo == null) return m;
|
||||
|
||||
this.m_conditionParts.Push(String.Format("[{0}]", propertyInfo.Name));
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
protected override Expression VisitMethodCall(MethodCallExpression m)
|
||||
{
|
||||
if (m == null) return m;
|
||||
|
||||
string format;
|
||||
switch (m.Method.Name)
|
||||
{
|
||||
case "StartsWith":
|
||||
format = "({0} LIKE {1}+'%')";
|
||||
break;
|
||||
|
||||
case "Contains":
|
||||
format = "({0} LIKE '%'+{1}+'%')";
|
||||
break;
|
||||
|
||||
case "EndsWith":
|
||||
format = "({0} LIKE '%'+{1})";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(m.NodeType + " is not supported!");
|
||||
}
|
||||
|
||||
this.Visit(m.Object);
|
||||
this.Visit(m.Arguments[0]);
|
||||
string right = this.m_conditionParts.Pop();
|
||||
string left = this.m_conditionParts.Pop();
|
||||
this.m_conditionParts.Push(String.Format(format, left, right));
|
||||
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Hncore.Infrastructure.EntitiesExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for add And and Or with parameters rebinder
|
||||
/// </summary>
|
||||
public static class ExpressionBuilder
|
||||
{
|
||||
/// <summary>
|
||||
/// Compose two expression and merge all in a new expression
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of params in expression</typeparam>
|
||||
/// <param name="first">Expression instance</param>
|
||||
/// <param name="second">Expression to merge</param>
|
||||
/// <param name="merge">Function to merge</param>
|
||||
/// <returns>New merged expressions</returns>
|
||||
public static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
|
||||
{
|
||||
// build parameter map (from parameters of second to parameters of first)
|
||||
var map = first.Parameters.Select((f, i) => new { f, s = second.Parameters[i] }).ToDictionary(p => p.s, p => p.f);
|
||||
|
||||
// replace parameters in the second lambda expression with parameters from the first
|
||||
var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);
|
||||
// apply composition of lambda expression bodies to parameters from the first expression
|
||||
return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
|
||||
}
|
||||
/// <summary>
|
||||
/// And operator
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of params in expression</typeparam>
|
||||
/// <param name="first">Right Expression in AND operation</param>
|
||||
/// <param name="second">Left Expression in And operation</param>
|
||||
/// <returns>New AND expression</returns>
|
||||
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
|
||||
{
|
||||
return first.Compose(second, Expression.AndAlso);
|
||||
}
|
||||
/// <summary>
|
||||
/// Or operator
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of param in expression</typeparam>
|
||||
/// <param name="first">Right expression in OR operation</param>
|
||||
/// <param name="second">Left expression in OR operation</param>
|
||||
/// <returns>New Or expressions</returns>
|
||||
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
|
||||
{
|
||||
return first.Compose(second, Expression.Or);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Hncore.Infrastructure.EntitiesExtension
|
||||
{
|
||||
public abstract class ExpressionVisitor
|
||||
{
|
||||
protected ExpressionVisitor() { }
|
||||
|
||||
protected virtual Expression Visit(Expression exp)
|
||||
{
|
||||
if (exp == null)
|
||||
return exp;
|
||||
switch (exp.NodeType)
|
||||
{
|
||||
case ExpressionType.Negate:
|
||||
case ExpressionType.NegateChecked:
|
||||
case ExpressionType.Not:
|
||||
case ExpressionType.Convert:
|
||||
case ExpressionType.ConvertChecked:
|
||||
case ExpressionType.ArrayLength:
|
||||
case ExpressionType.Quote:
|
||||
case ExpressionType.TypeAs:
|
||||
return this.VisitUnary((UnaryExpression)exp);
|
||||
case ExpressionType.Add:
|
||||
case ExpressionType.AddChecked:
|
||||
case ExpressionType.Subtract:
|
||||
case ExpressionType.SubtractChecked:
|
||||
case ExpressionType.Multiply:
|
||||
case ExpressionType.MultiplyChecked:
|
||||
case ExpressionType.Divide:
|
||||
case ExpressionType.Modulo:
|
||||
case ExpressionType.And:
|
||||
case ExpressionType.AndAlso:
|
||||
case ExpressionType.Or:
|
||||
case ExpressionType.OrElse:
|
||||
case ExpressionType.LessThan:
|
||||
case ExpressionType.LessThanOrEqual:
|
||||
case ExpressionType.GreaterThan:
|
||||
case ExpressionType.GreaterThanOrEqual:
|
||||
case ExpressionType.Equal:
|
||||
case ExpressionType.NotEqual:
|
||||
case ExpressionType.Coalesce:
|
||||
case ExpressionType.ArrayIndex:
|
||||
case ExpressionType.RightShift:
|
||||
case ExpressionType.LeftShift:
|
||||
case ExpressionType.ExclusiveOr:
|
||||
return this.VisitBinary((BinaryExpression)exp);
|
||||
case ExpressionType.TypeIs:
|
||||
return this.VisitTypeIs((TypeBinaryExpression)exp);
|
||||
case ExpressionType.Conditional:
|
||||
return this.VisitConditional((ConditionalExpression)exp);
|
||||
case ExpressionType.Constant:
|
||||
return this.VisitConstant((ConstantExpression)exp);
|
||||
case ExpressionType.Parameter:
|
||||
return this.VisitParameter((ParameterExpression)exp);
|
||||
case ExpressionType.MemberAccess:
|
||||
return this.VisitMemberAccess((MemberExpression)exp);
|
||||
case ExpressionType.Call:
|
||||
return this.VisitMethodCall((MethodCallExpression)exp);
|
||||
case ExpressionType.Lambda:
|
||||
return this.VisitLambda((LambdaExpression)exp);
|
||||
case ExpressionType.New:
|
||||
return this.VisitNew((NewExpression)exp);
|
||||
case ExpressionType.NewArrayInit:
|
||||
case ExpressionType.NewArrayBounds:
|
||||
return this.VisitNewArray((NewArrayExpression)exp);
|
||||
case ExpressionType.Invoke:
|
||||
return this.VisitInvocation((InvocationExpression)exp);
|
||||
case ExpressionType.MemberInit:
|
||||
return this.VisitMemberInit((MemberInitExpression)exp);
|
||||
case ExpressionType.ListInit:
|
||||
return this.VisitListInit((ListInitExpression)exp);
|
||||
default:
|
||||
throw new Exception(string.Format("Unhandled expression type: '{0}'", exp.NodeType));
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual MemberBinding VisitBinding(MemberBinding binding)
|
||||
{
|
||||
switch (binding.BindingType)
|
||||
{
|
||||
case MemberBindingType.Assignment:
|
||||
return this.VisitMemberAssignment((MemberAssignment)binding);
|
||||
case MemberBindingType.MemberBinding:
|
||||
return this.VisitMemberMemberBinding((MemberMemberBinding)binding);
|
||||
case MemberBindingType.ListBinding:
|
||||
return this.VisitMemberListBinding((MemberListBinding)binding);
|
||||
default:
|
||||
throw new Exception(string.Format("Unhandled binding type '{0}'", binding.BindingType));
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual ElementInit VisitElementInitializer(ElementInit initializer)
|
||||
{
|
||||
ReadOnlyCollection<Expression> arguments = this.VisitExpressionList(initializer.Arguments);
|
||||
if (arguments != initializer.Arguments)
|
||||
{
|
||||
return Expression.ElementInit(initializer.AddMethod, arguments);
|
||||
}
|
||||
return initializer;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitUnary(UnaryExpression u)
|
||||
{
|
||||
Expression operand = this.Visit(u.Operand);
|
||||
if (operand != u.Operand)
|
||||
{
|
||||
return Expression.MakeUnary(u.NodeType, operand, u.Type, u.Method);
|
||||
}
|
||||
return u;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitBinary(BinaryExpression b)
|
||||
{
|
||||
Expression left = this.Visit(b.Left);
|
||||
Expression right = this.Visit(b.Right);
|
||||
Expression conversion = this.Visit(b.Conversion);
|
||||
if (left != b.Left || right != b.Right || conversion != b.Conversion)
|
||||
{
|
||||
if (b.NodeType == ExpressionType.Coalesce && b.Conversion != null)
|
||||
return Expression.Coalesce(left, right, conversion as LambdaExpression);
|
||||
else
|
||||
return Expression.MakeBinary(b.NodeType, left, right, b.IsLiftedToNull, b.Method);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitTypeIs(TypeBinaryExpression b)
|
||||
{
|
||||
Expression expr = this.Visit(b.Expression);
|
||||
if (expr != b.Expression)
|
||||
{
|
||||
return Expression.TypeIs(expr, b.TypeOperand);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitConstant(ConstantExpression c)
|
||||
{
|
||||
return c;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitConditional(ConditionalExpression c)
|
||||
{
|
||||
Expression test = this.Visit(c.Test);
|
||||
Expression ifTrue = this.Visit(c.IfTrue);
|
||||
Expression ifFalse = this.Visit(c.IfFalse);
|
||||
if (test != c.Test || ifTrue != c.IfTrue || ifFalse != c.IfFalse)
|
||||
{
|
||||
return Expression.Condition(test, ifTrue, ifFalse);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitParameter(ParameterExpression p)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitMemberAccess(MemberExpression m)
|
||||
{
|
||||
Expression exp = this.Visit(m.Expression);
|
||||
if (exp != m.Expression)
|
||||
{
|
||||
return Expression.MakeMemberAccess(exp, m.Member);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitMethodCall(MethodCallExpression m)
|
||||
{
|
||||
Expression obj = this.Visit(m.Object);
|
||||
IEnumerable<Expression> args = this.VisitExpressionList(m.Arguments);
|
||||
if (obj != m.Object || args != m.Arguments)
|
||||
{
|
||||
return Expression.Call(obj, m.Method, args);
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
protected virtual ReadOnlyCollection<Expression> VisitExpressionList(ReadOnlyCollection<Expression> original)
|
||||
{
|
||||
List<Expression> list = null;
|
||||
for (int i = 0, n = original.Count; i < n; i++)
|
||||
{
|
||||
Expression p = this.Visit(original[i]);
|
||||
if (list != null)
|
||||
{
|
||||
list.Add(p);
|
||||
}
|
||||
else if (p != original[i])
|
||||
{
|
||||
list = new List<Expression>(n);
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
list.Add(original[j]);
|
||||
}
|
||||
list.Add(p);
|
||||
}
|
||||
}
|
||||
if (list != null)
|
||||
{
|
||||
return list.AsReadOnly();
|
||||
}
|
||||
return original;
|
||||
}
|
||||
|
||||
protected virtual MemberAssignment VisitMemberAssignment(MemberAssignment assignment)
|
||||
{
|
||||
Expression e = this.Visit(assignment.Expression);
|
||||
if (e != assignment.Expression)
|
||||
{
|
||||
return Expression.Bind(assignment.Member, e);
|
||||
}
|
||||
return assignment;
|
||||
}
|
||||
|
||||
protected virtual MemberMemberBinding VisitMemberMemberBinding(MemberMemberBinding binding)
|
||||
{
|
||||
IEnumerable<MemberBinding> bindings = this.VisitBindingList(binding.Bindings);
|
||||
if (bindings != binding.Bindings)
|
||||
{
|
||||
return Expression.MemberBind(binding.Member, bindings);
|
||||
}
|
||||
return binding;
|
||||
}
|
||||
|
||||
protected virtual MemberListBinding VisitMemberListBinding(MemberListBinding binding)
|
||||
{
|
||||
IEnumerable<ElementInit> initializers = this.VisitElementInitializerList(binding.Initializers);
|
||||
if (initializers != binding.Initializers)
|
||||
{
|
||||
return Expression.ListBind(binding.Member, initializers);
|
||||
}
|
||||
return binding;
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<MemberBinding> VisitBindingList(ReadOnlyCollection<MemberBinding> original)
|
||||
{
|
||||
List<MemberBinding> list = null;
|
||||
for (int i = 0, n = original.Count; i < n; i++)
|
||||
{
|
||||
MemberBinding b = this.VisitBinding(original[i]);
|
||||
if (list != null)
|
||||
{
|
||||
list.Add(b);
|
||||
}
|
||||
else if (b != original[i])
|
||||
{
|
||||
list = new List<MemberBinding>(n);
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
list.Add(original[j]);
|
||||
}
|
||||
list.Add(b);
|
||||
}
|
||||
}
|
||||
if (list != null)
|
||||
return list;
|
||||
return original;
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<ElementInit> VisitElementInitializerList(ReadOnlyCollection<ElementInit> original)
|
||||
{
|
||||
List<ElementInit> list = null;
|
||||
for (int i = 0, n = original.Count; i < n; i++)
|
||||
{
|
||||
ElementInit init = this.VisitElementInitializer(original[i]);
|
||||
if (list != null)
|
||||
{
|
||||
list.Add(init);
|
||||
}
|
||||
else if (init != original[i])
|
||||
{
|
||||
list = new List<ElementInit>(n);
|
||||
for (int j = 0; j < i; j++)
|
||||
{
|
||||
list.Add(original[j]);
|
||||
}
|
||||
list.Add(init);
|
||||
}
|
||||
}
|
||||
if (list != null)
|
||||
return list;
|
||||
return original;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitLambda(LambdaExpression lambda)
|
||||
{
|
||||
Expression body = this.Visit(lambda.Body);
|
||||
if (body != lambda.Body)
|
||||
{
|
||||
return Expression.Lambda(lambda.Type, body, lambda.Parameters);
|
||||
}
|
||||
return lambda;
|
||||
}
|
||||
|
||||
protected virtual NewExpression VisitNew(NewExpression nex)
|
||||
{
|
||||
IEnumerable<Expression> args = this.VisitExpressionList(nex.Arguments);
|
||||
if (args != nex.Arguments)
|
||||
{
|
||||
if (nex.Members != null)
|
||||
return Expression.New(nex.Constructor, args, nex.Members);
|
||||
else
|
||||
return Expression.New(nex.Constructor, args);
|
||||
}
|
||||
return nex;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitMemberInit(MemberInitExpression init)
|
||||
{
|
||||
NewExpression n = this.VisitNew(init.NewExpression);
|
||||
IEnumerable<MemberBinding> bindings = this.VisitBindingList(init.Bindings);
|
||||
if (n != init.NewExpression || bindings != init.Bindings)
|
||||
{
|
||||
return Expression.MemberInit(n, bindings);
|
||||
}
|
||||
return init;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitListInit(ListInitExpression init)
|
||||
{
|
||||
NewExpression n = this.VisitNew(init.NewExpression);
|
||||
IEnumerable<ElementInit> initializers = this.VisitElementInitializerList(init.Initializers);
|
||||
if (n != init.NewExpression || initializers != init.Initializers)
|
||||
{
|
||||
return Expression.ListInit(n, initializers);
|
||||
}
|
||||
return init;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitNewArray(NewArrayExpression na)
|
||||
{
|
||||
IEnumerable<Expression> exprs = this.VisitExpressionList(na.Expressions);
|
||||
if (exprs != na.Expressions)
|
||||
{
|
||||
if (na.NodeType == ExpressionType.NewArrayInit)
|
||||
{
|
||||
return Expression.NewArrayInit(na.Type.GetElementType(), exprs);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Expression.NewArrayBounds(na.Type.GetElementType(), exprs);
|
||||
}
|
||||
}
|
||||
return na;
|
||||
}
|
||||
|
||||
protected virtual Expression VisitInvocation(InvocationExpression iv)
|
||||
{
|
||||
IEnumerable<Expression> args = this.VisitExpressionList(iv.Arguments);
|
||||
Expression expr = this.Visit(iv.Expression);
|
||||
if (args != iv.Arguments || expr != iv.Expression)
|
||||
{
|
||||
return Expression.Invoke(expr, args);
|
||||
}
|
||||
return iv;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Hncore.Infrastructure.Data;
|
||||
using Hncore.Infrastructure.Extension;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Hncore.Infrastructure.EntitiesExtension
|
||||
{
|
||||
public static class IQueryableExtend
|
||||
{
|
||||
#region 返回IQueryable<T>前几条数据
|
||||
|
||||
/// <summary>
|
||||
/// 返回IQueryable前几条数据
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="TopN"></param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<T> TopN<T>(this IQueryable<T> query, int TopN)
|
||||
{
|
||||
return query.Take(TopN);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 对IQueryable<T>进行分页
|
||||
|
||||
/// <summary>
|
||||
/// 对IQueryable进行分页
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="PageSize">每页多少条数据</param>
|
||||
/// <param name="PageIndex">当前页</param>
|
||||
/// <returns></returns>
|
||||
public static IQueryable<T> QueryPager<T>(this IQueryable<T> query, int PageSize, int PageIndex)
|
||||
{
|
||||
if (PageIndex <= 0)
|
||||
{
|
||||
PageIndex = 1;
|
||||
}
|
||||
|
||||
if (PageSize <= 0)
|
||||
{
|
||||
PageSize = 1;
|
||||
}
|
||||
|
||||
if (PageSize > 0)
|
||||
return query.Skip((PageIndex - 1) * PageSize).Take(PageSize);
|
||||
return query;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 得到IQueryable<T>的分页后实体集合
|
||||
|
||||
/// <summary>
|
||||
/// 得到IQueryable的分页后实体集合
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="pageSize">每页多少条数据</param>
|
||||
/// <param name="pageIndex">当前页</param>
|
||||
/// <param name="isTotal">是否统计总行数</param>
|
||||
/// <returns></returns>
|
||||
public static PageData<T> ListPager<T>(this IQueryable<T> query, int pageSize, int pageIndex, bool isTotal)
|
||||
{
|
||||
PageData<T> list = new PageData<T>();
|
||||
|
||||
if (isTotal)
|
||||
{
|
||||
list.RowCount = query.Count();
|
||||
}
|
||||
|
||||
list.List = query.QueryPager<T>(pageSize, pageIndex).ToList();
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 得到IQueryable的分页后实体集合
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="pageSize">每页多少条数据</param>
|
||||
/// <param name="pageIndex">当前页</param>
|
||||
/// <param name="isTotal">是否统计总行数</param>
|
||||
/// <returns></returns>
|
||||
public static async Task<PageData<T>> ListPagerAsync<T>(this IQueryable<T> query, int pageSize, int pageIndex,
|
||||
bool isTotal)
|
||||
{
|
||||
PageData<T> list = new PageData<T>();
|
||||
|
||||
if (isTotal)
|
||||
{
|
||||
list.RowCount = await query.CountAsync();
|
||||
}
|
||||
|
||||
list.List = await query.QueryPager<T>(pageSize, pageIndex).ToListAsync();
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Hncore.Infrastructure.EntitiesExtension
|
||||
{
|
||||
public class ParameterRebinder : ExpressionVisitor
|
||||
{
|
||||
private readonly Dictionary<ParameterExpression, ParameterExpression> map;
|
||||
|
||||
/// <summary>
|
||||
/// Default construcotr
|
||||
/// </summary>
|
||||
/// <param name="map">Map specification</param>
|
||||
public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
|
||||
{
|
||||
this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
|
||||
}
|
||||
/// <summary>
|
||||
/// Replate parameters in expression with a Map information
|
||||
/// </summary>
|
||||
/// <param name="map">Map information</param>
|
||||
/// <param name="exp">Expression to replace parameters</param>
|
||||
/// <returns>Expression with parameters replaced</returns>
|
||||
public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
|
||||
{
|
||||
return new ParameterRebinder(map).Visit(exp);
|
||||
}
|
||||
/// <summary>
|
||||
/// Visit pattern method
|
||||
/// </summary>
|
||||
/// <param name="p">A Parameter expression</param>
|
||||
/// <returns>New visited expression</returns>
|
||||
protected override Expression VisitParameter(ParameterExpression p)
|
||||
{
|
||||
ParameterExpression replacement;
|
||||
if (map.TryGetValue(p, out replacement))
|
||||
{
|
||||
p = replacement;
|
||||
}
|
||||
|
||||
return base.VisitParameter(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Hncore.Infrastructure.EntitiesExtension
|
||||
{
|
||||
public class PartialEvaluator : ExpressionVisitor
|
||||
{
|
||||
private Func<Expression, bool> m_fnCanBeEvaluated;
|
||||
private HashSet<Expression> m_candidates;
|
||||
|
||||
public PartialEvaluator()
|
||||
: this(CanBeEvaluatedLocally)
|
||||
{ }
|
||||
|
||||
public PartialEvaluator(Func<Expression, bool> fnCanBeEvaluated)
|
||||
{
|
||||
this.m_fnCanBeEvaluated = fnCanBeEvaluated;
|
||||
}
|
||||
|
||||
public Expression Eval(Expression exp)
|
||||
{
|
||||
this.m_candidates = new Nominator(this.m_fnCanBeEvaluated).Nominate(exp);
|
||||
|
||||
return this.Visit(exp);
|
||||
}
|
||||
|
||||
protected override Expression Visit(Expression exp)
|
||||
{
|
||||
if (exp == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.m_candidates.Contains(exp))
|
||||
{
|
||||
return this.Evaluate(exp);
|
||||
}
|
||||
|
||||
return base.Visit(exp);
|
||||
}
|
||||
|
||||
private Expression Evaluate(Expression e)
|
||||
{
|
||||
if (e.NodeType == ExpressionType.Constant)
|
||||
{
|
||||
return e;
|
||||
}
|
||||
|
||||
LambdaExpression lambda = Expression.Lambda(e);
|
||||
Delegate fn = lambda.Compile();
|
||||
|
||||
return Expression.Constant(fn.DynamicInvoke(null), e.Type);
|
||||
}
|
||||
|
||||
private static bool CanBeEvaluatedLocally(Expression exp)
|
||||
{
|
||||
return exp.NodeType != ExpressionType.Parameter;
|
||||
}
|
||||
|
||||
#region Nominator
|
||||
|
||||
/// <summary>
|
||||
/// Performs bottom-up analysis to determine which nodes can possibly
|
||||
/// be part of an evaluated sub-tree.
|
||||
/// </summary>
|
||||
private class Nominator : ExpressionVisitor
|
||||
{
|
||||
private Func<Expression, bool> m_fnCanBeEvaluated;
|
||||
private HashSet<Expression> m_candidates;
|
||||
private bool m_cannotBeEvaluated;
|
||||
|
||||
internal Nominator(Func<Expression, bool> fnCanBeEvaluated)
|
||||
{
|
||||
this.m_fnCanBeEvaluated = fnCanBeEvaluated;
|
||||
}
|
||||
|
||||
internal HashSet<Expression> Nominate(Expression expression)
|
||||
{
|
||||
this.m_candidates = new HashSet<Expression>();
|
||||
this.Visit(expression);
|
||||
return this.m_candidates;
|
||||
}
|
||||
|
||||
protected override Expression Visit(Expression expression)
|
||||
{
|
||||
if (expression != null)
|
||||
{
|
||||
bool saveCannotBeEvaluated = this.m_cannotBeEvaluated;
|
||||
this.m_cannotBeEvaluated = false;
|
||||
|
||||
base.Visit(expression);
|
||||
|
||||
if (!this.m_cannotBeEvaluated)
|
||||
{
|
||||
if (this.m_fnCanBeEvaluated(expression))
|
||||
{
|
||||
this.m_candidates.Add(expression);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_cannotBeEvaluated = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.m_cannotBeEvaluated |= saveCannotBeEvaluated;
|
||||
}
|
||||
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user