| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Text;
- using System.Text.RegularExpressions;
- namespace SqlSugar
- {
- ///<summary>
- /// ** description:Get subquery sql
- /// ** author:sunkaixuan
- /// ** date:2017/9/17
- /// ** email:610262374@qq.com
- /// </summary>
- public class SubResolve
- {
- List<MethodCallExpression> allMethods = new List<MethodCallExpression>();
- private ExpressionContext context = null;
- private string subKey = "$SubAs:";
- private bool hasWhere;
- private bool isXmlPath = 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<string> 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<string> sqlItems, List<string> 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}";
- sqlItems[i] = Regex.Replace(sqlItems[i], repKey, asName);
- }
- }
- }
- private void GetShortName(List<string> sqlItems)
- {
- for (int i = 0; i < sqlItems.Count; i++)
- {
- if (sqlItems[i].StartsWith("FROM " + this.context.SqlTranslationLeft))
- {
- sqlItems[i] = sqlItems[i]+" "+this.context.CurrentShortName +" ";
- }
- }
- }
- private List<string> 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;
- }
- 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++;
- }
- List<string> result = isubList.Select(it =>
- {
- it.HasWhere = isHasWhere;
- return it.GetValue(it.Expression);
- }).ToList();
- this.context.JoinIndex = 0;
- return result;
- }
- private static void SetOrderByIndex(List<ISubOperation> 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++;
- }
- }
- }
- }
- }
- }
|