From bfb59d9d390f3f2a8e197b15e95822f86ede9f18 Mon Sep 17 00:00:00 2001 From: 2881099 <2881099@qq.com> Date: Fri, 11 Dec 2020 22:03:02 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E4=BF=AE=E5=A4=8D=20=E5=88=86=E7=BB=84?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=90=8E=EF=BC=8C=E6=97=A0=E6=B3=95=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E5=AD=90=E6=9F=A5=E8=AF=A2=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SelectedQueryProvider.cs | 2 + FreeSql.DbContext/FreeSql.DbContext.xml | 9 ++ FreeSql.Tests/FreeSql.Tests/UnitTest4.cs | 114 ++++++++++++++++++ FreeSql.sln | 15 --- FreeSql/FreeSql.xml | 5 + FreeSql/Internal/CommonExpression.cs | 58 +++++++-- .../SelectProvider/SelectGroupingProvider.cs | 23 +++- 7 files changed, 200 insertions(+), 26 deletions(-) diff --git a/Extensions/FreeSql.Extensions.Linq/SelectedQueryProvider.cs b/Extensions/FreeSql.Extensions.Linq/SelectedQueryProvider.cs index 6c3ad1d9..5c3124a8 100644 --- a/Extensions/FreeSql.Extensions.Linq/SelectedQueryProvider.cs +++ b/Extensions/FreeSql.Extensions.Linq/SelectedQueryProvider.cs @@ -161,6 +161,7 @@ namespace FreeSql.Internal.CommonProvider public ISelectedQuery OrderByIf(bool condition, Expression> column, bool descending = false) { if (condition == false) return this; + _lambdaParameter = column?.Parameters[0]; var sql = _comonExp.ExpressionWhereLambda(null, column, this, null, null); var method = _select.GetType().GetMethod("OrderBy", new[] { typeof(string), typeof(object) }); method.Invoke(_select, new object[] { descending ? $"{sql} DESC" : sql, null }); @@ -172,6 +173,7 @@ namespace FreeSql.Internal.CommonProvider public ISelectedQuery WhereIf(bool condition, Expression> exp) { if (condition == false) return this; + _lambdaParameter = exp?.Parameters[0]; var sql = _comonExp.ExpressionWhereLambda(null, exp, this, null, null); var method = _select.GetType().GetMethod("Where", new[] { typeof(string), typeof(object) }); method.Invoke(_select, new object[] { sql, null }); diff --git a/FreeSql.DbContext/FreeSql.DbContext.xml b/FreeSql.DbContext/FreeSql.DbContext.xml index 02eb0609..27909b2e 100644 --- a/FreeSql.DbContext/FreeSql.DbContext.xml +++ b/FreeSql.DbContext/FreeSql.DbContext.xml @@ -512,5 +512,14 @@ + + + 批量注入 Repository,可以参考代码自行调整 + + + + + + diff --git a/FreeSql.Tests/FreeSql.Tests/UnitTest4.cs b/FreeSql.Tests/FreeSql.Tests/UnitTest4.cs index 6d9b2744..cbc10733 100644 --- a/FreeSql.Tests/FreeSql.Tests/UnitTest4.cs +++ b/FreeSql.Tests/FreeSql.Tests/UnitTest4.cs @@ -13,6 +13,120 @@ namespace FreeSql.Tests { public class UnitTest4 { + [Fact] + public void GroupSubSelect() + { + var fsql = g.sqlite; + fsql.Delete().Where("1=1").ExecuteAffrows(); + + var affrows = fsql.Insert(new[]{ + new ts_group_sub_select01 + { + code = "code_01", + seqid = 1, + name = "name_01" + }, + new ts_group_sub_select01 + { + code = "code_02", + seqid = 2, + name = "name_02" + } + }).ExecuteAffrows(); + Assert.Equal(2, affrows); + + var sql = fsql.Select() + .GroupBy(a => new + { + a.code, + a.seqid, + a.name + }) + .ToSql(g => new + { + g.Key.code, + g.Key.seqid, + g.Key.name, + number = fsql.Select() + .Where(o => o.seqid == 6) + .Count(), + number2 = 3, + number3 = 5 + }); + Assert.Equal(@"SELECT a.""code"" as1, a.""seqid"" as2, a.""name"" as3, (SELECT count(1) + FROM ""ts_group_sub_select01"" o + WHERE (o.""seqid"" = 6)) as4, 3 as5, 5 as6 +FROM ""ts_group_sub_select01"" a +GROUP BY a.""code"", a.""seqid"", a.""name""", sql); + Assert.Equal(2, fsql.Select() + .GroupBy(a => new + { + a.code, + a.seqid, + a.name + }) + .ToList(g => new + { + g.Key.code, + g.Key.seqid, + g.Key.name, + number = fsql.Select() + .Where(o => o.seqid == 6) + .Count(), + number2 = 3, + number3 = 5 + }).Count); + + sql = fsql.Select() + .GroupBy(a => new + { + a.code, + a.seqid, + a.name + }) + .ToSql(g => new + { + g.Key.code, + g.Key.seqid, + g.Key.name, + number = fsql.Select() + .Where(o => o.seqid == g.Key.seqid) + .Count(), + number2 = 3, + number3 = 5 + }); + Assert.Equal(@"SELECT a.""code"" as1, a.""seqid"" as2, a.""name"" as3, (SELECT count(1) + FROM ""ts_group_sub_select01"" o + WHERE (o.""seqid"" = a.""seqid"")) as4, 3 as5, 5 as6 +FROM ""ts_group_sub_select01"" a +GROUP BY a.""code"", a.""seqid"", a.""name""", sql); + Assert.Equal(2, fsql.Select() + .GroupBy(a => new + { + a.code, + a.seqid, + a.name + }) + .ToList(g => new + { + g.Key.code, + g.Key.seqid, + g.Key.name, + number = fsql.Select() + .Where(o => o.seqid == g.Key.seqid) + .Count(), + number2 = 3, + number3 = 5 + }).Count); + } + class ts_group_sub_select01 + { + public Guid id { get; set; } + public string code { get; set; } + public int seqid { get; set; } + public string name { get; set; } + } + [Fact] public void OneToManyLazyloading() { diff --git a/FreeSql.sln b/FreeSql.sln index d159e3c7..fb6b29f9 100644 --- a/FreeSql.sln +++ b/FreeSql.sln @@ -91,8 +91,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.KingbaseES EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.Firebird", "Providers\FreeSql.Provider.Firebird\FreeSql.Provider.Firebird.csproj", "{101B11D2-7780-4E14-9B72-77F5D69B3DF9}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FreeSql.Provider.ElasticsearchSQL", "Providers\FreeSql.Provider.ElasticsearchSQL\FreeSql.Provider.ElasticsearchSQL.csproj", "{EC6980FD-090D-4BAA-8421-0D4C3D306F0D}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -559,18 +557,6 @@ Global {101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x64.Build.0 = Release|Any CPU {101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x86.ActiveCfg = Release|Any CPU {101B11D2-7780-4E14-9B72-77F5D69B3DF9}.Release|x86.Build.0 = Release|Any CPU - {EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Debug|x64.ActiveCfg = Debug|Any CPU - {EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Debug|x64.Build.0 = Debug|Any CPU - {EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Debug|x86.ActiveCfg = Debug|Any CPU - {EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Debug|x86.Build.0 = Debug|Any CPU - {EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Release|Any CPU.Build.0 = Release|Any CPU - {EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Release|x64.ActiveCfg = Release|Any CPU - {EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Release|x64.Build.0 = Release|Any CPU - {EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Release|x86.ActiveCfg = Release|Any CPU - {EC6980FD-090D-4BAA-8421-0D4C3D306F0D}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -603,7 +589,6 @@ Global {3D2BD8EC-253A-437F-B4C8-74BC0D91429B} = {2A381C57-2697-427B-9F10-55DA11FD02E4} {CDD6A896-F6DF-44CB-B430-06B383916EB0} = {2A381C57-2697-427B-9F10-55DA11FD02E4} {101B11D2-7780-4E14-9B72-77F5D69B3DF9} = {2A381C57-2697-427B-9F10-55DA11FD02E4} - {EC6980FD-090D-4BAA-8421-0D4C3D306F0D} = {2A381C57-2697-427B-9F10-55DA11FD02E4} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {089687FD-5D25-40AB-BA8A-A10D1E137F98} diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 756b3fce..3ec2dfa5 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -3760,6 +3760,11 @@ + + + 临时 LambdaExpression.Parameter + + 如果实体类有自增属性,分成两个 List,有值的Item1 merge,无值的Item2 insert diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs index 3ee0d33e..230d9906 100644 --- a/FreeSql/Internal/CommonExpression.cs +++ b/FreeSql/Internal/CommonExpression.cs @@ -18,6 +18,10 @@ namespace FreeSql.Internal { public abstract class BaseDiyMemberExpression { + /// + /// 临时 LambdaExpression.Parameter + /// + public ParameterExpression _lambdaParameter; public ReadAnonymousTypeInfo _map; public string _field; public abstract string ParseExp(Expression[] members); @@ -676,6 +680,7 @@ namespace FreeSql.Internal static ConcurrentDictionary _dicTypeExistsExpressionCallAttribute = new ConcurrentDictionary(); static ConcurrentDictionary> _dicMethodExistsExpressionCallAttribute = new ConcurrentDictionary>(); static ConcurrentDictionary _dicTypeExpressionCallClassContextFields = new ConcurrentDictionary(); + static ThreadLocal> _subSelectParentDiyMemExps = new ThreadLocal>(); //子查询的所有父自定义查询,比如分组之后的子查询 public string ExpressionLambdaToSql(Expression exp, ExpTSC tsc) { if (exp == null) return ""; @@ -982,14 +987,20 @@ namespace FreeSql.Internal fsqltables = fsqlSelect0._tables; //fsqltables[0].Alias = $"{tsc._tables[0].Alias}_{fsqltables[0].Alias}"; if (fsqltables != tsc._tables) - fsqltables.AddRange(tsc._tables.Select(a => new SelectTableInfo + { + if (tsc._tables == null && tsc.diymemexp == null) throw new NotSupportedException($"这个特别的子查询不能解析"); //2020-12-11 IUpdate 条件不支持子查询 + if (tsc._tables != null) //groupby is null { - Alias = a.Alias, - On = "1=1", - Table = a.Table, - Type = SelectTableInfoType.Parent, - Parameter = a.Parameter - })); + fsqltables.AddRange(tsc._tables.Select(a => new SelectTableInfo + { + Alias = a.Alias, + On = "1=1", + Table = a.Table, + Type = SelectTableInfoType.Parent, + Parameter = a.Parameter + })); + } + } if (tsc.whereGlobalFilter?.Any() == true) { var fsqlGlobalFilter = fsqlSelect0._whereGlobalFilter; @@ -1030,7 +1041,28 @@ namespace FreeSql.Internal //if (args[a] == null) ExpressionLambdaToSql(call3Exp.Arguments[a], fsqltables, null, null, SelectTableInfoType.From, true); } } - method.Invoke(fsql, args); + var isSubSelectPdme = tsc._tables == null && tsc.diymemexp != null; + try + { + if (isSubSelectPdme) + { + if (_subSelectParentDiyMemExps.Value == null) _subSelectParentDiyMemExps.Value = new List(); + _subSelectParentDiyMemExps.Value.Add(tsc.diymemexp); + } + method.Invoke(fsql, args); + } + finally + { + if (isSubSelectPdme) + { + var psgpdmes = _subSelectParentDiyMemExps.Value; + if (psgpdmes != null) + { + psgpdmes.RemoveAt(psgpdmes.Count - 1); + if (psgpdmes.Count == 0) _subSelectParentDiyMemExps.Value = null; + } + } + } } if (fsql == null) asSelectBefores.Push(exp3tmp); } @@ -1302,6 +1334,16 @@ namespace FreeSql.Internal var expText = tsc.diymemexp.ParseExp(expStack.Where((a, b) => b >= bidx).ToArray()); if (string.IsNullOrEmpty(expText) == false) return expText; } + var psgpdymes = _subSelectParentDiyMemExps.Value; //解决:分组之后的子查询解析 + if (psgpdymes?.Any() == true) + { + var expStackFirst = expStack.First(); + if (expStackFirst.NodeType == ExpressionType.Parameter) + { + var expText = psgpdymes.Where(a => a._lambdaParameter == expStackFirst).FirstOrDefault()?.ParseExp(expStack.Where((a, b) => b >= 2).ToArray()); + if (string.IsNullOrEmpty(expText) == false) return expText; + } + } if (tsc._tables == null) { diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs index a25b713d..16b05dd3 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs @@ -142,7 +142,11 @@ namespace FreeSql.Internal.CommonProvider public SelectGroupingProvider(IFreeSql orm, Select0Provider select, ReadAnonymousTypeInfo map, string field, CommonExpression comonExp, List tables) :base(orm, select, map, field, comonExp, tables) { } - public string ToSql(Expression, TReturn>> select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex) => InternalToSql(select, fieldAlias); + public string ToSql(Expression, TReturn>> select, FieldAliasOptions fieldAlias = FieldAliasOptions.AsIndex) + { + _lambdaParameter = select?.Parameters[0]; + return InternalToSql(select, fieldAlias); + } public string ToSql(string field) { if (string.IsNullOrEmpty(field)) @@ -180,23 +184,34 @@ namespace FreeSql.Internal.CommonProvider public ISelectGrouping Having(Expression, bool>> exp) { + _lambdaParameter = exp?.Parameters[0]; InternalHaving(exp); return this; } public ISelectGrouping OrderBy(Expression, TMember>> column) { + _lambdaParameter = column?.Parameters[0]; InternalOrderBy(column, false); return this; } public ISelectGrouping OrderByDescending(Expression, TMember>> column) { + _lambdaParameter = column?.Parameters[0]; InternalOrderBy(column, true); return this; } public List Select(Expression, TReturn>> select) => ToList(select); - public List ToList(Expression, TReturn>> select) => InternalToList(select, typeof(TReturn)) as List; - public Dictionary ToDictionary(Expression, TElement>> elementSelector) => InternalToKeyValuePairs(elementSelector, typeof(TElement)).ToDictionary(a => (TKey)a.Key, a => (TElement)a.Value); + public List ToList(Expression, TReturn>> select) + { + _lambdaParameter = select?.Parameters[0]; + return InternalToList(select, typeof(TReturn)) as List; + } + public Dictionary ToDictionary(Expression, TElement>> elementSelector) + { + _lambdaParameter = elementSelector?.Parameters[0]; + return InternalToKeyValuePairs(elementSelector, typeof(TElement)).ToDictionary(a => (TKey)a.Key, a => (TElement)a.Value); + } #if net40 #else @@ -208,6 +223,7 @@ namespace FreeSql.Internal.CommonProvider var field = new StringBuilder(); var index = 0; + _lambdaParameter = select?.Parameters[0]; _comonExp.ReadAnonymousField(null, field, map, ref index, select, null, this, null, null, false); if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TReturn); var method = _select.GetType().GetMethod("ToListMapReaderAsync", BindingFlags.Instance | BindingFlags.NonPublic); @@ -220,6 +236,7 @@ namespace FreeSql.Internal.CommonProvider var field = new StringBuilder(); var index = 0; + _lambdaParameter = elementSelector?.Parameters[0]; _comonExp.ReadAnonymousField(null, field, map, ref index, elementSelector, null, this, null, null, false); if (map.Childs.Any() == false && map.MapType == null) map.MapType = typeof(TElement); var method = _select.GetType().GetMethod("ToListMapReaderPrivateAsync", BindingFlags.Instance | BindingFlags.NonPublic);