From 2f76a22e219ad280393cb8a09fb6b2e4b21a6d4f Mon Sep 17 00:00:00 2001 From: 2881099 <2881099@qq.com> Date: Mon, 25 Jul 2022 22:12:25 +0800 Subject: [PATCH] fix WithTempQuery 05 --- FreeSql.DbContext/FreeSql.DbContext.xml | 9 -- .../Curd/SqlServerSelectWithTempQueryTest.cs | 115 ++++++++++++++++-- FreeSql/Internal/CommonExpression.cs | 31 +++-- .../SelectProvider/Select1Provider.cs | 3 +- .../SelectProvider/SelectGroupingProvider.cs | 61 +++++++--- 5 files changed, 177 insertions(+), 42 deletions(-) diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 26522f10..537315e2 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -800,14 +800,5 @@ - - - 批量注入 Repository,可以参考代码自行调整 - - - - - - diff --git a/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerSelectWithTempQueryTest.cs b/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerSelectWithTempQueryTest.cs index 2d2502d1..8e435295 100644 --- a/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerSelectWithTempQueryTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/SqlServer/Curd/SqlServerSelectWithTempQueryTest.cs @@ -174,6 +174,57 @@ WHERE (a.[rownum] = 1)"; Assert.Equal(list04[1].Id, 4); Assert.Equal(list04[2].rownum, 1); Assert.Equal(list04[2].Id, 5); + + + var sql05 = fsql.Select() + .Where(a => a.Id > 0) + .WithTempQuery(a => new + { + a.Id, + a.Nickname + }) + .GroupBy(a => new { a.Nickname }) + .WithTempQuery(a => new + { + a.Key, + sum1 = a.Sum(a.Value.Id), + cou1 = a.Count() + }) + .ToSql(); + var assertSql05 = @"SELECT * +FROM ( + SELECT a.[Nickname], sum(a.[Id]) [sum1], count(1) [cou1] + FROM ( + SELECT a.[Id], a.[Nickname] + FROM [TwoTablePartitionBy_User] a + WHERE (a.[Id] > 0) ) a + GROUP BY a.[Nickname] ) a"; + Assert.Equal(assertSql05, sql05); + var list05 = fsql.Select() + .Where(a => a.Id > 0) + .WithTempQuery(a => new + { + a.Id, + a.Nickname + }) + .GroupBy(a => new { a.Nickname }) + .WithTempQuery(a => new + { + a.Key, + sum1 = a.Sum(a.Value.Id), + cou1 = a.Count() + }) + .ToList(); + Assert.Equal(3, list05.Count); + Assert.Equal("name01", list05[0].Key.Nickname); + Assert.Equal(6, list05[0].sum1); + Assert.Equal(3, list05[0].cou1); + Assert.Equal("name02", list05[1].Key.Nickname); + Assert.Equal(4, list05[1].sum1); + Assert.Equal(1, list05[1].cou1); + Assert.Equal("name03", list05[2].Key.Nickname); + Assert.Equal(11, list05[2].sum1); + Assert.Equal(2, list05[2].cou1); } class SingleTablePartitionBy_User { @@ -527,7 +578,8 @@ FROM ( SELECT a.[Id], a.[Nickname], row_number() over( partition by a.[Nickname] order by a.[Id]) [rownum] FROM [TwoTablePartitionBy_User] a ) a WHERE (a.[rownum] = 1) ) a -INNER JOIN (SELECT a.[UserId], a.[Remark] +INNER JOIN ( + SELECT a.[UserId], a.[Remark] FROM [TwoTablePartitionBy_UserExt] a) b ON a.[Id] = b.[UserId] WHERE ((a.[Nickname] = N'name03' OR a.[Nickname] = N'name02'))"; Assert.Equal(sql07, assertSql07); @@ -567,7 +619,8 @@ WHERE ((a.[Nickname] = N'name03' OR a.[Nickname] = N'name02'))"; FROM ( SELECT a.[Id], a.[Nickname], row_number() over( partition by a.[Nickname] order by a.[Id]) [rownum] FROM [TwoTablePartitionBy_User] a ) a -INNER JOIN (SELECT a.[UserId], a.[Remark] +INNER JOIN ( + SELECT a.[UserId], a.[Remark] FROM [TwoTablePartitionBy_UserExt] a WHERE (a.[UserId] > 0)) b ON a.[Id] = b.[UserId] WHERE (a.[rownum] = 1) AND ((a.[Nickname] = N'name03' OR a.[Nickname] = N'name02'))"; @@ -599,7 +652,7 @@ WHERE (a.[rownum] = 1) AND ((a.[Nickname] = N'name03' OR a.[Nickname] = N'name02 rownum = SqlExt.RowNumber().Over().PartitionBy(a.Nickname).OrderBy(a.Id).ToValue() }) .Where(a => a.rownum == 1) - .FromQuery(fsql.Select().Where(b => b.UserId > 0).GroupBy(b => new { b.UserId, b.Remark }).WithTempQuery(b => b.Key)) + .FromQuery(fsql.Select().Where(b => b.UserId > 0).WithTempQuery(b => new { b.UserId, b.Remark })) .InnerJoin((a, b) => a.user.Id == b.UserId) .Where((a, b) => a.user.Nickname == "name03" || a.user.Nickname == "name02") .ToSql((a, b) => new TwoTablePartitionBy_UserDto()); @@ -607,10 +660,10 @@ WHERE (a.[rownum] = 1) AND ((a.[Nickname] = N'name03' OR a.[Nickname] = N'name02 FROM ( SELECT a.[Id], a.[Nickname], row_number() over( partition by a.[Nickname] order by a.[Id]) [rownum] FROM [TwoTablePartitionBy_User] a ) a -INNER JOIN ( SELECT a.[UserId], a.[Remark] +INNER JOIN ( + SELECT a.[UserId], a.[Remark] FROM [TwoTablePartitionBy_UserExt] a - WHERE (a.[UserId] > 0) - GROUP BY a.[UserId], a.[Remark] ) b ON a.[Id] = b.[UserId] + WHERE (a.[UserId] > 0) ) b ON a.[Id] = b.[UserId] WHERE (a.[rownum] = 1) AND ((a.[Nickname] = N'name03' OR a.[Nickname] = N'name02'))"; Assert.Equal(sql09, assertSql09); var list09 = fsql.Select() @@ -620,7 +673,7 @@ WHERE (a.[rownum] = 1) AND ((a.[Nickname] = N'name03' OR a.[Nickname] = N'name02 rownum = SqlExt.RowNumber().Over().PartitionBy(a.Nickname).OrderBy(a.Id).ToValue() }) .Where(a => a.rownum == 1) - .FromQuery(fsql.Select().Where(b => b.UserId > 0).GroupBy(b => new { b.UserId, b.Remark }).WithTempQuery(b => b.Key)) + .FromQuery(fsql.Select().Where(b => b.UserId > 0).WithTempQuery(b => new { b.UserId, b.Remark })) .InnerJoin((a, b) => a.user.Id == b.UserId) .Where((a, b) => a.user.Nickname == "name03" || a.user.Nickname == "name02") .ToList(); @@ -633,6 +686,48 @@ WHERE (a.[rownum] = 1) AND ((a.[Nickname] = N'name03' OR a.[Nickname] = N'name02 Assert.Equal(list09[1].remark, "remark05"); + var sql091 = fsql.Select() + .WithTempQuery(a => new + { + user = a, + rownum = SqlExt.RowNumber().Over().PartitionBy(a.Nickname).OrderBy(a.Id).ToValue() + }) + .Where(a => a.rownum == 1) + .FromQuery(fsql.Select().Where(b => b.UserId > 0).GroupBy(b => new { b.UserId, b.Remark }).WithTempQuery(b => b.Key)) + .InnerJoin((a, b) => a.user.Id == b.UserId) + .Where((a, b) => a.user.Nickname == "name03" || a.user.Nickname == "name02") + .ToSql((a, b) => new TwoTablePartitionBy_UserDto()); + var assertSql091 = @"SELECT a.[rownum] as1, b.[Remark] as2 +FROM ( + SELECT a.[Id], a.[Nickname], row_number() over( partition by a.[Nickname] order by a.[Id]) [rownum] + FROM [TwoTablePartitionBy_User] a ) a +INNER JOIN ( + SELECT a.[UserId], a.[Remark] + FROM [TwoTablePartitionBy_UserExt] a + WHERE (a.[UserId] > 0) + GROUP BY a.[UserId], a.[Remark] ) b ON a.[Id] = b.[UserId] +WHERE (a.[rownum] = 1) AND ((a.[Nickname] = N'name03' OR a.[Nickname] = N'name02'))"; + Assert.Equal(sql091, assertSql091); + var list091 = fsql.Select() + .WithTempQuery(a => new + { + user = a, + rownum = SqlExt.RowNumber().Over().PartitionBy(a.Nickname).OrderBy(a.Id).ToValue() + }) + .Where(a => a.rownum == 1) + .FromQuery(fsql.Select().Where(b => b.UserId > 0).GroupBy(b => new { b.UserId, b.Remark }).WithTempQuery(b => b.Key)) + .InnerJoin((a, b) => a.user.Id == b.UserId) + .Where((a, b) => a.user.Nickname == "name03" || a.user.Nickname == "name02") + .ToList(); + Assert.Equal(list091.Count, 2); + Assert.Equal(list091[0].rownum, 1); + Assert.Equal(list091[0].Id, 0); + Assert.Equal(list091[0].remark, "remark04"); + Assert.Equal(list091[1].rownum, 1); + Assert.Equal(list091[1].Id, 0); + Assert.Equal(list091[1].remark, "remark05"); + + var sql10 = fsql.Select() .WithTempQuery(a => new { @@ -648,7 +743,8 @@ WHERE (a.[rownum] = 1) AND ((a.[Nickname] = N'name03' OR a.[Nickname] = N'name02 FROM ( SELECT a.[Id], a.[Nickname], row_number() over( partition by a.[Nickname] order by a.[Id]) [rownum] FROM [TwoTablePartitionBy_User] a ) a -INNER JOIN ( SELECT a.[UserId], a.[Remark], sum(a.[UserId]) [rownum] +INNER JOIN ( + SELECT a.[UserId], a.[Remark], sum(a.[UserId]) [rownum] FROM [TwoTablePartitionBy_UserExt] a WHERE (a.[UserId] > 0) GROUP BY a.[UserId], a.[Remark] ) b ON a.[Id] = b.[UserId] @@ -689,7 +785,8 @@ WHERE (a.[rownum] = 1) AND ((a.[Nickname] = N'name03' OR a.[Nickname] = N'name02 FROM ( SELECT a.[Id], a.[Nickname], row_number() over( partition by a.[Nickname] order by a.[Id]) [rownum] FROM [TwoTablePartitionBy_User] a ) a -INNER JOIN ( SELECT a.[UserId] [uid], sum(a.[UserId]) [rownum] +INNER JOIN ( + SELECT a.[UserId] [uid], sum(a.[UserId]) [rownum] FROM [TwoTablePartitionBy_UserExt] a WHERE (a.[UserId] > 0) GROUP BY a.[UserId] ) b ON a.[Id] = b.[uid] diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs index a42e34bf..c4fb4e72 100644 --- a/FreeSql/Internal/CommonExpression.cs +++ b/FreeSql/Internal/CommonExpression.cs @@ -51,14 +51,14 @@ namespace FreeSql.Internal public bool ReadAnonymousField(List _tables, Func _tableRule, StringBuilder field, ReadAnonymousTypeInfo parent, ref int index, Expression exp, Select0Provider select, BaseDiyMemberExpression diymemexp, List whereGlobalFilter, List findIncludeMany, List findSubSelectMany, bool isAllDtoMap) { - void LocalSetFieldAlias(ref int localIndex) + void LocalSetFieldAlias(ref int localIndex, bool isdiymemexp) { if (localIndex >= 0) { parent.DbNestedField = $"as{++localIndex}"; field.Append(_common.FieldAsAlias(parent.DbNestedField)); } - else if (diymemexp?.ParseExpMapResult != null) + else if (isdiymemexp && diymemexp?.ParseExpMapResult != null) parent.DbNestedField = diymemexp.ParseExpMapResult.DbNestedField; else if (string.IsNullOrEmpty(parent.CsName) == false) { @@ -77,7 +77,7 @@ namespace FreeSql.Internal case ExpressionType.NegateChecked: parent.DbField = $"-({ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, getTSC())})"; field.Append(", ").Append(parent.DbField); - LocalSetFieldAlias(ref index); + LocalSetFieldAlias(ref index, false); if (parent.CsType == null && exp.Type.IsValueType) parent.CsType = exp.Type; return false; case ExpressionType.Convert: return ReadAnonymousField(_tables, _tableRule, field, parent, ref index, (exp as UnaryExpression)?.Operand, select, diymemexp, whereGlobalFilter, findIncludeMany, findSubSelectMany, isAllDtoMap); @@ -96,7 +96,7 @@ namespace FreeSql.Internal else parent.DbField = _common.FormatSql("{0}", constExp?.Value); field.Append(", ").Append(parent.DbField); - LocalSetFieldAlias(ref index); + LocalSetFieldAlias(ref index, false); if (parent.CsType == null && exp.Type.IsValueType) parent.CsType = exp.Type; return false; case ExpressionType.Conditional: @@ -125,7 +125,7 @@ namespace FreeSql.Internal else parent.DbField = ExpressionLambdaToSql(exp, getTSC()); field.Append(", ").Append(parent.DbField); - LocalSetFieldAlias(ref index); + LocalSetFieldAlias(ref index, false); if (parent.CsType == null && exp.Type.IsValueType) parent.CsType = exp.Type; return false; case ExpressionType.Parameter: @@ -273,7 +273,7 @@ namespace FreeSql.Internal if (findcol != null) pdbfield = _common.RereadColumn(findcol, pdbfield); } field.Append(", ").Append(pdbfield); - LocalSetFieldAlias(ref index); + LocalSetFieldAlias(ref index, true); return false; } return false; @@ -486,7 +486,7 @@ namespace FreeSql.Internal } parent.DbField = $"({ExpressionLambdaToSql(exp, getTSC())})"; field.Append(", ").Append(parent.DbField); - LocalSetFieldAlias(ref index); + LocalSetFieldAlias(ref index, false); if (parent.CsType == null && exp.Type.IsValueType) parent.CsType = exp.Type; return false; } @@ -2178,6 +2178,23 @@ namespace FreeSql.Internal } return null; } + public class ReplaceVisitor : ExpressionVisitor + { + private Expression _oldexp; + private Expression _newexp; + public Expression Modify(Expression find, Expression oldexp, Expression newexp) + { + this._oldexp = oldexp; + this._newexp = newexp; + return Visit(find); + } + protected override Expression VisitMember(MemberExpression node) + { + if (node.Expression == _oldexp) + return Expression.Property(_newexp, node.Member.Name); + return base.VisitMember(node); + } + } public class ReplaceParameterVisitor : ExpressionVisitor { private Expression _replaceExp; diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs index 87a14edd..0d8cb161 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs @@ -141,11 +141,12 @@ namespace FreeSql.Internal.CommonProvider { sql2 = select2sp._tableRule(select2sp._tables[0].Table.Type, null); if (sql2.StartsWith("(") && sql2.EndsWith(")")) sql2 = sql2.Substring(1, sql2.Length - 2); + if (sql2.StartsWith(" \r\n")) sql2 = sql2.Substring(3); } if (string.IsNullOrWhiteSpace(sql2)) sql2 = select2?.ToSql("*"); } - return ret.WithSql(null, sql2); + return ret.WithSql(null, $" \r\n{sql2}"); } public ISelectGrouping GroupBy(Expression> columns) diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs index 0cb9b7c0..a68ea8c7 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs @@ -38,7 +38,8 @@ namespace FreeSql.Internal.CommonProvider ParseExpMapResult = _map; return _map.DbField; } - var parentName = ((members.FirstOrDefault() as MemberExpression)?.Expression as MemberExpression)?.Member.Name; + var firstMember = ((members.FirstOrDefault() as MemberExpression)?.Expression as MemberExpression); + var parentName = firstMember?.Member.Name; switch (parentName) { case "Key": @@ -51,29 +52,57 @@ namespace FreeSql.Internal.CommonProvider ParseExpMapResult = read; return read.DbField; case "Value": - var tb = _tables.First(); + var curtables = _tables; + SelectTableInfo curtable = null; var foridx = 0; - if (members.Length > 1) + if (_select._diymemexpWithTempQuery != null && _select._diymemexpWithTempQuery is Select0Provider.WithTempQueryParser tempQueryParser) { - 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 (_select._tables.Count == 1) + curtable = _select._tables[0]; + else { - if (tryitemidx == 1) foridx++; - 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)) { - //var alias = $"SP10{(char)(96 + tryitemidx)}"; - var tmptb = _tables.Where((a, idx) => //a.AliasInit == alias && - a.Table.Type == mem0.Type && idx == tryitemidx - 1).FirstOrDefault(); - if (tmptb != null) + if (tryitemidx == 1) foridx++; + else { - tb = tmptb; - foridx++; + //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(tb.Table.Type, tb.Alias); + var parmExp = Expression.Parameter(curtable.Table.Type, curtable.Alias); Expression retExp = parmExp; for (var a = foridx; a < members.Length; a++) { @@ -205,7 +234,7 @@ namespace FreeSql.Internal.CommonProvider var ret = (_orm as BaseDbProvider).CreateSelectProvider(null) as Select1Provider; if (ret._tables[0].Table == null) ret._tables[0].Table = TableInfo.GetDefaultTable(typeof(TDto)); var parser = new Select0Provider.WithTempQueryParser(_select, this, selector, ret._tables[0]); - var sql = this.ToSql(parser._insideSelectList[0].InsideField); + var sql = $"\r\n{this.ToSql(parser._insideSelectList[0].InsideField)}"; ret.WithSql(sql); ret._diymemexpWithTempQuery = parser; return ret;