using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Text.RegularExpressions; namespace SqlSugar { /// /// ** description:Get subquery sql /// ** author:sunkaixuan /// ** date:2017/9/17 /// ** email:610262374@qq.com /// public class SubResolve { List allMethods = new List(); private ExpressionContext context = null; private string subKey = "$SubAs:"; private bool hasWhere; private bool isXmlPath = false; private bool isAsAttr = false; public SubResolve(MethodCallExpression expression, ExpressionContext context, Expression oppsiteExpression) { this.context = context; var currentExpression = expression; allMethods.Add(currentExpression); if (context.IsSingle && oppsiteExpression != null && oppsiteExpression is MemberExpression) { var childExpression = (oppsiteExpression as MemberExpression).Expression; if (childExpression is ParameterExpression) this.context.SingleTableNameSubqueryShortName = (childExpression as ParameterExpression).Name; else { this.context.SingleTableNameSubqueryShortName = (context.Expression as LambdaExpression).Parameters.First().Name; } } else if (context.IsSingle&& ExpressionTool.GetMethodName(currentExpression) != "ToList") { if (context.Expression is LambdaExpression) { this.context.SingleTableNameSubqueryShortName = (context.Expression as LambdaExpression).Parameters.First().Name; } else if (context.Expression is MethodCallExpression) { var expArgs = ((context.Expression as MethodCallExpression).Object as MethodCallExpression).Arguments; if (expArgs != null && expArgs.Any()) { var meExp = expArgs[0] as LambdaExpression; if (meExp != null) { var selfParameterName = meExp.Parameters.First().Name; if ((meExp.Body is BinaryExpression)) { context.SingleTableNameSubqueryShortName = (((meExp.Body as BinaryExpression).Left as MemberExpression)?.Expression as ParameterExpression)?.Name; } if (ExpressionTool.GetMethodName(context.Expression).IsContainsIn("ToList") && meExp.Parameters.Any(it => it.Name == selfParameterName)) { if (meExp.Body is BinaryExpression) { context.SingleTableNameSubqueryShortName = (((meExp.Body as BinaryExpression).Right as MemberExpression)?.Expression as ParameterExpression)?.Name; } } if (context.SingleTableNameSubqueryShortName == selfParameterName) { if (meExp.Body is BinaryExpression) { context.SingleTableNameSubqueryShortName = (((meExp.Body as BinaryExpression).Right as MemberExpression)?.Expression as ParameterExpression)?.Name; } } } } } else if (context.Expression.GetType().Name == "MethodBinaryExpression") { var subExp = (context.Expression as BinaryExpression).Left is MethodCallExpression ? (context.Expression as BinaryExpression).Left : (context.Expression as BinaryExpression).Right; if (subExp is MethodCallExpression) { var meExp = ((subExp as MethodCallExpression).Object as MethodCallExpression).Arguments[0] as LambdaExpression; var selfParameterName = meExp.Parameters.First().Name; context.SingleTableNameSubqueryShortName = (((meExp.Body as BinaryExpression).Left as MemberExpression).Expression as ParameterExpression).Name; if (context.SingleTableNameSubqueryShortName == selfParameterName) { context.SingleTableNameSubqueryShortName = (((meExp.Body as BinaryExpression).Right as MemberExpression).Expression as ParameterExpression).Name; } } } else if (context.RootExpression != null && context.Expression.GetType().Name == "SimpleBinaryExpression") { var name = (this.context.RootExpression as LambdaExpression).Parameters[0].Name; context.SingleTableNameSubqueryShortName = name; } else if (context.Expression is BinaryExpression) { var subExp = (context.Expression as BinaryExpression).Left is MethodCallExpression ? (context.Expression as BinaryExpression).Left : (context.Expression as BinaryExpression).Right; if (subExp is MethodCallExpression) { var argus = ((subExp as MethodCallExpression).Object as MethodCallExpression).Arguments; if (argus.Count > 0) { var meExp = argus[0] as LambdaExpression; var selfParameterName = meExp.Parameters.First().Name; context.SingleTableNameSubqueryShortName = (((meExp.Body as BinaryExpression).Left as MemberExpression)?.Expression as ParameterExpression)?.Name; if (context.SingleTableNameSubqueryShortName == selfParameterName) { context.SingleTableNameSubqueryShortName = (((meExp.Body as BinaryExpression).Right as MemberExpression).Expression as ParameterExpression).Name; } } } } else if (context.Expression is MemberInitExpression memberInitExpression) { var getParameters = ExpressionTool.GetParameters(context.Expression).Select(it=>it.Name).Distinct().ToList(); if (getParameters?.Count()>1) { context.SingleTableNameSubqueryShortName = getParameters.First(); } } else { Check.ExceptionEasy( "I'm sorry I can't parse the current expression","不支持当前表达式"); } } var subIndex = this.context.SubQueryIndex; while (currentExpression != null) { var addItem = currentExpression.Object as MethodCallExpression; if (addItem != null) allMethods.Add(addItem); if (subIndex==this.context.SubQueryIndex&&addItem !=null&&addItem.Arguments.HasValue()&&addItem.Arguments.Any(it=>it.ToString().Contains("Subqueryable()"))) { this.context.SubQueryIndex++; } currentExpression = addItem; } } public string GetSql() { List subItems = GetSubItems(); var sqlItems = subItems.Where(it => !it.StartsWith(subKey)).ToList(); var asItems = subItems.Where(it => it.StartsWith(subKey)).ToList(); if (asItems.Any()) { GetSubAs(sqlItems, asItems); } if (this.context.CurrentShortName.HasValue()) { GetShortName(sqlItems); } var sql = ""; if (sqlItems.Count(it => IsJoin(it)) > 1) { var index = sqlItems.IndexOf(sqlItems.First(x=>IsJoin(x))); var joinitems = sqlItems.Where(it => IsJoin(it)).ToList(); joinitems.Reverse(); var items = sqlItems.Where(it => !IsJoin(it)).ToList(); items.InsertRange(index, joinitems); sql = string.Join(UtilConstants.Space, items); } else { sql = string.Join(UtilConstants.Space, sqlItems); } if (isXmlPath) { var xmlPath = context.DbMehtods.GetForXmlPath(); if (xmlPath.HasValue()) { sql = sql + xmlPath; } } return this.context.DbMehtods.Pack(sql); } private static bool IsJoin(string it) { return it.StartsWith(" INNER JOIN") || it.StartsWith(" LEFT JOIN"); } private void GetSubAs(List sqlItems, List asItems) { for (int i = 0; i < sqlItems.Count; i++) { if (sqlItems[i].StartsWith("FROM " + this.context.SqlTranslationLeft)) { var asName = this.context.GetTranslationTableName(asItems.First().Replace(subKey, ""), false); var repKey = $"\\{this.context.SqlTranslationLeft}.+\\{this.context.SqlTranslationRight}"; if (this.context.IsSingle&&this.context.JoinIndex==0&&this.context.CurrentShortName.HasValue()&& isAsAttr&& !asName.Contains(this.context.CurrentShortName)) { asName = asName + " " + this.context.CurrentShortName+" "; } sqlItems[i] = Regex.Replace(sqlItems[i], repKey, asName); } } } private void GetShortName(List sqlItems) { for (int i = 0; i < sqlItems.Count; i++) { if (sqlItems[i].StartsWith("FROM " + this.context.SqlTranslationLeft)) { if (isAsAttr&&sqlItems[i].EndsWith(this.context.CurrentShortName + " ")) { } else { sqlItems[i] = sqlItems[i] + " " + this.context.CurrentShortName + " "; } } } } private List GetSubItems() { var isSubSubQuery = this.allMethods.Select(it => it.ToString()).Any(it => Regex.Matches(it, "Subquery").Count > 1); var isubList = this.allMethods.Select(exp => { if (isSubSubQuery) { this.context.JoinIndex = 1; this.context.SubQueryIndex = 0; } var methodName = exp.Method.Name; var items = SubTools.SubItems(this.context); var item = items.First(s => s.Name == methodName); if (item is SubWhere && hasWhere == false) { hasWhere = true; } else if (item is SubWhere) { item = items.First(s => s is SubAnd); } if (item is SubWhereIF && hasWhere == false) { hasWhere = true; } else if (item is SubWhereIF) { item = items.First(s => s is SubAndIF); } else if (item is SubSelectStringJoin) { isXmlPath = true; } else if (item is SubAsWithAttr) { isAsAttr = true; } item.Context = this.context; item.Expression = exp; return item; }).ToList(); SetOrderByIndex(isubList); isubList.Insert(0, new SubBegin()); if (isubList.Any(it => it is SubSelect||it is SubFirst)) { isubList.Add(new SubTop() { Context = this.context }); } if (isubList.Any(it => it is SubAny || it is SubNotAny)) { isubList.Add(new SubLeftBracket()); isubList.Add(new SubRightBracket()); isubList.Add(new SubSelectDefault()); } var db = this.context?.SugarContext?.Context; if (db != null&& db?.CurrentConnectionConfig?.DbType == DbType.SqlServer) { if (db.CurrentConnectionConfig?.MoreSettings?.IsWithNoLockSubquery == true) { if (!isubList.Any(it => it is SubWithNolock)) { isubList.Add(new SubWithNolock() { Context = this.context }); } } } isubList = isubList.OrderBy(it => it.Sort).ToList(); var isHasWhere = isubList.Where(it => it is SubWhere).Any(); var isJoin = isubList.Any(it => it is SubInnerJoin || it is SubLeftJoin); if (isJoin) { this.context.JoinIndex++; } if (isAsAttr) { this.context.IsAsAttr = true; } List result = isubList.Select(it => { it.HasWhere = isHasWhere; return it.GetValue(it.Expression); }).ToList(); this.context.JoinIndex = 0; this.context.IsAsAttr = false; return result; } private static void SetOrderByIndex(List isubList) { var orderByIndex = 0; var orderByList = isubList.Where(it => it is SubOrderBy || it is SubOrderByDesc).ToList(); if (orderByList.Count > 1) { orderByList.Reverse(); foreach (var item in orderByList) { if (item is SubOrderBy) { (item as SubOrderBy).OrderIndex = orderByIndex; orderByIndex++; } else if (item is SubOrderByDesc) { (item as SubOrderByDesc).OrderIndex = orderByIndex; orderByIndex++; } } } } } }