public ISelect <TResult> SelectMany <TCollection, TResult>(Expression <Func <T1, ISelect <TCollection> > > collectionSelector, Expression <Func <T1, TCollection, TResult> > resultSelector) where TCollection : class where TResult : class { SelectTableInfo find = null; if (collectionSelector.Body.NodeType == ExpressionType.Call) { var callExp = collectionSelector.Body as MethodCallExpression; if (callExp.Method.Name == "DefaultIfEmpty" && callExp.Object.Type.GenericTypeArguments.Any()) { find = _tables.Where((a, idx) => idx > 0 && a.Type == SelectTableInfoType.InnerJoin && a.Table.Type == callExp.Object.Type.GenericTypeArguments[0]).LastOrDefault(); if (find != null) { if (!string.IsNullOrEmpty(find.On)) { find.On = Regex.Replace(find.On, $@"\b{find.Alias}\.", $"{resultSelector.Parameters[1].Name}."); } if (!string.IsNullOrEmpty(find.NavigateCondition)) { find.NavigateCondition = Regex.Replace(find.NavigateCondition, $@"\b{find.Alias}\.", $"{resultSelector.Parameters[1].Name}."); } find.Type = SelectTableInfoType.LeftJoin; find.Alias = resultSelector.Parameters[1].Name; find.Parameter = resultSelector.Parameters[1]; } } } if (find == null) { var tb = _commonUtils.GetTableByEntity(typeof(TCollection)); if (tb == null) { throw new Exception($"SelectMany 错误的类型:{typeof(TCollection).FullName}"); } _tables.Add(new SelectTableInfo { Alias = resultSelector.Parameters[1].Name, AliasInit = resultSelector.Parameters[1].Name, Parameter = resultSelector.Parameters[1], Table = tb, Type = SelectTableInfoType.From }); } if (typeof(TResult) == typeof(T1)) { return(this as ISelect <TResult>); } _selectExpression = resultSelector.Body; var ret = _orm.Select <TResult>() as Select1Provider <TResult>; Select0Provider <ISelect <T1>, T1> .CopyData(this, ret, null); return(ret); }
internal static void InternalSelectMany2 <T1>(Select1Provider <T1> s1p, LambdaExpression collectionSelector, LambdaExpression resultSelector) where T1 : class { SelectTableInfo find = null; if (collectionSelector.Body.NodeType == ExpressionType.Call) { var callExp = collectionSelector.Body as MethodCallExpression; if (callExp.Method.Name == "DefaultIfEmpty" && callExp.Method.GetGenericArguments().Any()) { find = s1p._tables.Where((a, idx) => idx > 0 && a.Type == SelectTableInfoType.InnerJoin && a.Table.Type == callExp.Method.GetGenericArguments()[0]).LastOrDefault(); if (find != null) { if (!string.IsNullOrEmpty(find.On)) { find.On = Regex.Replace(find.On, $@"\b{find.Alias}\.", $"{resultSelector.Parameters[1].Name}."); } if (!string.IsNullOrEmpty(find.NavigateCondition)) { find.NavigateCondition = Regex.Replace(find.NavigateCondition, $@"\b{find.Alias}\.", $"{resultSelector.Parameters[1].Name}."); } find.Type = SelectTableInfoType.LeftJoin; find.Alias = resultSelector.Parameters[1].Name; find.Parameter = resultSelector.Parameters[1]; } } } if (find == null) { var tb = s1p._commonUtils.GetTableByEntity(resultSelector.Parameters[1].Type); if (tb == null) { throw new Exception($"SelectMany 错误的类型:{resultSelector.Parameters[1].Type.FullName}"); } s1p._tables.Add(new SelectTableInfo { Alias = resultSelector.Parameters[1].Name, AliasInit = resultSelector.Parameters[1].Name, Parameter = resultSelector.Parameters[1], Table = tb, Type = SelectTableInfoType.From }); } }
internal string ExpressionLambdaToSql(Expression exp, List <SelectTableInfo> _tables, List <SelectColumnInfo> _selectColumnMap, Func <Expression[], string> getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { switch (exp.NodeType) { case ExpressionType.Not: return($"not({ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"); case ExpressionType.Quote: return(ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)); case ExpressionType.Lambda: return(ExpressionLambdaToSql((exp as LambdaExpression)?.Body, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)); case ExpressionType.Convert: return(ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)); case ExpressionType.Negate: case ExpressionType.NegateChecked: return("-" + ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)); case ExpressionType.Constant: return(_common.FormatSql("{0}", (exp as ConstantExpression)?.Value)); case ExpressionType.Conditional: var condExp = exp as ConditionalExpression; return($"case when {ExpressionLambdaToSql(condExp.Test, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} then {ExpressionLambdaToSql(condExp.IfTrue, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} else {ExpressionLambdaToSql(condExp.IfFalse, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} end"); case ExpressionType.Call: var exp3 = exp as MethodCallExpression; var callType = exp3.Object?.Type ?? exp3.Method.DeclaringType; switch (callType.FullName) { case "System.String": return(ExpressionLambdaToSqlCallString(exp3, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)); case "System.Math": return(ExpressionLambdaToSqlCallMath(exp3, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)); case "System.DateTime": return(ExpressionLambdaToSqlCallDateTime(exp3, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)); case "System.TimeSpan": return(ExpressionLambdaToSqlCallTimeSpan(exp3, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)); case "System.Convert": return(ExpressionLambdaToSqlCallConvert(exp3, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)); } if (callType.FullName.StartsWith("FreeSql.ISelectGroupingAggregate`")) { switch (exp3.Method.Name) { case "Count": return("count(1)"); case "Sum": return($"sum({ExpressionLambdaToSql(exp3.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"); case "Avg": return($"avg({ExpressionLambdaToSql(exp3.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"); case "Max": return($"max({ExpressionLambdaToSql(exp3.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"); case "Min": return($"min({ExpressionLambdaToSql(exp3.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"); } } if (callType.FullName.StartsWith("FreeSql.ISelect`")) //子表查询 { if (exp3.Method.Name == "Any") //exists { var exp3Stack = new Stack <Expression>(); var exp3tmp = exp3.Object; while (exp3tmp != null) { exp3Stack.Push(exp3tmp); switch (exp3tmp.NodeType) { case ExpressionType.Call: exp3tmp = (exp3tmp as MethodCallExpression).Object; continue; case ExpressionType.MemberAccess: exp3tmp = (exp3tmp as MemberExpression).Expression; continue; } break; } object fsql = null; List <SelectTableInfo> fsqltables = null; var fsqltable1SetAlias = false; Type fsqlType = null; while (exp3Stack.Any()) { exp3tmp = exp3Stack.Pop(); if (exp3tmp.Type.FullName.StartsWith("FreeSql.ISelect`") && fsql == null) { fsql = Expression.Lambda(exp3tmp).Compile().DynamicInvoke(); fsqlType = fsql?.GetType(); if (fsqlType == null) { break; } fsqlType.GetField("_limit", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(fsql, 1); fsqltables = fsqlType.GetField("_tables", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(fsql) as List <SelectTableInfo>; //fsqltables[0].Alias = $"{_tables[0].Alias}_{fsqltables[0].Alias}"; fsqltables.AddRange(_tables.Select(a => new SelectTableInfo { Alias = a.Type == SelectTableInfoType.Parent ? a.Alias : $"__parent_{a.Alias}_parent__", On = "1=1", Table = a.Table, Type = SelectTableInfoType.Parent })); } else if (fsqlType != null) { var call3Exp = exp3tmp as MethodCallExpression; var method = fsqlType.GetMethod(call3Exp.Method.Name, call3Exp.Arguments.Select(a => a.Type).ToArray()); if (call3Exp.Method.ContainsGenericParameters) { method.MakeGenericMethod(call3Exp.Method.GetGenericArguments()); } var parms = method.GetParameters(); var args = new object[call3Exp.Arguments.Count]; for (var a = 0; a < args.Length; a++) { var argExp = (call3Exp.Arguments[a] as UnaryExpression)?.Operand; if (argExp != null && argExp.NodeType == ExpressionType.Lambda) { if (fsqltable1SetAlias == false) { fsqltables[0].Alias = (argExp as LambdaExpression).Parameters.First().Name; fsqltable1SetAlias = true; } } args[a] = argExp; //if (args[a] == null) ExpressionLambdaToSql(call3Exp.Arguments[a], fsqltables, null, null, SelectTableInfoType.From, true); } method.Invoke(fsql, args); } } if (fsql != null) { var sql = fsqlType.GetMethod("ToSql", new Type[] { typeof(string) })?.Invoke(fsql, new object[] { "1" })?.ToString(); if (string.IsNullOrEmpty(sql) == false) { foreach (var tb in _tables) { sql = sql.Replace($"__parent_{tb.Alias}_parent__", tb.Alias); } return($"exists({sql})"); } } } } var other3Exp = ExpressionLambdaToSqlOther(exp3, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (string.IsNullOrEmpty(other3Exp) == false) { return(other3Exp); } throw new Exception($"未现实函数表达式 {exp3} 解析"); case ExpressionType.MemberAccess: var exp4 = exp as MemberExpression; if (exp4.Expression != null && exp4.Expression.Type.IsArray == false && exp4.Expression.Type.FullName.StartsWith("System.Nullable`1[")) { return(ExpressionLambdaToSql(exp4.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)); } var extRet = ""; var memberType = exp4.Expression?.Type ?? exp4.Type; switch (memberType.FullName) { case "System.String": extRet = ExpressionLambdaToSqlMemberAccessString(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); break; case "System.DateTime": extRet = ExpressionLambdaToSqlMemberAccessDateTime(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); break; case "System.TimeSpan": extRet = ExpressionLambdaToSqlMemberAccessTimeSpan(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); break; } if (string.IsNullOrEmpty(extRet) == false) { return(extRet); } var other4Exp = ExpressionLambdaToSqlOther(exp4, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (string.IsNullOrEmpty(other4Exp) == false) { return(other4Exp); } var expStack = new Stack <Expression>(); expStack.Push(exp); MethodCallExpression callExp = null; var exp2 = exp4.Expression; while (true) { switch (exp2.NodeType) { case ExpressionType.Constant: expStack.Push(exp2); break; case ExpressionType.Parameter: expStack.Push(exp2); break; case ExpressionType.MemberAccess: expStack.Push(exp2); exp2 = (exp2 as MemberExpression).Expression; if (exp2 == null) { break; } continue; case ExpressionType.Call: callExp = exp2 as MethodCallExpression; expStack.Push(exp2); exp2 = callExp.Object; if (exp2 == null) { break; } continue; } break; } if (expStack.First().NodeType != ExpressionType.Parameter) { return(_common.FormatSql("{0}", Expression.Lambda(exp).Compile().DynamicInvoke())); } if (callExp != null) { return(ExpressionLambdaToSql(callExp, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)); } if (getSelectGroupingMapString != null && expStack.First().Type.FullName.StartsWith("FreeSql.ISelectGroupingAggregate`")) { if (getSelectGroupingMapString != null) { var expText = getSelectGroupingMapString(expStack.Where((a, b) => b >= 2).ToArray()); if (string.IsNullOrEmpty(expText) == false) { return(expText); } } } if (_tables == null) { var pp = expStack.Pop() as ParameterExpression; var memberExp = expStack.Pop() as MemberExpression; var tb = _common.GetTableByEntity(pp.Type); if (tb.ColumnsByCs.ContainsKey(memberExp.Member.Name) == false) { throw new ArgumentException($"{tb.DbName} 找不到列 {memberExp.Member.Name}"); } if (_selectColumnMap != null) { _selectColumnMap.Add(new SelectColumnInfo { Table = null, Column = tb.ColumnsByCs[memberExp.Member.Name] }); } var name = tb.ColumnsByCs[memberExp.Member.Name].Attribute.Name; if (isQuoteName) { name = _common.QuoteSqlName(name); } return(name); } Func <TableInfo, string, bool, SelectTableInfo> getOrAddTable = (tbtmp, alias, isa) => { var finds = _tables.Where((a2, c2) => (isa || c2 > 0) && a2.Table.CsName == tbtmp.CsName).ToArray(); //外部表,内部表一起查 if (finds.Length > 1) { finds = _tables.Where((a2, c2) => a2.Table.CsName == tbtmp.CsName && a2.Type == SelectTableInfoType.Parent && a2.Alias == $"__parent_{alias}_parent__").ToArray(); //查询外部表 if (finds.Any() == false) { finds = _tables.Where((a2, c2) => (isa || c2 > 0) && a2.Table.CsName == tbtmp.CsName && a2.Type != SelectTableInfoType.Parent).ToArray(); //查询内部表 if (finds.Length > 1) { finds = _tables.Where((a2, c2) => (isa || c2 > 0) && a2.Table.CsName == tbtmp.CsName && a2.Type != SelectTableInfoType.Parent && a2.Alias == alias).ToArray(); } } } var find = finds.FirstOrDefault(); if (find == null) { _tables.Add(find = new SelectTableInfo { Table = tbtmp, Alias = alias, On = null, Type = tbtype }); } return(find); }; TableInfo tb2 = null; string alias2 = "", name2 = ""; SelectTableInfo find2 = null; while (expStack.Count > 0) { exp2 = expStack.Pop(); switch (exp2.NodeType) { case ExpressionType.Constant: throw new NotImplementedException("未现实 MemberAccess 下的 Constant"); case ExpressionType.Parameter: case ExpressionType.MemberAccess: var exp2Type = exp2.Type; if (exp2Type.FullName.StartsWith("FreeSql.ISelectGroupingAggregate`")) { exp2Type = exp2Type.GenericTypeArguments.FirstOrDefault() ?? exp2.Type; } var tb2tmp = _common.GetTableByEntity(exp2Type); var mp2 = exp2 as MemberExpression; if (mp2?.Member.Name == "Key" && mp2.Expression.Type.FullName.StartsWith("FreeSql.ISelectGroupingAggregate`")) { continue; } if (tb2tmp != null) { if (exp2.NodeType == ExpressionType.Parameter) { alias2 = (exp2 as ParameterExpression).Name; } else { alias2 = $"{alias2}__{mp2.Member.Name}"; } find2 = getOrAddTable(tb2tmp, alias2, exp2.NodeType == ExpressionType.Parameter); alias2 = find2.Alias; tb2 = tb2tmp; } if (mp2 == null || expStack.Any()) { continue; } if (tb2.ColumnsByCs.ContainsKey(mp2.Member.Name) == false) //如果选的是对象,附加所有列 { if (_selectColumnMap != null) { var tb3 = _common.GetTableByEntity(mp2.Type); if (tb3 != null) { var find3 = getOrAddTable(tb2tmp, $"{alias2}__{mp2.Member.Name}", exp2.NodeType == ExpressionType.Parameter); foreach (var tb3c in tb3.Columns.Values) { _selectColumnMap.Add(new SelectColumnInfo { Table = find3, Column = tb3c }); } if (tb3.Columns.Any()) { return(""); } } } throw new ArgumentException($"{tb2.DbName} 找不到列 {mp2.Member.Name}"); } var col2 = tb2.ColumnsByCs[mp2.Member.Name]; if (_selectColumnMap != null && find2 != null) { _selectColumnMap.Add(new SelectColumnInfo { Table = find2, Column = col2 }); return(""); } name2 = tb2.ColumnsByCs[mp2.Member.Name].Attribute.Name; break; case ExpressionType.Call: break; } } if (isQuoteName) { name2 = _common.QuoteSqlName(name2); } return($"{alias2}.{name2}"); } var expBinary = exp as BinaryExpression; if (expBinary == null) { var other99Exp = ExpressionLambdaToSqlOther(exp, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (string.IsNullOrEmpty(other99Exp) == false) { return(other99Exp); } return(""); } if (expBinary.NodeType == ExpressionType.Coalesce) { return(_common.IsNull( ExpressionLambdaToSql(expBinary.Left, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName), ExpressionLambdaToSql(expBinary.Right, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName))); } if (dicExpressionOperator.TryGetValue(expBinary.NodeType, out var tryoper) == false) { return(""); } var left = ExpressionLambdaToSql(expBinary.Left, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); var right = ExpressionLambdaToSql(expBinary.Right, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (left == "NULL") { var tmp = right; right = left; left = tmp; } if (right == "NULL") { tryoper = tryoper == "=" ? " IS " : " IS NOT "; } if (tryoper == "+" && (expBinary.Left.Type.FullName == "System.String" || expBinary.Right.Type.FullName == "System.String")) { return(_common.StringConcat(left, right, expBinary.Left.Type, expBinary.Right.Type)); } if (tryoper == "%") { return(_common.Mod(left, right, expBinary.Left.Type, expBinary.Right.Type)); } return($"{left} {tryoper} {right}"); }
public override string ParseExp(Expression[] members) { ParseExpMapResult = null; if (members.Any() == false) { ParseExpMapResult = _map; return(_map.DbField); } var firstMember = ((members.FirstOrDefault() as MemberExpression)?.Expression as MemberExpression); var parentName = firstMember?.Member.Name; switch (parentName) { case "Key": var read = _map; for (var a = 0; a < members.Length; a++) { read = read.Childs.Where(z => z.CsName == (members[a] as MemberExpression)?.Member.Name).FirstOrDefault(); if (read == null) { return(null); } } ParseExpMapResult = read; return(read.DbField); case "Value": var curtables = _tables; SelectTableInfo curtable = null; var foridx = 0; if (_select._diymemexpWithTempQuery != null && _select._diymemexpWithTempQuery is Select0Provider.WithTempQueryParser tempQueryParser) { if (_select._tables.Count == 1) { curtable = _select._tables[0]; } else { curtables = _select._tables; LocalValueInitData(); } if (tempQueryParser._outsideTable.Contains(curtable)) { for (var a = 0; a < members.Length; a++) { members[a] = new CommonExpression.ReplaceVisitor().Modify(members[a], firstMember, curtable.Parameter); } var ret = _select._diymemexpWithTempQuery.ParseExp(members); ParseExpMapResult = _select._diymemexpWithTempQuery.ParseExpMapResult; return(ret); } } else { LocalValueInitData(); } void LocalValueInitData() { curtable = curtables.First(); if (members.Length > 1) { var mem0 = (members.FirstOrDefault() as MemberExpression); var mem0Name = mem0?.Member.Name; if (mem0Name?.StartsWith("Item") == true && int.TryParse(mem0Name.Substring(4), out var tryitemidx)) { if (tryitemidx == 1) { foridx++; } else { //var alias = $"SP10{(char)(96 + tryitemidx)}"; var tmptb = curtables.Where((a, idx) => //a.AliasInit == alias && a.Table.Type == mem0.Type && idx == tryitemidx - 1).FirstOrDefault(); if (tmptb != null) { curtable = tmptb; foridx++; } } } } } var parmExp = Expression.Parameter(curtable.Table.Type, curtable.Alias); Expression retExp = parmExp; for (var a = foridx; a < members.Length; a++) { switch (members[a].NodeType) { case ExpressionType.Call: retExp = Expression.Call(retExp, (members[a] as MethodCallExpression).Method); break; case ExpressionType.MemberAccess: retExp = Expression.MakeMemberAccess(retExp, (members[a] as MemberExpression).Member); break; default: return(null); } } return(_comonExp.ExpressionLambdaToSql(retExp, new CommonExpression.ExpTSC { _tables = _tables, _tableRule = _select._tableRule, tbtype = SelectTableInfoType.From, isQuoteName = true, isDisableDiyParse = true, style = CommonExpression.ExpressionStyle.Where })); } return(null); }