using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; namespace Ant.ORM.ORMV20.Core { public class AnalyticExpression { /// /// 递归解析表达式路由计算 /// /// private string CreateSqlElements(Expression exp, ref MemberType type, bool isTure = true) { if (exp is LambdaExpression) { LambdaExpression lambda = exp as LambdaExpression; var expression = lambda.Body; MemberType EleType = MemberType.None; return CreateSqlElements(expression, ref EleType); } else if (exp is BinaryExpression) { var expression = exp as BinaryExpression; MemberType leftType = MemberType.None; MemberType rightType = MemberType.None; var leftIsDateTime = expression.Left.Type.ToString().Contains("System.DateTime"); var rightIsDateTime = expression.Right.Type.ToString().Contains("System.DateTime"); var left = CreateSqlElements(expression.Left, ref leftType); var right = CreateSqlElements(expression.Right, ref rightType); var oper = GetOperator(expression.NodeType); var isKeyOperValue = leftType == MemberType.Key && rightType == MemberType.Value; var isValueOperKey = rightType == MemberType.Key && leftType == MemberType.Value; #region 处理 null if (isKeyOperValue & (right == "null" || right == null) && oper.Trim() == "=") { var oldLeft = AddParas(ref left, right); return string.Format(" ({0} is null ) ", oldLeft); } else if (isKeyOperValue & (right == "null" || right == null) && oper.Trim() == "<>") { var oldLeft = AddParas(ref left, right); return string.Format(" ({0} is not null ) ", oldLeft); } else if (isValueOperKey & (left == "null" || left == null) && oper.Trim() == "=") { return string.Format(" ({0} is null ) ", right); } else if (isValueOperKey & (left == "null" || left == null) && oper.Trim() == "<>") { return string.Format(" ({0} is not null ) ", right); } #endregion else if (isKeyOperValue) { object parValue = null; if (leftIsDateTime && right != null && right.IsDate()) { parValue = Convert.ToDateTime(right); } else { parValue = right; } var oldLeft = AddParas(ref left, parValue); return string.Format(" ({0} {1} @{2}) ", oldLeft, oper, left); } else if (isValueOperKey) { object parValue = null; if (rightIsDateTime && left != null && left.IsDate()) { parValue = Convert.ToDateTime(left); } else { parValue = left; } var oldRight = AddParasReturnRight(parValue, ref right); return string.Format("( @{0} {1} {2} )", right, oper, oldRight); } else if (leftType == MemberType.Value && rightType == MemberType.Value) { return string.Format("( '{0}' {1} '{2}' )", left, oper, right); } else { return string.Format("( {0} {1} {2} )", left, oper, right); } } else if (exp is BlockExpression) { } else if (exp is ConditionalExpression) { } else if (exp is MethodCallExpression) { MethodCallExpression mce = (MethodCallExpression)exp; string methodName = mce.Method.Name; if (methodName == "Contains") { return Contains(methodName, mce, isTure); } else if (methodName == "StartsWith") { return StartsWith(methodName, mce, isTure); } else if (methodName == "EndsWith") { return EndWith(methodName, mce, isTure); } else if (methodName == "ToString") { type = MemberType.Value; return MethodToString(methodName, mce, ref type); } else { type = MemberType.Value; return MethodTo(methodName, mce, ref type); } } else if (exp is ConstantExpression) { type = MemberType.Value; ConstantExpression ce = ((ConstantExpression)exp); if (ce.Value == null) return "null"; else { return ce.Value.ToString(); } } else if (exp is MemberExpression) { MemberExpression me = ((MemberExpression)exp); if (me.Expression == null || me.Expression.NodeType.ToString() != "Parameter") { type = MemberType.Value; object dynInv = null; try { // var dynInv = Expression.Lambda(exp).Compile().DynamicInvoke();原始写法性能极慢,下面写法性能提高了几十倍 // var dynInv= Expression.Lambda(me.Expression as ConstantExpression).Compile().DynamicInvoke(); var conExp = me.Expression as ConstantExpression; if (conExp != null) { dynInv = (me.Member as System.Reflection.FieldInfo).GetValue((me.Expression as ConstantExpression).Value); } else { var memberInfos = new Stack(); // "descend" toward's the root object reference: while (exp is MemberExpression) { var memberExpr = exp as MemberExpression; memberInfos.Push(memberExpr.Member); exp = memberExpr.Expression; } // fetch the root object reference: var constExpr = exp as ConstantExpression; var objReference = constExpr.Value; // "ascend" back whence we came from and resolve object references along the way: while (memberInfos.Count > 0) // or some other break condition { var mi = memberInfos.Pop(); if (mi.MemberType == MemberTypes.Property) { objReference = objReference.GetType() .GetProperty(mi.Name) .GetValue(objReference, null); } else if (mi.MemberType == MemberTypes.Field) { objReference = objReference.GetType() .GetField(mi.Name) .GetValue(objReference); } } dynInv = objReference; } } catch (Exception ex) { if (me.ToString() == "DateTime.Now") { return DateTime.Now.ToString(); } Check.Exception(true, "错误信息:{0} \r\n message:{1}", "拉姆达解析出错,参数可支持的函数有 Trim 、Contains 、ObjToXXX、 Convert.ToXXX、Contains、StartsWith和StartsEnd。 ", ex.Message); } if (dynInv == null) return null; else return dynInv.ToString(); } else { if (Type == ResolveExpressType.nT) { type = MemberType.Key; return exp.ToString(); } string name = me.Member.Name; type = MemberType.Key; return name; } } else if (exp is UnaryExpression) { UnaryExpression ue = ((UnaryExpression)exp); var mex = ue.Operand; return CreateSqlElements(mex, ref type, false); } return null; } /// /// 拉姆达函数处理 /// /// /// /// /// private string MethodTo(string methodName, MethodCallExpression mce, ref MemberType type) { string value = string.Empty; if (mce.Arguments.IsValuable()) { value = CreateSqlElements(mce.Arguments.FirstOrDefault(), ref type); } else { value = MethodToString(methodName, mce, ref type); ; } if (methodName == "ToDateTime" || methodName == "ObjToDate") { return Convert.ToDateTime(value).ToString(); } else if (methodName.StartsWith("ToInt")) { return Convert.ToInt32(value).ToString(); } else if (methodName.StartsWith("Trim")) { return (value.ObjToString()).Trim(); } else if (methodName.StartsWith("ObjTo")) { return value; } return value; } /// /// 添加参数并返回右边值 /// /// /// /// private string AddParasReturnRight(object left, ref string right) { string oldRight = right; right = right + SameIndex; SameIndex++; if (Type != ResolveExpressType.oneT) { right = right.Replace(".", "_"); } if (left == null) { this.Paras.Add(new SqlParameter("@" + right, DBNull.Value)); } else { this.Paras.Add(new SqlParameter("@" + right, left)); } return oldRight; } /// /// 拉姆达StartsWith函数处理 /// /// /// /// /// private string StartsWith(string methodName, MethodCallExpression mce, bool isTure) { MemberType leftType = MemberType.None; MemberType rightType = MemberType.None; var left = CreateSqlElements(mce.Object, ref leftType); var right = CreateSqlElements(mce.Arguments[0], ref rightType); var oldLeft = AddParas(ref left, right); return string.Format("({0} {1} LIKE @{2}+'%')", oldLeft, isTure == false ? " NOT " : null, left); } /// /// 拉姆达EndWith函数处理 /// /// /// /// /// private string EndWith(string methodName, MethodCallExpression mce, bool isTure) { MemberType leftType = MemberType.None; MemberType rightType = MemberType.None; var left = CreateSqlElements(mce.Object, ref leftType); var right = CreateSqlElements(mce.Arguments[0], ref rightType); var oldLeft = AddParas(ref left, right); return string.Format("({0} {1} LIKE '%'+@{2})", oldLeft, isTure == false ? " NOT " : null, left); } /// /// 拉姆达Contains函数处理 /// /// /// /// /// private string Contains(string methodName, MethodCallExpression mce, bool isTure) { MemberType leftType = MemberType.None; MemberType rightType = MemberType.None; var left = CreateSqlElements(mce.Object, ref leftType); var right = CreateSqlElements(mce.Arguments[0], ref rightType); var oldLeft = AddParas(ref left, right); return string.Format("({0} {1} LIKE '%'+@{2}+'%')", oldLeft, isTure == false ? " NOT " : null, left); } /// /// 根据条件生成对应的sql查询操作符 /// /// /// private string GetOperator(ExpressionType expressiontype) { switch (expressiontype) { case ExpressionType.And: case ExpressionType.AndAlso: return " AND "; case ExpressionType.Equal: return " ="; case ExpressionType.GreaterThan: return " >"; case ExpressionType.GreaterThanOrEqual: return ">="; case ExpressionType.LessThan: return "<"; case ExpressionType.LessThanOrEqual: return "<="; case ExpressionType.NotEqual: return "<>"; case ExpressionType.Or: case ExpressionType.OrElse: return " OR "; case ExpressionType.Add: case ExpressionType.AddChecked: return "+"; case ExpressionType.Subtract: case ExpressionType.SubtractChecked: return "-"; case ExpressionType.Divide: return "/"; case ExpressionType.Multiply: case ExpressionType.MultiplyChecked: return "*"; default: throw new SqlSugarException(string.Format("拉姆达解析出错:不支持{0}此种运算符查找!" + expressiontype)); } } /// /// 拉姆达成员类型 /// public enum MemberType { None = 0, Key = 1, Value = 2 } } }