From c35c69cf20759ca1b16ab312e4d5e1186391b102 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Thu, 27 Dec 2018 19:16:49 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=86=E7=BB=84=E8=81=9A=E5=90=88=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Docs/select.md | 28 +-- FreeSql.Tests/UnitTest1.cs | 17 +- FreeSql/Interface/Curd/ISelect/ISelect1.cs | 13 +- FreeSql/Interface/Curd/ISelect/ISelect10.cs | 2 +- FreeSql/Interface/Curd/ISelect/ISelect2.cs | 23 --- FreeSql/Interface/Curd/ISelect/ISelect3.cs | 2 +- FreeSql/Interface/Curd/ISelect/ISelect4.cs | 2 +- FreeSql/Interface/Curd/ISelect/ISelect5.cs | 2 +- FreeSql/Interface/Curd/ISelect/ISelect6.cs | 2 +- FreeSql/Interface/Curd/ISelect/ISelect7.cs | 2 +- FreeSql/Interface/Curd/ISelect/ISelect8.cs | 2 +- FreeSql/Interface/Curd/ISelect/ISelect9.cs | 2 +- FreeSql/Interface/Curd/ISelect/ISelectFrom.cs | 7 - .../Interface/Curd/ISelect/ISelectGrouping.cs | 8 + FreeSql/Internal/CommonExpression.cs | 152 +++++++++------- .../Internal/CommonProvider/DeleteProvider.cs | 2 +- .../Internal/CommonProvider/InsertProvider.cs | 4 +- .../SelectProvider/Select0Provider.cs | 40 +++-- .../SelectProvider/Select10Provider.cs | 6 +- .../SelectProvider/Select1Provider.cs | 7 +- .../SelectProvider/Select2Provider.cs | 35 ---- .../SelectProvider/Select3Provider.cs | 6 +- .../SelectProvider/Select4Provider.cs | 6 +- .../SelectProvider/Select5Provider.cs | 6 +- .../SelectProvider/Select6Provider.cs | 6 +- .../SelectProvider/Select7Provider.cs | 6 +- .../SelectProvider/Select8Provider.cs | 6 +- .../SelectProvider/Select9Provider.cs | 6 +- .../SelectProvider/SelectGroupingProvider.cs | 100 +++++++---- .../Internal/CommonProvider/UpdateProvider.cs | 8 +- FreeSql/Internal/Utils.cs | 1 + FreeSql/MySql/Curd/MySqlSelect.cs | 8 +- FreeSql/MySql/MySqlExpression.cs | 160 ++++++++--------- FreeSql/PostgreSQL/Curd/PostgreSQLSelect.cs | 8 +- FreeSql/PostgreSQL/PostgreSQLExpression.cs | 166 +++++++++--------- FreeSql/SqlServer/Curd/SqlServerSelect.cs | 8 +- FreeSql/SqlServer/SqlServerExpression.cs | 164 ++++++++--------- readme.md | 31 +++- 38 files changed, 553 insertions(+), 501 deletions(-) delete mode 100644 FreeSql/Interface/Curd/ISelect/ISelect2.cs delete mode 100644 FreeSql/Internal/CommonProvider/SelectProvider/Select2Provider.cs diff --git a/Docs/select.md b/Docs/select.md index 56ae2b71..60e0ffbb 100644 --- a/Docs/select.md +++ b/Docs/select.md @@ -45,28 +45,28 @@ StartsWith, EndsWith, Contains, ToLower, ToUpper, Substring, Length, IndexOf, Pa ### 单表 ```csharp var sql = select.Where(a => a.Id == 10).ToSql(); -///SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.`Id` = 10) +///SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a.`Title`, a.`CreateTime` FROM `tb_topic` a WHERE (a.`Id` = 10) sql = select.Where(a => a.Id == 10 && a.Id > 10 || a.Clicks > 100).ToSql(); -///SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.`Id` = 10 AND a.`Id` > 10 OR a.`Clicks` > 100) +///SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a.`Title`, a.`CreateTime` FROM `tb_topic` a WHERE (a.`Id` = 10 AND a.`Id` > 10 OR a.`Clicks` > 100) ``` ### 多表,使用导航属性 ```csharp sql = select.Where(a => a.Type.Name == "typeTitle" && a.Type.Guid == a.TestTypeInfoGuid).ToSql(); -///SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a, `TestTypeInfo` a__Type WHERE (a__Type.`Name` = 'typeTitle' AND a__Type.`Guid` = a.`TestTypeInfoGuid`) +///SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a__Type.`Guid`, a__Type.`ParentId`, a__Type.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a, `TestTypeInfo` a__Type WHERE (a__Type.`Name` = 'typeTitle' AND a__Type.`Guid` = a.`TestTypeInfoGuid`) sql = select.Where(a => a.Type.Parent.Name == "tparent").ToSql(); -//SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a, `TestTypeInfo` a__Type, `TestTypeParentInfo` a__Type__Parent WHERE (a__Type__Parent.`Name` = 'tparent') +//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a__Type.`Guid`, a__Type.`ParentId`, a__Type.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a, `TestTypeInfo` a__Type, `TestTypeParentInfo` a__Type__Parent WHERE (a__Type__Parent.`Name` = 'tparent') ``` ### 多表,没有导航属性 ```csharp sql = select.Where((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "typeTitle").ToSql(); -//SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a, `TestTypeInfo` b WHERE (b.`Guid` = a.`TestTypeInfoGuid` AND b.`Name` = 'typeTitle') +//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, b.`Guid`, b.`ParentId`, b.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a, `TestTypeInfo` b WHERE (b.`Guid` = a.`TestTypeInfoGuid` AND b.`Name` = 'typeTitle') sql = select.Where((a, b, c) => c.Name == "tparent").ToSql(); -//SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a, `TestTypeParentInfo` c WHERE (c.`Name` = 'tparent') +//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a.`Title`, a.`CreateTime` FROM `tb_topic` a, `TestTypeParentInfo` c WHERE (c.`Name` = 'tparent') ``` ### 多表,任意查 @@ -74,13 +74,13 @@ sql = select.Where((a, b, c) => c.Name == "tpa sql = select.From((s, b, c) => s .Where(a => a.Id == 10 && c.Name == "xxx") .Where(a => b.ParentId == 20)).ToSql(); -//SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a, `TestTypeParentInfo` c, `TestTypeInfo` b WHERE (a.`Id` = 10 AND c.`Name` = 'xxx') AND (b.`ParentId` = 20) +//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, b.`Guid`, b.`ParentId`, b.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a, `TestTypeParentInfo` c, `TestTypeInfo` b WHERE (a.`Id` = 10 AND c.`Name` = 'xxx') AND (b.`ParentId` = 20) ``` ### 原生SQL ```csharp sql = select.Where("a.clicks > 100 && a.id = ?id", new { id = 10 }).ToSql(); -//SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.clicks > 100 && a.id = ?id) +//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a.`Title`, a.`CreateTime` FROM `tb_topic` a WHERE (a.clicks > 100 && a.id = ?id) ``` > 以上条件查询,支持 WhereIf @@ -90,23 +90,23 @@ sql = select.Where("a.clicks > 100 && a.id = ?id", new { id = 10 }).ToSql(); ### 使用导航属性联表 ```csharp sql = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid).ToSql(); -//SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid` +//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a__Type.`Guid`, a__Type.`ParentId`, a__Type.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a LEFT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid` sql = select .LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid) .LeftJoin(a => a.Type.Parent.Id == a.Type.ParentId).ToSql(); -//SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid` LEFT JOIN `TestTypeParentInfo` a__Type__Parent ON a__Type__Parent.`Id` = a__Type.`ParentId` +//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a__Type.`Guid`, a__Type.`ParentId`, a__Type.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a LEFT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid` LEFT JOIN `TestTypeParentInfo` a__Type__Parent ON a__Type__Parent.`Id` = a__Type.`ParentId` ``` ### 没有导航属性联表 ```csharp sql = select.LeftJoin((a, b) => b.Guid == a.TestTypeInfoGuid).ToSql(); -//SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid` +//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, b.`Guid`, b.`ParentId`, b.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a LEFT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid` sql = select .LeftJoin((a, b) => b.Guid == a.TestTypeInfoGuid) .LeftJoin((a, c) => c.Id == a.Type.ParentId).ToSql(); -//SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid` LEFT JOIN `TestTypeParentInfo` c ON c.`Id` = b.`ParentId` +//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, b.`Guid`, b.`ParentId`, b.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a LEFT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid` LEFT JOIN `TestTypeParentInfo` c ON c.`Id` = b.`ParentId` ``` ### 联表任意查 @@ -114,13 +114,13 @@ sql = select sql = select.From((s, b, c) => s .LeftJoin(a => a.TestTypeInfoGuid == b.Guid) .LeftJoin(a => b.ParentId == c.Id)).ToSql(); -//SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, b.`Guid` as4, b.`ParentId` as5, b.`Name` as6, a.`Title` as7, a.`CreateTime` as8 FROM `tb_topic` a LEFT JOIN `TestTypeInfo` b ON a.`TestTypeInfoGuid` = b.`Guid` LEFT JOIN `TestTypeParentInfo` c ON b.`ParentId` = c.`Id` +//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, b.`Guid`, b.`ParentId`, b.`Name`, a.`Title`, a.`CreateTime` FROM `tb_topic` a LEFT JOIN `TestTypeInfo` b ON a.`TestTypeInfoGuid` = b.`Guid` LEFT JOIN `TestTypeParentInfo` c ON b.`ParentId` = c.`Id` ``` ### 原生SQL联表 ```csharp sql = select.LeftJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = ?bname", new { bname = "xxx" }).ToSql(); -//SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a LEFT JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = ?bname +//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a.`Title`, a.`CreateTime` FROM `tb_topic` a LEFT JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = ?bname ``` # 查询数据 diff --git a/FreeSql.Tests/UnitTest1.cs b/FreeSql.Tests/UnitTest1.cs index 1a2f414e..f17b9ca5 100644 --- a/FreeSql.Tests/UnitTest1.cs +++ b/FreeSql.Tests/UnitTest1.cs @@ -12,13 +12,16 @@ namespace FreeSql.Tests { [Fact] public void Test1() { - //g.mysql.Select().Where(a => a.Id == 1) - // .GroupBy(a => new { tt2 = a.Title.Substring(0, 2), mod4 = a.Id % 4 }) - // .Having(a => a.Count() > 2 && a.Avg(a.Key.mod4) > 0 && a.Key.mod4 > 0) - // .OrderBy(a => a.Key.tt2) - // .OrderByDescending(a => a.Count()) - // .ToList(a => new { a.Key.tt2, cou1 = a.Count(), arg1 = a.Avg(a.Key.mod4) }); - + var groupby = g.mysql.Select().From((s, b, c) => s + .Where(a => a.Id == 1) + ) + .GroupBy((a, b, c) => new { tt2 = a.Title.Substring(0, 2), mod4 = a.Id % 4 }) + .Having(a => a.Count() > 0 && a.Avg(a.Key.mod4) > 0 && a.Max(a.Key.mod4) > 0) + .Having(a => a.Count() < 300 || a.Avg(a.Key.mod4) < 100) + .OrderBy(a => a.Key.tt2) + .OrderByDescending(a => a.Count()) + .ToSql(a => new { a.Key.tt2, cou1 = a.Count(), arg1 = a.Avg(a.Key.mod4) }); + var sss = new[] { 1, 2, 3 }; sss.Count(); diff --git a/FreeSql/Interface/Curd/ISelect/ISelect1.cs b/FreeSql/Interface/Curd/ISelect/ISelect1.cs index fff7de33..fb169eae 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelect1.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelect1.cs @@ -12,6 +12,13 @@ namespace FreeSql { /// 选择列 /// List ToList(Expression> select); + /// + /// 返回即将执行的SQL语句 + /// + /// 返回类型 + /// 选择列 + /// + string ToSql(Expression> select); /// /// 求和 @@ -190,11 +197,11 @@ namespace FreeSql { ISelect Where(Expression> exp) where T2 : class where T3 : class where T4 : class where T5 : class; /// - /// 按选择的列分组,GroupBy(a => a.Name) | GroupBy(a => new{a.Name,a.Time}) | GroupBy(a => new[]{"name","time"}) + /// 按选择的列分组,GroupBy(a => a.Name) | GroupBy(a => new{a.Name,a.Time}) /// - /// + /// /// - ISelect GroupBy(Expression> columns); + ISelectGrouping GroupBy(Expression> exp); /// /// 按列排序,OrderBy(a => a.Time) diff --git a/FreeSql/Interface/Curd/ISelect/ISelect10.cs b/FreeSql/Interface/Curd/ISelect/ISelect10.cs index 5928fd91..c3e6c2db 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelect10.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelect10.cs @@ -15,7 +15,7 @@ namespace FreeSql { ISelect Where(Expression> exp); ISelect WhereIf(bool condition, Expression> exp); - ISelect GroupBy(Expression> columns); + ISelectGrouping GroupBy(Expression> exp); ISelect OrderBy(Expression> column); ISelect OrderByDescending(Expression> column); diff --git a/FreeSql/Interface/Curd/ISelect/ISelect2.cs b/FreeSql/Interface/Curd/ISelect/ISelect2.cs deleted file mode 100644 index 3e232c38..00000000 --- a/FreeSql/Interface/Curd/ISelect/ISelect2.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; - -namespace FreeSql { - public interface ISelect : ISelect0, T1> where T1 : class where T2 : class { - - List ToList(Expression> select); - - TMember Sum(Expression> column); - TMember Min(Expression> column); - TMember Max(Expression> column); - TMember Avg(Expression> column); - - ISelect Where(Expression> exp); - ISelect WhereIf(bool condition, Expression> exp); - - ISelect GroupBy(Expression> columns); - - ISelect OrderBy(Expression> column); - ISelect OrderByDescending(Expression> column); - } -} \ No newline at end of file diff --git a/FreeSql/Interface/Curd/ISelect/ISelect3.cs b/FreeSql/Interface/Curd/ISelect/ISelect3.cs index a7063f12..d5b0b723 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelect3.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelect3.cs @@ -15,7 +15,7 @@ namespace FreeSql { ISelect Where(Expression> exp); ISelect WhereIf(bool condition, Expression> exp); - ISelect GroupBy(Expression> columns); + ISelectGrouping GroupBy(Expression> exp); ISelect OrderBy(Expression> column); ISelect OrderByDescending(Expression> column); diff --git a/FreeSql/Interface/Curd/ISelect/ISelect4.cs b/FreeSql/Interface/Curd/ISelect/ISelect4.cs index 526a2a6d..e4d7ad7f 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelect4.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelect4.cs @@ -15,7 +15,7 @@ namespace FreeSql { ISelect Where(Expression> exp); ISelect WhereIf(bool condition, Expression> exp); - ISelect GroupBy(Expression> columns); + ISelectGrouping GroupBy(Expression> exp); ISelect OrderBy(Expression> column); ISelect OrderByDescending(Expression> column); diff --git a/FreeSql/Interface/Curd/ISelect/ISelect5.cs b/FreeSql/Interface/Curd/ISelect/ISelect5.cs index 856259ca..186a1aee 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelect5.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelect5.cs @@ -15,7 +15,7 @@ namespace FreeSql { ISelect Where(Expression> exp); ISelect WhereIf(bool condition, Expression> exp); - ISelect GroupBy(Expression> columns); + ISelectGrouping GroupBy(Expression> exp); ISelect OrderBy(Expression> column); ISelect OrderByDescending(Expression> column); diff --git a/FreeSql/Interface/Curd/ISelect/ISelect6.cs b/FreeSql/Interface/Curd/ISelect/ISelect6.cs index 1a0c864d..a1767ff7 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelect6.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelect6.cs @@ -15,7 +15,7 @@ namespace FreeSql { ISelect Where(Expression> exp); ISelect WhereIf(bool condition, Expression> exp); - ISelect GroupBy(Expression> columns); + ISelectGrouping GroupBy(Expression> exp); ISelect OrderBy(Expression> column); ISelect OrderByDescending(Expression> column); diff --git a/FreeSql/Interface/Curd/ISelect/ISelect7.cs b/FreeSql/Interface/Curd/ISelect/ISelect7.cs index 6590be33..acd67af9 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelect7.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelect7.cs @@ -15,7 +15,7 @@ namespace FreeSql { ISelect Where(Expression> exp); ISelect WhereIf(bool condition, Expression> exp); - ISelect GroupBy(Expression> columns); + ISelectGrouping GroupBy(Expression> exp); ISelect OrderBy(Expression> column); ISelect OrderByDescending(Expression> column); diff --git a/FreeSql/Interface/Curd/ISelect/ISelect8.cs b/FreeSql/Interface/Curd/ISelect/ISelect8.cs index e56638c5..4ef41d90 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelect8.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelect8.cs @@ -15,7 +15,7 @@ namespace FreeSql { ISelect Where(Expression> exp); ISelect WhereIf(bool condition, Expression> exp); - ISelect GroupBy(Expression> columns); + ISelectGrouping GroupBy(Expression> exp); ISelect OrderBy(Expression> column); ISelect OrderByDescending(Expression> column); diff --git a/FreeSql/Interface/Curd/ISelect/ISelect9.cs b/FreeSql/Interface/Curd/ISelect/ISelect9.cs index f11133da..3bd25b51 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelect9.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelect9.cs @@ -15,7 +15,7 @@ namespace FreeSql { ISelect Where(Expression> exp); ISelect WhereIf(bool condition, Expression> exp); - ISelect GroupBy(Expression> columns); + ISelectGrouping GroupBy(Expression> exp); ISelect OrderBy(Expression> column); ISelect OrderByDescending(Expression> column); diff --git a/FreeSql/Interface/Curd/ISelect/ISelectFrom.cs b/FreeSql/Interface/Curd/ISelect/ISelectFrom.cs index 4bc2981b..9150034e 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelectFrom.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelectFrom.cs @@ -23,13 +23,6 @@ namespace FreeSql { /// ISelectFromExpression WhereIf(bool condition, Expression> exp); - /// - /// 按选择的列分组,GroupBy(a => a.Name) | GroupBy(a => new{a.Name,a.Time}) | GroupBy(a => new[]{"name","time"}) - /// - /// - /// - ISelectFromExpression GroupBy(Expression> columns); - /// /// 按列排序,OrderBy(a => a.Time) /// diff --git a/FreeSql/Interface/Curd/ISelect/ISelectGrouping.cs b/FreeSql/Interface/Curd/ISelect/ISelectGrouping.cs index 876532f9..7659a084 100644 --- a/FreeSql/Interface/Curd/ISelect/ISelectGrouping.cs +++ b/FreeSql/Interface/Curd/ISelect/ISelectGrouping.cs @@ -33,6 +33,14 @@ namespace FreeSql { /// 选择列 /// List ToList(Expression, TReturn>> select); + + /// + /// 返回即将执行的SQL语句 + /// + /// 返回类型 + /// 选择列 + /// + string ToSql(Expression, TReturn>> select); } public interface ISelectGroupingAggregate { diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs index 304fef5e..e6a65446 100644 --- a/FreeSql/Internal/CommonExpression.cs +++ b/FreeSql/Internal/CommonExpression.cs @@ -13,39 +13,44 @@ namespace FreeSql.Internal { _common = common; } - internal bool ReadAnonymousField(List _tables, StringBuilder field, ReadAnonymousTypeInfo parent, ref int index, Expression exp) { + internal bool ReadAnonymousField(List _tables, StringBuilder field, ReadAnonymousTypeInfo parent, ref int index, Expression exp, Func getSelectGroupingMapString) { switch (exp.NodeType) { - case ExpressionType.Quote: return ReadAnonymousField(_tables, field, parent, ref index, (exp as UnaryExpression)?.Operand); - case ExpressionType.Lambda: return ReadAnonymousField(_tables, field, parent, ref index, (exp as LambdaExpression)?.Body); + case ExpressionType.Quote: return ReadAnonymousField(_tables, field, parent, ref index, (exp as UnaryExpression)?.Operand, getSelectGroupingMapString); + case ExpressionType.Lambda: return ReadAnonymousField(_tables, field, parent, ref index, (exp as LambdaExpression)?.Body, getSelectGroupingMapString); case ExpressionType.Negate: case ExpressionType.NegateChecked: - parent.DbField = $"-{ExpressionLambdaToSql(exp, _tables, null, SelectTableInfoType.From, true)}"; - field.Append(", ").Append(parent.DbField).Append(" as").Append(++index); + parent.DbField = $"-({ExpressionLambdaToSql(exp, _tables, null, getSelectGroupingMapString, SelectTableInfoType.From, true)})"; + field.Append(", ").Append(parent.DbField); + if (index >= 0) field.Append(" as").Append(++index); return false; - case ExpressionType.Convert: return ReadAnonymousField(_tables, field, parent, ref index, (exp as UnaryExpression)?.Operand); + case ExpressionType.Convert: return ReadAnonymousField(_tables, field, parent, ref index, (exp as UnaryExpression)?.Operand, getSelectGroupingMapString); case ExpressionType.Constant: var constExp = exp as ConstantExpression; parent.DbField = _common.FormatSql("{0}", constExp?.Value); - field.Append(", ").Append(parent.DbField).Append(" as").Append(++index); + field.Append(", ").Append(parent.DbField); + if (index >= 0) field.Append(" as").Append(++index); return false; case ExpressionType.Call: - parent.DbField = ExpressionLambdaToSql(exp, _tables, null, SelectTableInfoType.From, true); - field.Append(", ").Append(parent.DbField).Append(" as").Append(++index); + parent.DbField = ExpressionLambdaToSql(exp, _tables, null, getSelectGroupingMapString, SelectTableInfoType.From, true); + field.Append(", ").Append(parent.DbField); + if (index >= 0) field.Append(" as").Append(++index); return false; case ExpressionType.MemberAccess: if (_common.GetTableByEntity(exp.Type) != null) { //加载表所有字段 var map = new List(); - ExpressionSelectColumn_MemberAccess(_tables, map, SelectTableInfoType.From, exp, true); + ExpressionSelectColumn_MemberAccess(_tables, map, SelectTableInfoType.From, exp, true, getSelectGroupingMapString); parent.Consturctor = map.First().Table.Table.Type.GetConstructor(new Type[0]); parent.ConsturctorType = ReadAnonymousTypeInfoConsturctorType.Properties; for (var idx = 0; idx < map.Count; idx++) { var child = new ReadAnonymousTypeInfo { CsName = map[idx].Column.CsName, DbField = $"{map[idx].Table.Alias}.{_common.QuoteSqlName(map[idx].Column.Attribute.Name)}" }; - field.Append(", ").Append(_common.QuoteReadColumn(map[idx].Column.CsType, child.DbField)).Append(" as").Append(++index); + field.Append(", ").Append(_common.QuoteReadColumn(map[idx].Column.CsType, child.DbField)); + if (index >= 0) field.Append(" as").Append(++index); parent.Childs.Add(child); } } else { - parent.DbField = ExpressionLambdaToSql(exp, _tables, null, SelectTableInfoType.From, true); - field.Append(", ").Append(parent.DbField).Append(" as").Append(++index); + parent.DbField = ExpressionLambdaToSql(exp, _tables, null, getSelectGroupingMapString, SelectTableInfoType.From, true); + field.Append(", ").Append(parent.DbField); + if (index >= 0) field.Append(" as").Append(++index); return false; } return false; @@ -56,10 +61,13 @@ namespace FreeSql.Internal { for (var a = 0; a < newExp.Members.Count; a++) { var child = new ReadAnonymousTypeInfo { CsName = newExp.Members[a].Name, CsType = newExp.Arguments[a].Type }; parent.Childs.Add(child); - ReadAnonymousField(_tables, field, child, ref index, newExp.Arguments[a]); + ReadAnonymousField(_tables, field, child, ref index, newExp.Arguments[a], getSelectGroupingMapString); } return true; } + parent.DbField = $"({ExpressionLambdaToSql(exp, _tables, null, getSelectGroupingMapString, SelectTableInfoType.From, true)})"; + field.Append(", ").Append(parent.DbField); + if (index >= 0) field.Append(" as").Append(++index); return false; } internal object ReadAnonymous(ReadAnonymousTypeInfo parent, object[] dr, ref int index) { @@ -83,28 +91,28 @@ namespace FreeSql.Internal { internal string ExpressionConstant(ConstantExpression exp) => _common.FormatSql("{0}", exp?.Value); - internal string ExpressionSelectColumn_MemberAccess(List _tables, List _selectColumnMap, SelectTableInfoType tbtype, Expression exp, bool isQuoteName) { - return ExpressionLambdaToSql(exp, _tables, _selectColumnMap, tbtype, isQuoteName); + internal string ExpressionSelectColumn_MemberAccess(List _tables, List _selectColumnMap, SelectTableInfoType tbtype, Expression exp, bool isQuoteName, Func getSelectGroupingMapString) { + return ExpressionLambdaToSql(exp, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); } - internal string[] ExpressionSelectColumns_MemberAccess_New_NewArrayInit(List _tables, Expression exp, bool isQuoteName) { + internal string[] ExpressionSelectColumns_MemberAccess_New_NewArrayInit(List _tables, Expression exp, bool isQuoteName, Func getSelectGroupingMapString) { switch (exp?.NodeType) { - case ExpressionType.Quote: return ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, (exp as UnaryExpression)?.Operand, isQuoteName); - case ExpressionType.Lambda: return ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, (exp as LambdaExpression)?.Body, isQuoteName); - case ExpressionType.Convert: return ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, (exp as UnaryExpression)?.Operand, isQuoteName); - case ExpressionType.Constant: return new[] { ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, isQuoteName) }; - case ExpressionType.MemberAccess: return new[] { ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, isQuoteName) }; + case ExpressionType.Quote: return ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, (exp as UnaryExpression)?.Operand, isQuoteName, getSelectGroupingMapString); + case ExpressionType.Lambda: return ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, (exp as LambdaExpression)?.Body, isQuoteName, getSelectGroupingMapString); + case ExpressionType.Convert: return ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, (exp as UnaryExpression)?.Operand, isQuoteName, getSelectGroupingMapString); + case ExpressionType.Constant: return new[] { ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, isQuoteName, getSelectGroupingMapString) }; + case ExpressionType.MemberAccess: return new[] { ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, isQuoteName, getSelectGroupingMapString) }; case ExpressionType.New: var newExp = exp as NewExpression; if (newExp == null) break; var newExpMembers = new string[newExp.Members.Count]; - for (var a = 0; a < newExpMembers.Length; a++) newExpMembers[a] = ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, newExp.Arguments[a], isQuoteName); + for (var a = 0; a < newExpMembers.Length; a++) newExpMembers[a] = ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, newExp.Arguments[a], isQuoteName, getSelectGroupingMapString); return newExpMembers; case ExpressionType.NewArrayInit: var newArr = exp as NewArrayExpression; if (newArr == null) break; var newArrMembers = new List(); - foreach (var newArrExp in newArr.Expressions) newArrMembers.AddRange(ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, newArrExp, isQuoteName)); + foreach (var newArrExp in newArr.Expressions) newArrMembers.AddRange(ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, newArrExp, isQuoteName, getSelectGroupingMapString)); return newArrMembers.ToArray(); } return new string[0]; @@ -127,8 +135,8 @@ namespace FreeSql.Internal { { ExpressionType.Modulo, "%" }, { ExpressionType.Equal, "=" }, }; - internal string ExpressionWhereLambdaNoneForeignObject(List _tables, List _selectColumnMap, Expression exp) { - var sql = ExpressionLambdaToSql(exp, _tables, _selectColumnMap, SelectTableInfoType.From, true); + internal string ExpressionWhereLambdaNoneForeignObject(List _tables, List _selectColumnMap, Expression exp, Func getSelectGroupingMapString) { + var sql = ExpressionLambdaToSql(exp, _tables, _selectColumnMap, getSelectGroupingMapString, SelectTableInfoType.From, true); switch(sql) { case "1": case "'t'": return "1=1"; @@ -138,8 +146,8 @@ namespace FreeSql.Internal { } } - internal string ExpressionWhereLambda(List _tables, Expression exp) { - var sql = ExpressionLambdaToSql(exp, _tables, null, SelectTableInfoType.From, true); + internal string ExpressionWhereLambda(List _tables, Expression exp, Func getSelectGroupingMapString) { + var sql = ExpressionLambdaToSql(exp, _tables, null, getSelectGroupingMapString, SelectTableInfoType.From, true); switch (sql) { case "1": case "'t'": return "1=1"; @@ -148,9 +156,9 @@ namespace FreeSql.Internal { default: return sql; } } - internal void ExpressionJoinLambda(List _tables, SelectTableInfoType tbtype, Expression exp) { + internal void ExpressionJoinLambda(List _tables, SelectTableInfoType tbtype, Expression exp, Func getSelectGroupingMapString) { var tbidx = _tables.Count; - var filter = ExpressionLambdaToSql(exp, _tables, null, tbtype, true); + var filter = ExpressionLambdaToSql(exp, _tables, null, getSelectGroupingMapString, tbtype, true); switch (filter) { case "1": case "'t'": filter = "1=1"; break; @@ -169,35 +177,46 @@ namespace FreeSql.Internal { } } - internal string ExpressionLambdaToSql(Expression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal string ExpressionLambdaToSql(Expression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { switch (exp.NodeType) { - case ExpressionType.Quote: return ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, tbtype, isQuoteName); - case ExpressionType.Lambda: return ExpressionLambdaToSql((exp as LambdaExpression)?.Body, _tables, _selectColumnMap, tbtype, isQuoteName); - case ExpressionType.Convert: return ExpressionLambdaToSql((exp as UnaryExpression)?.Operand, _tables, _selectColumnMap, 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, tbtype, isQuoteName); + 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, tbtype, isQuoteName)} then {ExpressionLambdaToSql(condExp.IfTrue, _tables, _selectColumnMap, tbtype, isQuoteName)} else {ExpressionLambdaToSql(condExp.IfFalse, _tables, _selectColumnMap, tbtype, isQuoteName)} end"; + 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; - switch (exp3.Object?.Type.FullName ?? exp3.Method.DeclaringType.FullName) { - case "System.String": return ExpressionLambdaToSqlCallString(exp3, _tables, _selectColumnMap, tbtype, isQuoteName); - case "System.Math": return ExpressionLambdaToSqlCallMath(exp3, _tables, _selectColumnMap, tbtype, isQuoteName); - case "System.DateTime": return ExpressionLambdaToSqlCallDateTime(exp3, _tables, _selectColumnMap, tbtype, isQuoteName); - case "System.TimeSpan": return ExpressionLambdaToSqlCallTimeSpan(exp3, _tables, _selectColumnMap, tbtype, isQuoteName); - case "System.Convert": return ExpressionLambdaToSqlCallConvert(exp3, _tables, _selectColumnMap, tbtype, isQuoteName); + 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); } - throw new Exception($"MySqlExpression 未现实函数表达式 {exp3} 解析"); + 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)})"; + } + } + 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, tbtype, isQuoteName); + 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 = ""; - switch (exp4.Expression?.Type.FullName ?? exp4.Type.FullName) { - case "System.String": extRet = ExpressionLambdaToSqlMemberAccessString(exp4, _tables, _selectColumnMap, tbtype, isQuoteName); break; - case "System.DateTime": extRet = ExpressionLambdaToSqlMemberAccessDateTime(exp4, _tables, _selectColumnMap, tbtype, isQuoteName); break; - case "System.TimeSpan": extRet = ExpressionLambdaToSqlMemberAccessTimeSpan(exp4, _tables, _selectColumnMap, tbtype, isQuoteName); break; + 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; @@ -228,7 +247,18 @@ namespace FreeSql.Internal { break; } if (expStack.First().NodeType != ExpressionType.Parameter) return _common.FormatSql("{0}", Expression.Lambda(exp).Compile().DynamicInvoke()); - if (callExp != null) return ExpressionLambdaToSql(callExp, _tables, _selectColumnMap, tbtype, isQuoteName); + if (callExp != null) return ExpressionLambdaToSql(callExp, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + if (getSelectGroupingMapString != null && expStack.First().Type.FullName.StartsWith("FreeSql.ISelectGroupingAggregate`")) { + var expText = getSelectGroupingMapString(expStack.Where((a, b) => b >= 2).ToArray()); + if (string.IsNullOrEmpty(expText) == false) return expText; + } + //if (exp4.Expression != null && exp4.Expression.NodeType == ExpressionType.MemberAccess) { + // var keyExp = exp4.Expression as MemberExpression; + // if (keyExp.Member.Name == "Key" && keyExp.Expression.Type.FullName.StartsWith("FreeSql.ISelectGroupingAggregate`")) { + // var expText = getSelectGroupingMapString(exp4) + // } + //} + if (_tables == null) { var pp = expStack.Pop() as ParameterExpression; var memberExp = expStack.Pop() as MemberExpression; @@ -300,12 +330,12 @@ namespace FreeSql.Internal { if (expBinary == null) return ""; if (expBinary.NodeType == ExpressionType.Coalesce) { return _common.IsNull( - ExpressionLambdaToSql(expBinary.Left, _tables, _selectColumnMap, tbtype, isQuoteName), - ExpressionLambdaToSql(expBinary.Right, _tables, _selectColumnMap, tbtype, isQuoteName)); + 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, tbtype, isQuoteName); - var right = ExpressionLambdaToSql(expBinary.Right, _tables, _selectColumnMap, tbtype, isQuoteName); + 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; @@ -316,13 +346,13 @@ namespace FreeSql.Internal { return $"{left} {tryoper} {right}"; } - internal abstract string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName); - internal abstract string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName); - internal abstract string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName); - internal abstract string ExpressionLambdaToSqlCallString(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName); - internal abstract string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName); - internal abstract string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName); - internal abstract string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName); - internal abstract string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName); + internal abstract string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName); + internal abstract string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName); + internal abstract string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName); + internal abstract string ExpressionLambdaToSqlCallString(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName); + internal abstract string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName); + internal abstract string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName); + internal abstract string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName); + internal abstract string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName); } } diff --git a/FreeSql/Internal/CommonProvider/DeleteProvider.cs b/FreeSql/Internal/CommonProvider/DeleteProvider.cs index 35fbad2c..44ff8826 100644 --- a/FreeSql/Internal/CommonProvider/DeleteProvider.cs +++ b/FreeSql/Internal/CommonProvider/DeleteProvider.cs @@ -35,7 +35,7 @@ namespace FreeSql.Internal.CommonProvider { } public abstract List ExecuteDeleted(); - public IDelete Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambdaNoneForeignObject(null, null, exp?.Body)); + public IDelete Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambdaNoneForeignObject(null, null, exp?.Body, null)); public IDelete Where(string sql, object parms = null) { if (string.IsNullOrEmpty(sql)) return this; if (++_whereTimes > 1) _where.Append(" AND "); diff --git a/FreeSql/Internal/CommonProvider/InsertProvider.cs b/FreeSql/Internal/CommonProvider/InsertProvider.cs index 5896ae43..5cb9399a 100644 --- a/FreeSql/Internal/CommonProvider/InsertProvider.cs +++ b/FreeSql/Internal/CommonProvider/InsertProvider.cs @@ -40,13 +40,13 @@ namespace FreeSql.Internal.CommonProvider { public abstract List ExecuteInserted(); public IInsert IgnoreColumns(Expression> columns) { - var cols = _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false).Distinct(); + var cols = _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false, null).Distinct(); _ignore.Clear(); foreach (var col in cols) _ignore.Add(col, true); return this; } public IInsert InsertColumns(Expression> columns) { - var cols = _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false).ToDictionary(a => a, a => true); + var cols = _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false, null).ToDictionary(a => a, a => true); _ignore.Clear(); foreach (var col in _table.Columns.Values) if (cols.ContainsKey(col.Attribute.Name) == false) diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs index 515b48f9..71ee06bf 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select0Provider.cs @@ -108,7 +108,8 @@ namespace FreeSql.Internal.CommonProvider { public TSelect OrderBy(string sql, object parms = null) { if (string.IsNullOrEmpty(sql)) _orderby = null; - _orderby = string.Concat(string.IsNullOrEmpty(_orderby) ? " \r\nORDER BY " : "", _orderby, sql); + var isnull = string.IsNullOrEmpty(_orderby); + _orderby = string.Concat(isnull ? " \r\nORDER BY " : "", _orderby, isnull ? "" : ", ", sql); if (parms != null) _params.AddRange(_commonUtils.GetDbParamtersByObject(sql, parms)); return this as TSelect; } @@ -146,14 +147,14 @@ namespace FreeSql.Internal.CommonProvider { }); } public List ToList() { - return this.ToList(this.GetAllField()); + return this.ToListMapReader(this.GetAllField()); } public T1 ToOne() { this.Limit(1); return ToList().FirstOrDefault(); } - protected List ToList((ReadAnonymousTypeInfo map, string field) af) { + protected List ToListMapReader((ReadAnonymousTypeInfo map, string field) af) { var sql = this.ToSql(af.field); if (_cache.seconds > 0 && string.IsNullOrEmpty(_cache.key)) _cache.key = $"{sql}{string.Join("|", _params.Select(a => a.Value))}"; @@ -171,7 +172,7 @@ namespace FreeSql.Internal.CommonProvider { var field = new StringBuilder(); var index = 0; - _commonExpression.ReadAnonymousField(_tables, field, map, ref index, newexp); + _commonExpression.ReadAnonymousField(_tables, field, map, ref index, newexp, null); return (map, map.Childs.Count > 0 ? field.Remove(0, 2).ToString() : null); } protected (ReadAnonymousTypeInfo map, string field) GetAllField() { @@ -222,31 +223,38 @@ namespace FreeSql.Internal.CommonProvider { } #region common - protected TMember InternalAvg(Expression exp) => this.ToList($"avg({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true)})").FirstOrDefault(); - protected TMember InternalMax(Expression exp) => this.ToList($"max({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true)})").FirstOrDefault(); - protected TMember InternalMin(Expression exp) => this.ToList($"min({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true)})").FirstOrDefault(); - protected TMember InternalSum(Expression exp) => this.ToList($"sum({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true)})").FirstOrDefault(); + protected TMember InternalAvg(Expression exp) => this.ToList($"avg({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)})").FirstOrDefault(); + protected TMember InternalMax(Expression exp) => this.ToList($"max({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)})").FirstOrDefault(); + protected TMember InternalMin(Expression exp) => this.ToList($"min({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)})").FirstOrDefault(); + protected TMember InternalSum(Expression exp) => this.ToList($"sum({_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, exp, true, null)})").FirstOrDefault(); - protected TSelect InternalGroupBy(Expression columns) { - return this.GroupBy(string.Join(", ", _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_tables, columns, true))); + protected ISelectGrouping InternalGroupBy(Expression columns) { + var map = new ReadAnonymousTypeInfo(); + var field = new StringBuilder(); + var index = -10000; //临时规则,不返回 as1 + + _commonExpression.ReadAnonymousField(_tables, field, map, ref index, columns, null); + this.GroupBy(map.Childs.Count > 0 ? field.Remove(0, 2).ToString() : null); + return new SelectGroupingProvider(this, map, _commonExpression); } protected TSelect InternalJoin(Expression exp, SelectTableInfoType joinType) { - _commonExpression.ExpressionJoinLambda(_tables, joinType, exp); + _commonExpression.ExpressionJoinLambda(_tables, joinType, exp, null); return this as TSelect; } protected TSelect InternalJoin(Expression exp, SelectTableInfoType joinType) { var tb = _commonUtils.GetTableByEntity(typeof(T2)); if (tb == null) throw new ArgumentException("T2 类型错误"); _tables.Add(new SelectTableInfo { Table = tb, Alias = $"IJ{_tables.Count}", On = null, Type = joinType }); - _commonExpression.ExpressionJoinLambda(_tables, joinType, exp); + _commonExpression.ExpressionJoinLambda(_tables, joinType, exp, null); return this as TSelect; } - protected TSelect InternalOrderBy(Expression column) => this.OrderBy(_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true)); - protected TSelect InternalOrderByDescending(Expression column) => this.OrderBy($"{_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true)} DESC"); + protected TSelect InternalOrderBy(Expression column) => this.OrderBy(_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null)); + protected TSelect InternalOrderByDescending(Expression column) => this.OrderBy($"{_commonExpression.ExpressionSelectColumn_MemberAccess(_tables, null, SelectTableInfoType.From, column, true, null)} DESC"); - protected List InternalToList(Expression select) => this.ToList(this.GetNewExpressionField(select as NewExpression)); + protected List InternalToList(Expression select) => this.ToListMapReader(this.GetNewExpressionField(select as NewExpression)); + protected string InternalToSql(Expression select) => this.ToSql(this.GetNewExpressionField(select as NewExpression).field); - protected TSelect InternalWhere(Expression exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp)); + protected TSelect InternalWhere(Expression exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp, null)); protected TSelect InternalJoin(Expression exp) { return this as TSelect; diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select10Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select10Provider.cs index 98547b2a..fd2ed9a3 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select10Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select10Provider.cs @@ -22,7 +22,7 @@ namespace FreeSql.Internal.CommonProvider { TMember ISelect.Avg(Expression> column) => this.InternalAvg(column?.Body); - ISelect ISelect.GroupBy(Expression> columns) => this.InternalGroupBy(columns?.Body); + ISelectGrouping ISelect.GroupBy(Expression> exp) => this.InternalGroupBy(exp?.Body); TMember ISelect.Max(Expression> column) => this.InternalMax(column?.Body); @@ -36,8 +36,8 @@ namespace FreeSql.Internal.CommonProvider { List ISelect.ToList(Expression> select) => this.InternalToList(select?.Body); - ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)); + ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)); - ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this; + ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)) : this; } } \ No newline at end of file diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs index fbaa29cb..d76875e2 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select1Provider.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using System.Text; namespace FreeSql.Internal.CommonProvider { @@ -26,11 +27,10 @@ namespace FreeSql.Internal.CommonProvider { switch (expCall.Method.Name) { case "Where": this.InternalWhere(expCall.Arguments[0]); break; case "WhereIf": - var whereIfCond = _commonExpression.ExpressionSelectColumn_MemberAccess(null, null, SelectTableInfoType.From, expCall.Arguments[0], false); + var whereIfCond = _commonExpression.ExpressionSelectColumn_MemberAccess(null, null, SelectTableInfoType.From, expCall.Arguments[0], false, null); if (whereIfCond == "1" || whereIfCond == "'t'") this.InternalWhere(expCall.Arguments[1]); break; - case "GroupBy": this.InternalGroupBy(expCall.Arguments[0]); break; case "OrderBy": this.InternalOrderBy(expCall.Arguments[0]); break; case "OrderByDescending": this.InternalOrderByDescending(expCall.Arguments[0]); break; @@ -74,7 +74,7 @@ namespace FreeSql.Internal.CommonProvider { public abstract ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression>> exp) where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : class where T10 : class;// { this.InternalFrom(exp?.Body); var ret = new Select10Provider(_orm, _commonUtils, _commonExpression, null); Select0Provider, T1>.CopyData(this, ret); return ret; } - public ISelect GroupBy(Expression> columns) => this.InternalGroupBy(columns?.Body); + public ISelectGrouping GroupBy(Expression> columns) => this.InternalGroupBy(columns); public TMember Max(Expression> column) => this.InternalMax(column?.Body); @@ -87,6 +87,7 @@ namespace FreeSql.Internal.CommonProvider { public TMember Sum(Expression> column) => this.InternalSum(column?.Body); public List ToList(Expression> select) => this.InternalToList(select?.Body); + public string ToSql(Expression> select) => this.InternalToSql(select?.Body); public ISelect Where(Expression> exp) => this.InternalWhere(exp?.Body); diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select2Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select2Provider.cs deleted file mode 100644 index 630e3b4a..00000000 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select2Provider.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq.Expressions; - -namespace FreeSql.Internal.CommonProvider { - - abstract class Select2Provider : Select0Provider, T1>, ISelect - where T1 : class - where T2 : class { - - public Select2Provider(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { - if (_orm.CodeFirst.IsAutoSyncStructure) _orm.CodeFirst.SyncStructure(); - } - - TMember ISelect.Avg(Expression> column) => this.InternalAvg(column?.Body); - - ISelect ISelect.GroupBy(Expression> columns) => this.InternalGroupBy(columns?.Body); - - TMember ISelect.Max(Expression> column) => this.InternalMax(column?.Body); - - TMember ISelect.Min(Expression> column) => this.InternalMin(column?.Body); - - ISelect ISelect.OrderBy(Expression> column) => this.InternalOrderBy(column?.Body); - - ISelect ISelect.OrderByDescending(Expression> column) => this.InternalOrderByDescending(column?.Body); - - TMember ISelect.Sum(Expression> column) => this.InternalSum(column?.Body); - - List ISelect.ToList(Expression> select) => this.InternalToList(select?.Body); - - ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)); - - ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this; - } -} \ No newline at end of file diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select3Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select3Provider.cs index 14fb6ef1..fecab1d0 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select3Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select3Provider.cs @@ -15,7 +15,7 @@ namespace FreeSql.Internal.CommonProvider { TMember ISelect.Avg(Expression> column) => this.InternalAvg(column?.Body); - ISelect ISelect.GroupBy(Expression> columns) => this.InternalGroupBy(columns?.Body); + ISelectGrouping ISelect.GroupBy(Expression> exp) => this.InternalGroupBy(exp?.Body); TMember ISelect.Max(Expression> column) => this.InternalMax(column?.Body); @@ -29,8 +29,8 @@ namespace FreeSql.Internal.CommonProvider { List ISelect.ToList(Expression> select) => this.InternalToList(select?.Body); - ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)); + ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)); - ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this; + ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)) : this; } } \ No newline at end of file diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select4Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select4Provider.cs index 8bb92273..4c8f4302 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select4Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select4Provider.cs @@ -16,7 +16,7 @@ namespace FreeSql.Internal.CommonProvider { TMember ISelect.Avg(Expression> column) => this.InternalAvg(column?.Body); - ISelect ISelect.GroupBy(Expression> columns) => this.InternalGroupBy(columns?.Body); + ISelectGrouping ISelect.GroupBy(Expression> exp) => this.InternalGroupBy(exp?.Body); TMember ISelect.Max(Expression> column) => this.InternalMax(column?.Body); @@ -30,8 +30,8 @@ namespace FreeSql.Internal.CommonProvider { List ISelect.ToList(Expression> select) => this.InternalToList(select?.Body); - ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)); + ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)); - ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this; + ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)) : this; } } diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select5Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select5Provider.cs index 36062060..65428796 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select5Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select5Provider.cs @@ -17,7 +17,7 @@ namespace FreeSql.Internal.CommonProvider { TMember ISelect.Avg(Expression> column) => this.InternalAvg(column?.Body); - ISelect ISelect.GroupBy(Expression> columns) => this.InternalGroupBy(columns?.Body); + ISelectGrouping ISelect.GroupBy(Expression> exp) => this.InternalGroupBy(exp?.Body); TMember ISelect.Max(Expression> column) => this.InternalMax(column?.Body); @@ -31,8 +31,8 @@ namespace FreeSql.Internal.CommonProvider { List ISelect.ToList(Expression> select) => this.InternalToList(select?.Body); - ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)); + ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)); - ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this; + ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)) : this; } } diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select6Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select6Provider.cs index 73c6a295..fc7342cf 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select6Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select6Provider.cs @@ -18,7 +18,7 @@ namespace FreeSql.Internal.CommonProvider { TMember ISelect.Avg(Expression> column) => this.InternalAvg(column?.Body); - ISelect ISelect.GroupBy(Expression> columns) => this.InternalGroupBy(columns?.Body); + ISelectGrouping ISelect.GroupBy(Expression> exp) => this.InternalGroupBy(exp?.Body); TMember ISelect.Max(Expression> column) => this.InternalMax(column?.Body); @@ -32,8 +32,8 @@ namespace FreeSql.Internal.CommonProvider { List ISelect.ToList(Expression> select) => this.InternalToList(select?.Body); - ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)); + ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)); - ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this; + ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)) : this; } } \ No newline at end of file diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select7Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select7Provider.cs index 2da30e2e..8014c0c0 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select7Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select7Provider.cs @@ -19,7 +19,7 @@ namespace FreeSql.Internal.CommonProvider { TMember ISelect.Avg(Expression> column) => this.InternalAvg(column?.Body); - ISelect ISelect.GroupBy(Expression> columns) => this.InternalGroupBy(columns?.Body); + ISelectGrouping ISelect.GroupBy(Expression> exp) => this.InternalGroupBy(exp?.Body); TMember ISelect.Max(Expression> column) => this.InternalMax(column?.Body); @@ -33,8 +33,8 @@ namespace FreeSql.Internal.CommonProvider { List ISelect.ToList(Expression> select) => this.InternalToList(select?.Body); - ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)); + ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)); - ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this; + ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)) : this; } } \ No newline at end of file diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select8Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select8Provider.cs index c0ef0b26..6b9ff4c7 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select8Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select8Provider.cs @@ -20,7 +20,7 @@ namespace FreeSql.Internal.CommonProvider { TMember ISelect.Avg(Expression> column) => this.InternalAvg(column?.Body); - ISelect ISelect.GroupBy(Expression> columns) => this.InternalGroupBy(columns?.Body); + ISelectGrouping ISelect.GroupBy(Expression> exp) => this.InternalGroupBy(exp?.Body); TMember ISelect.Max(Expression> column) => this.InternalMax(column?.Body); @@ -34,8 +34,8 @@ namespace FreeSql.Internal.CommonProvider { List ISelect.ToList(Expression> select) => this.InternalToList(select?.Body); - ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)); + ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)); - ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this; + ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)) : this; } } \ No newline at end of file diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/Select9Provider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/Select9Provider.cs index 1df87e3b..e96a0f97 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/Select9Provider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/Select9Provider.cs @@ -21,7 +21,7 @@ namespace FreeSql.Internal.CommonProvider { TMember ISelect.Avg(Expression> column) => this.InternalAvg(column?.Body); - ISelect ISelect.GroupBy(Expression> columns) => this.InternalGroupBy(columns?.Body); + ISelectGrouping ISelect.GroupBy(Expression> exp) => this.InternalGroupBy(exp?.Body); TMember ISelect.Max(Expression> column) => this.InternalMax(column?.Body); @@ -35,8 +35,8 @@ namespace FreeSql.Internal.CommonProvider { List ISelect.ToList(Expression> select) => this.InternalToList(select?.Body); - ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)); + ISelect ISelect.Where(Expression> exp) => this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)); - ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body)) : this; + ISelect ISelect.WhereIf(bool condition, Expression> exp) => condition ? this.Where(_commonExpression.ExpressionWhereLambda(_tables, exp?.Body, null)) : this; } } diff --git a/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs b/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs index ff60992d..6c4d074d 100644 --- a/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs +++ b/FreeSql/Internal/CommonProvider/SelectProvider/SelectGroupingProvider.cs @@ -1,42 +1,72 @@ -//using FreeSql.Internal.Model; -//using System; -//using System.Collections.Generic; -//using System.Linq.Expressions; -//using System.Text; +using FreeSql.Internal.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; -//namespace FreeSql.Internal.CommonProvider { -// public class SelectGroupingProvider : ISelectGrouping where T2 : class { +namespace FreeSql.Internal.CommonProvider { + class SelectGroupingProvider : ISelectGrouping { -// internal Select1Provider _select; -// internal ReadAnonymousTypeInfo _map; -// internal CommonExpression _comonExp; -// internal SelectTableInfo _table; -// SelectGroupingProvider(CommonExpression comonExp, Expression exp) { -// _comonExp = comonExp; -// //var columns = _comonExp.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(_select._tables, columns, true); -// _table = new SelectTableInfo { Alias = "", On = "", Table = _comonExp._common.GetTableByEntity(typeof(T1)), Type = SelectTableInfoType.From }; -// } + internal object _select; + internal ReadAnonymousTypeInfo _map; + internal CommonExpression _comonExp; + public SelectGroupingProvider(object select, ReadAnonymousTypeInfo map, CommonExpression comonExp) { + _select = select; + _map = map; + _comonExp = comonExp; + } -// public ISelectGrouping Having(Expression, bool>> exp) { -// _select.Having(_comonExp.ExpressionWhereLambda(new List(new[] { _table }), exp)); -// return this; -// } + string getSelectGroupingMapString(Expression[] members) { + 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; + } + return read.DbField; + } -// public ISelectGrouping OrderBy(Expression, TMember>> column) { -// var columnMap = new List(); -// _comonExp.ExpressionSelectColumn_MemberAccess(new List(new[] { _table }), columnMap, SelectTableInfoType.From, column, true); + public ISelectGrouping Having(Expression, bool>> exp) { + var sql = _comonExp.ExpressionWhereLambda(null, exp, getSelectGroupingMapString); + var method = _select.GetType().GetMethod("Having", new[] { typeof(string), typeof(object) }); + method.Invoke(_select, new object[] { sql, null }); + return this; + } -// _select.OrderBy(); -// return this; -// } + public ISelectGrouping OrderBy(Expression, TMember>> column) { + var sql = _comonExp.ExpressionWhereLambda(null, column, getSelectGroupingMapString); + var method = _select.GetType().GetMethod("OrderBy", new[] { typeof(string), typeof(object) }); + method.Invoke(_select, new object[] { sql, null }); + return this; + } -// public ISelectGrouping OrderByDescending(Expression, TMember>> column) { -// _select.OrderBy(" DESC"); -// return this; -// } + public ISelectGrouping OrderByDescending(Expression, TMember>> column) { + var sql = _comonExp.ExpressionWhereLambda(null, column, getSelectGroupingMapString); + var method = _select.GetType().GetMethod("OrderBy", new[] { typeof(string), typeof(object) }); + method.Invoke(_select, new object[] { $"{sql} DESC", null }); + return this; + } -// public List ToList(Expression, TReturn>> select) { -// throw new NotImplementedException(); -// } -// } -//} + public List ToList(Expression, TReturn>> select) { + var map = new ReadAnonymousTypeInfo(); + var field = new StringBuilder(); + var index = 0; + + _comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString); + var method = _select.GetType().GetMethod("ToListMapReader", BindingFlags.Instance | BindingFlags.NonPublic); + method = method.MakeGenericMethod(typeof(TReturn)); + return method.Invoke(_select, new object[] { (map, map.Childs.Count > 0 ? field.Remove(0, 2).ToString() : null) }) as List; + } + + public string ToSql(Expression, TReturn>> select) { + var map = new ReadAnonymousTypeInfo(); + var field = new StringBuilder(); + var index = 0; + + _comonExp.ReadAnonymousField(null, field, map, ref index, select, getSelectGroupingMapString); + var method = _select.GetType().GetMethod("ToSql", new[] { typeof(string) }); + return method.Invoke(_select, new object[] { map.Childs.Count > 0 ? field.Remove(0, 2).ToString() : null }) as string; + } + } +} diff --git a/FreeSql/Internal/CommonProvider/UpdateProvider.cs b/FreeSql/Internal/CommonProvider/UpdateProvider.cs index c49290a2..05d1a9e6 100644 --- a/FreeSql/Internal/CommonProvider/UpdateProvider.cs +++ b/FreeSql/Internal/CommonProvider/UpdateProvider.cs @@ -38,7 +38,7 @@ namespace FreeSql.Internal.CommonProvider { public abstract List ExecuteUpdated(); public IUpdate IgnoreColumns(Expression> columns) { - var cols = _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false).Distinct(); + var cols = _commonExpression.ExpressionSelectColumns_MemberAccess_New_NewArrayInit(null, columns?.Body, false, null).Distinct(); _ignore.Clear(); foreach (var col in cols) _ignore.Add(col, true); return this; @@ -53,7 +53,7 @@ namespace FreeSql.Internal.CommonProvider { public IUpdate Set(Expression> column, TMember value) { var cols = new List(); - _commonExpression.ExpressionSelectColumn_MemberAccess(null, cols, SelectTableInfoType.From, column?.Body, true); + _commonExpression.ExpressionSelectColumn_MemberAccess(null, cols, SelectTableInfoType.From, column?.Body, true, null); if (cols.Count != 1) return this; var col = cols.First(); _set.Append(", ").Append(_commonUtils.QuoteSqlName(col.Column.Attribute.Name)).Append(" = ").Append(_commonUtils.QuoteWriteParamter(col.Column.CsType, $"{_commonUtils.QuoteParamterName("p_")}{_params.Count}")); @@ -64,7 +64,7 @@ namespace FreeSql.Internal.CommonProvider { public IUpdate Set(Expression> binaryExpression) { if (binaryExpression?.Body is BinaryExpression == false) return this; var cols = new List(); - var expt = _commonExpression.ExpressionWhereLambdaNoneForeignObject(null, cols, binaryExpression); + var expt = _commonExpression.ExpressionWhereLambdaNoneForeignObject(null, cols, binaryExpression, null); if (cols.Any() == false) return this; foreach (var col in cols) { if (col.Column.Attribute.IsNullable) { @@ -84,7 +84,7 @@ namespace FreeSql.Internal.CommonProvider { return this; } - public IUpdate Where(Expression> expression) => this.Where(_commonExpression.ExpressionWhereLambdaNoneForeignObject(null, null, expression?.Body)); + public IUpdate Where(Expression> expression) => this.Where(_commonExpression.ExpressionWhereLambdaNoneForeignObject(null, null, expression?.Body, null)); public IUpdate Where(string sql, object parms = null) { if (string.IsNullOrEmpty(sql)) return this; _where.Append(" AND (").Append(sql).Append(")"); diff --git a/FreeSql/Internal/Utils.cs b/FreeSql/Internal/Utils.cs index 77c72468..0ac5acb0 100644 --- a/FreeSql/Internal/Utils.cs +++ b/FreeSql/Internal/Utils.cs @@ -20,6 +20,7 @@ namespace FreeSql.Internal { static ConcurrentDictionary _cacheGetTableByEntity = new ConcurrentDictionary(); internal static TableInfo GetTableByEntity(Type entity, CommonUtils common) { + if (entity.FullName.StartsWith("<>f__AnonymousType")) return null; if (_cacheGetTableByEntity.TryGetValue($"{common.QuoteSqlName("db")}{entity.FullName}", out var trytb)) return trytb; //区分数据库类型缓存 if (common.CodeFirst.GetDbInfo(entity) != null) return null; diff --git a/FreeSql/MySql/Curd/MySqlSelect.cs b/FreeSql/MySql/Curd/MySqlSelect.cs index 5e766461..619131b7 100644 --- a/FreeSql/MySql/Curd/MySqlSelect.cs +++ b/FreeSql/MySql/Curd/MySqlSelect.cs @@ -78,10 +78,10 @@ namespace FreeSql.MySql.Curd { public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new MySqlSelect(_orm, _commonUtils, _commonExpression, null); MySqlSelect.CopyData(this, ret); return ret; } public override string ToSql(string field = null) => ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); } - class MySqlSelect : FreeSql.Internal.CommonProvider.Select2Provider where T1 : class where T2 : class { - public MySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } - public override string ToSql(string field = null) => MySqlSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); - } + //class MySqlSelect : FreeSql.Internal.CommonProvider.Select2Provider where T1 : class where T2 : class { + // public MySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + // public override string ToSql(string field = null) => MySqlSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); + //} class MySqlSelect : FreeSql.Internal.CommonProvider.Select3Provider where T1 : class where T2 : class where T3 : class { public MySqlSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } public override string ToSql(string field = null) => MySqlSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); diff --git a/FreeSql/MySql/MySqlExpression.cs b/FreeSql/MySql/MySqlExpression.cs index 02323f2e..66e40f5e 100644 --- a/FreeSql/MySql/MySqlExpression.cs +++ b/FreeSql/MySql/MySqlExpression.cs @@ -10,20 +10,20 @@ namespace FreeSql.MySql { public MySqlExpression(CommonUtils common) : base(common) { } - internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Expression == null) { switch (exp.Member.Name) { case "Empty": return "''"; } return null; } - var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Member.Name) { case "Length": return $"char_length({left})"; } return null; } - internal override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Expression == null) { switch (exp.Member.Name) { case "Now": return "now()"; @@ -34,7 +34,7 @@ namespace FreeSql.MySql { } return null; } - var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Member.Name) { case "Date": return $"cast(date_format({left},'%Y-%m-%d') as datetime)"; case "TimeOfDay": return $"timestampdiff(microsecond, date_format({left},'%Y-%m-%d'), {left})"; @@ -51,7 +51,7 @@ namespace FreeSql.MySql { } return null; } - internal override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Expression == null) { switch (exp.Member.Name) { case "Zero": return "0"; @@ -60,7 +60,7 @@ namespace FreeSql.MySql { } return null; } - var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Member.Name) { case "Days": return $"(({left}) div {(long)1000000 * 60 * 60 * 24})"; case "Hours": return $"(({left}) div {(long)1000000 * 60 * 60} mod 24)"; @@ -77,13 +77,13 @@ namespace FreeSql.MySql { return null; } - internal override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); + internal override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Method.Name) { case "StartsWith": case "EndsWith": case "Contains": - var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (args0Value == "NULL") return $"({left}) IS NULL"; if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"concat({args0Value}, '%')")}"; if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"concat('%', {args0Value})")}"; @@ -92,26 +92,26 @@ namespace FreeSql.MySql { case "ToLower": return $"lower({left})"; case "ToUpper": return $"upper({left})"; case "Substring": - var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString(); else substrArgs1 += "+1"; if (exp.Arguments.Count == 1) return $"substr({left}, {substrArgs1})"; - return $"substr({left}, {substrArgs1}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + return $"substr({left}, {substrArgs1}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; case "IndexOf": - var indexOfFindStr = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var indexOfFindStr = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") { - var locateArgs1 = ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName); + var locateArgs1 = ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (long.TryParse(locateArgs1, out var testtrylng2)) locateArgs1 = (testtrylng2 + 1).ToString(); else locateArgs1 += "+1"; return $"(locate({left}, {indexOfFindStr}, {locateArgs1})-1)"; } return $"(locate({left}, {indexOfFindStr})-1)"; case "PadLeft": - if (exp.Arguments.Count == 1) return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + if (exp.Arguments.Count == 1) return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; case "PadRight": - if (exp.Arguments.Count == 1) return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + if (exp.Arguments.Count == 1) return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; case "Trim": case "TrimStart": case "TrimEnd": @@ -127,62 +127,62 @@ namespace FreeSql.MySql { argsTrim01s = arritem.Expressions.ToArray(); } foreach (var argsTrim01 in argsTrim01s) { - if (exp.Method.Name == "Trim") left = $"trim({ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, tbtype, isQuoteName)} from {left})"; - if (exp.Method.Name == "TrimStart") left = $"trim(leading {ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, tbtype, isQuoteName)} from {left})"; - if (exp.Method.Name == "TrimEnd") left = $"trim(trailing {ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, tbtype, isQuoteName)} from {left})"; + if (exp.Method.Name == "Trim") left = $"trim({ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} from {left})"; + if (exp.Method.Name == "TrimStart") left = $"trim(leading {ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} from {left})"; + if (exp.Method.Name == "TrimEnd") left = $"trim(trailing {ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} from {left})"; } } return left; - case "Replace": return $"replace({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "CompareTo": return $"strcmp({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + case "Replace": return $"replace({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "CompareTo": return $"strcmp({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; } throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); } - internal override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { switch (exp.Method.Name) { - case "Abs": return $"abs({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Sign": return $"sign({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Floor": return $"floor({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Ceiling": return $"ceiling({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + case "Abs": return $"abs({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Sign": return $"sign({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Floor": return $"floor({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Ceiling": return $"ceiling({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; case "Round": - if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - return $"round({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Exp": return $"exp({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Log": return $"log({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Log10": return $"log10({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Pow": return $"pow({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Sqrt": return $"sqrt({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Cos": return $"cos({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Sin": return $"sin({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Tan": return $"tan({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Acos": return $"acos({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Asin": return $"asin({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Atan": return $"atan({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Atan2": return $"atan2({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Truncate": return $"truncate({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, 0)"; + if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"round({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Exp": return $"exp({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Log": return $"log({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Log10": return $"log10({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Pow": return $"pow({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Sqrt": return $"sqrt({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Cos": return $"cos({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Sin": return $"sin({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Tan": return $"tan({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Acos": return $"acos({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Asin": return $"asin({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Atan": return $"atan({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Atan2": return $"atan2({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Truncate": return $"truncate({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, 0)"; } throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); } - internal override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Object == null) { switch (exp.Method.Name) { - case "Compare": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} - ({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)}))"; - case "DaysInMonth": return $"dayofmonth(last_day(concat({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, '-', {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)}, '-01')))"; - case "Equals": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} = {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + case "Compare": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} - ({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}))"; + case "DaysInMonth": return $"dayofmonth(last_day(concat({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, '-', {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, '-01')))"; + case "Equals": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} = {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; case "IsLeapYear": - var isLeapYearArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var isLeapYearArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); return $"(({isLeapYearArgs1})%4=0 AND ({isLeapYearArgs1})%100<>0 OR ({isLeapYearArgs1})%400=0)"; - case "Parse": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as datetime)"; + case "Parse": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as datetime)"; case "ParseExact": case "TryParse": - case "TryParseExact": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as datetime)"; + case "TryParseExact": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as datetime)"; } } else { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); - var args1 = exp.Arguments.Count == 0 ? null : ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + var args1 = exp.Arguments.Count == 0 ? null : ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Method.Name) { case "Add": return $"date_add({left}, interval ({args1}) microsecond)"; case "AddDays": return $"date_add({left}, interval ({args1}) day)"; @@ -199,60 +199,60 @@ namespace FreeSql.MySql { if (exp.Arguments[0].Type.FullName == "System.TimeSpan" || exp.Arguments[0].Type.GenericTypeArguments.FirstOrDefault()?.FullName == "System.TimeSpan") return $"date_sub({left}, interval ({args1}) microsecond)"; break; - case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "CompareTo": return $"(({left}) - ({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}))"; + case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "CompareTo": return $"(({left}) - ({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}))"; case "ToString": return $"date_format({left}, '%Y-%m-%d %H:%i:%s.%f')"; } } throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); } - internal override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Object == null) { switch (exp.Method.Name) { - case "Compare": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}-({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)}))"; - case "Equals": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} = {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "FromDays": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})*{(long)1000000 * 60 * 60 * 24})"; - case "FromHours": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})*{(long)1000000 * 60 * 60})"; - case "FromMilliseconds": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})*1000)"; - case "FromMinutes": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})*{(long)1000000 * 60})"; - case "FromSeconds": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})*1000000)"; - case "FromTicks": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})/10)"; - case "Parse": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as signed)"; + case "Compare": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}-({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}))"; + case "Equals": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} = {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "FromDays": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})*{(long)1000000 * 60 * 60 * 24})"; + case "FromHours": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})*{(long)1000000 * 60 * 60})"; + case "FromMilliseconds": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})*1000)"; + case "FromMinutes": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})*{(long)1000000 * 60})"; + case "FromSeconds": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})*1000000)"; + case "FromTicks": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})/10)"; + case "Parse": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as signed)"; case "ParseExact": case "TryParse": - case "TryParseExact": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as signed)"; + case "TryParseExact": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as signed)"; } } else { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); - var args1 = exp.Arguments.Count == 0 ? null : ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + var args1 = exp.Arguments.Count == 0 ? null : ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Method.Name) { case "Add": return $"({left}+{args1})"; case "Subtract": return $"({left}-({args1}))"; - case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "CompareTo": return $"({left}-({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}))"; + case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "CompareTo": return $"({left}-({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}))"; case "ToString": return $"cast({left} as char)"; } } throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); } - internal override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Object == null) { switch (exp.Method.Name) { - case "ToBoolean": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} not in ('0','false'))"; - case "ToByte": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as unsigned)"; - case "ToChar": return $"substr(cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as char), 1, 1)"; - case "ToDateTime": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as datetime)"; - case "ToDecimal": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as decimal(36,18))"; - case "ToDouble": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as decimal(32,16))"; + case "ToBoolean": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} not in ('0','false'))"; + case "ToByte": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as unsigned)"; + case "ToChar": return $"substr(cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as char), 1, 1)"; + case "ToDateTime": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as datetime)"; + case "ToDecimal": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as decimal(36,18))"; + case "ToDouble": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as decimal(32,16))"; case "ToInt16": case "ToInt32": case "ToInt64": - case "ToSByte": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as signed)"; - case "ToSingle": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as decimal(14,7))"; - case "ToString": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as char)"; + case "ToSByte": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as signed)"; + case "ToSingle": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as decimal(14,7))"; + case "ToString": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as char)"; case "ToUInt16": case "ToUInt32": - case "ToUInt64": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as unsigned)"; + case "ToUInt64": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as unsigned)"; } } throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); diff --git a/FreeSql/PostgreSQL/Curd/PostgreSQLSelect.cs b/FreeSql/PostgreSQL/Curd/PostgreSQLSelect.cs index ed369b6b..51dcb00b 100644 --- a/FreeSql/PostgreSQL/Curd/PostgreSQLSelect.cs +++ b/FreeSql/PostgreSQL/Curd/PostgreSQLSelect.cs @@ -80,10 +80,10 @@ namespace FreeSql.PostgreSQL.Curd { public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new PostgreSQLSelect(_orm, _commonUtils, _commonExpression, null); PostgreSQLSelect.CopyData(this, ret); return ret; } public override string ToSql(string field = null) => ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); } - class PostgreSQLSelect : FreeSql.Internal.CommonProvider.Select2Provider where T1 : class where T2 : class { - public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } - public override string ToSql(string field = null) => PostgreSQLSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); - } + //class PostgreSQLSelect : FreeSql.Internal.CommonProvider.Select2Provider where T1 : class where T2 : class { + // public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + // public override string ToSql(string field = null) => PostgreSQLSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); + //} class PostgreSQLSelect : FreeSql.Internal.CommonProvider.Select3Provider where T1 : class where T2 : class where T3 : class { public PostgreSQLSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } public override string ToSql(string field = null) => PostgreSQLSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); diff --git a/FreeSql/PostgreSQL/PostgreSQLExpression.cs b/FreeSql/PostgreSQL/PostgreSQLExpression.cs index 81447818..e874898b 100644 --- a/FreeSql/PostgreSQL/PostgreSQLExpression.cs +++ b/FreeSql/PostgreSQL/PostgreSQLExpression.cs @@ -10,20 +10,20 @@ namespace FreeSql.PostgreSQL { public PostgreSQLExpression(CommonUtils common) : base(common) { } - internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Expression == null) { switch (exp.Member.Name) { case "Empty": return "''"; } return null; } - var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Member.Name) { case "Length": return $"char_length({left})"; } return null; } - internal override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Expression == null) { switch (exp.Member.Name) { case "Now": return "current_timestamp"; @@ -34,7 +34,7 @@ namespace FreeSql.PostgreSQL { } return null; } - var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Member.Name) { case "Date": return $"({left})::date"; case "TimeOfDay": return $"(extract(epoch from ({left})::time)*1000000)"; @@ -51,7 +51,7 @@ namespace FreeSql.PostgreSQL { } return null; } - internal override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Expression == null) { switch (exp.Member.Name) { case "Zero": return "0"; @@ -60,7 +60,7 @@ namespace FreeSql.PostgreSQL { } return null; } - var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Member.Name) { case "Days": return $"floor(({left})/{(long)1000000 * 60 * 60 * 24})"; case "Hours": return $"floor(({left})/{(long)1000000 * 60 * 60}%24)"; @@ -77,18 +77,18 @@ namespace FreeSql.PostgreSQL { return null; } - internal override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); + internal override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Method.Name) { case "StartsWith": case "EndsWith": case "Contains": - var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (args0Value == "NULL") return $"({left}) IS NULL"; var likeOpt = "LIKE"; if (exp.Arguments.Count > 1) { if (exp.Arguments[1].Type == typeof(bool) || - exp.Arguments[1].Type == typeof(StringComparison) && ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName).Contains("IgnoreCase")) likeOpt = "ILIKE"; + exp.Arguments[1].Type == typeof(StringComparison) && ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName).Contains("IgnoreCase")) likeOpt = "ILIKE"; } if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::varchar || '%')")}"; if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::varchar)")}"; @@ -97,18 +97,18 @@ namespace FreeSql.PostgreSQL { case "ToLower": return $"lower({left})"; case "ToUpper": return $"upper({left})"; case "Substring": - var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString(); else substrArgs1 += "+1"; if (exp.Arguments.Count == 1) return $"substr({left}, {substrArgs1})"; - return $"substr({left}, {substrArgs1}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "IndexOf": return $"(strpos({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})-1)"; + return $"substr({left}, {substrArgs1}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "IndexOf": return $"(strpos({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})-1)"; case "PadLeft": - if (exp.Arguments.Count == 1) return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + if (exp.Arguments.Count == 1) return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; case "PadRight": - if (exp.Arguments.Count == 1) return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + if (exp.Arguments.Count == 1) return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; case "Trim": case "TrimStart": case "TrimEnd": @@ -126,7 +126,7 @@ namespace FreeSql.PostgreSQL { argsTrim01s = arritem.Expressions.ToArray(); } foreach (var argsTrim01 in argsTrim01s) { - var trimChr = ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, tbtype, isQuoteName).Trim('\''); + var trimChr = ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName).Trim('\''); if (trimChr.Length == 1) trimArg1 += trimChr; else trimArg2 += $" || ({trimChr})"; } @@ -135,56 +135,56 @@ namespace FreeSql.PostgreSQL { if (exp.Method.Name == "TrimStart") left = $"ltrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})"; if (exp.Method.Name == "TrimEnd") left = $"rtrim({left}, {_common.FormatSql("{0}", trimArg1)}{trimArg2})"; return left; - case "Replace": return $"replace({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "CompareTo": return $"case when {left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} then 0 when {left} > {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} then 1 else -1 end"; - case "Equals": return $"({left} = ({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::varchar)"; + case "Replace": return $"replace({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "CompareTo": return $"case when {left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} then 0 when {left} > {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} then 1 else -1 end"; + case "Equals": return $"({left} = ({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::varchar)"; } throw new Exception($"PostgreSQLExpression 未现实函数表达式 {exp} 解析"); } - internal override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { switch (exp.Method.Name) { - case "Abs": return $"abs({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Sign": return $"sign({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Floor": return $"floor({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Ceiling": return $"ceiling({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + case "Abs": return $"abs({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Sign": return $"sign({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Floor": return $"floor({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Ceiling": return $"ceiling({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; case "Round": - if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - return $"round({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Exp": return $"exp({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Log": return $"log({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Log10": return $"log10({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Pow": return $"pow({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Sqrt": return $"sqrt({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Cos": return $"cos({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Sin": return $"sin({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Tan": return $"tan({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Acos": return $"acos({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Asin": return $"asin({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Atan": return $"atan({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Atan2": return $"atan2({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Truncate": return $"trunc({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, 0)"; + if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"round({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Exp": return $"exp({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Log": return $"log({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Log10": return $"log10({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Pow": return $"pow({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Sqrt": return $"sqrt({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Cos": return $"cos({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Sin": return $"sin({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Tan": return $"tan({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Acos": return $"acos({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Asin": return $"asin({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Atan": return $"atan({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Atan2": return $"atan2({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Truncate": return $"trunc({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, 0)"; } throw new Exception($"PostgreSQLExpression 未现实函数表达式 {exp} 解析"); } - internal override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Object == null) { switch (exp.Method.Name) { - case "Compare": return $"extract(epoch from ({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::timestamp-({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})::timestamp)"; - case "DaysInMonth": return $"extract(day from ({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} || '-' || {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)} || '-01')::timestamp+'1 month'::interval-'1 day'::interval)"; - case "Equals": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::timestamp = ({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})::timestamp)"; + case "Compare": return $"extract(epoch from ({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::timestamp-({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::timestamp)"; + case "DaysInMonth": return $"extract(day from ({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} || '-' || {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} || '-01')::timestamp+'1 month'::interval-'1 day'::interval)"; + case "Equals": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::timestamp = ({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::timestamp)"; case "IsLeapYear": - var isLeapYearArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var isLeapYearArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); return $"(({isLeapYearArgs1})::int8%4=0 AND ({isLeapYearArgs1})::int8%100<>0 OR ({isLeapYearArgs1})::int8%400=0)"; - case "Parse": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::timestamp"; + case "Parse": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::timestamp"; case "ParseExact": case "TryParse": - case "TryParseExact": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::timestamp"; + case "TryParseExact": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::timestamp"; } } else { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); - var args1 = exp.Arguments.Count == 0 ? null : ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + var args1 = exp.Arguments.Count == 0 ? null : ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Method.Name) { case "Add": return $"(({left})::timestamp+(({args1})||' microseconds')::interval)"; case "AddDays": return $"(({left})::timestamp+(({args1})||' day')::interval)"; @@ -201,60 +201,60 @@ namespace FreeSql.PostgreSQL { if (exp.Arguments[0].Type.FullName == "System.TimeSpan" || exp.Arguments[0].Type.GenericTypeArguments.FirstOrDefault()?.FullName == "System.TimeSpan") return $"(({left})::timestamp-(({args1})||' microseconds')::interval)"; break; - case "Equals": return $"({left} = ({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::timestamp)"; - case "CompareTo": return $"extract(epoch from ({left})::timestamp-({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::timestamp)"; + case "Equals": return $"({left} = ({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::timestamp)"; + case "CompareTo": return $"extract(epoch from ({left})::timestamp-({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::timestamp)"; case "ToString": return $"to_char({left}, 'YYYY-MM-DD HH24:MI:SS.US')"; } } throw new Exception($"PostgreSQLExpression 未现实函数表达式 {exp} 解析"); } - internal override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Object == null) { switch (exp.Method.Name) { - case "Compare": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}-({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)}))"; - case "Equals": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} = {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "FromDays": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})*{(long)1000000 * 60 * 60 * 24})"; - case "FromHours": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})*{(long)1000000 * 60 * 60})"; - case "FromMilliseconds": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})*1000)"; - case "FromMinutes": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})*{(long)1000000 * 60})"; - case "FromSeconds": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})*1000000)"; - case "FromTicks": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})/10)"; - case "Parse": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::int8"; + case "Compare": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}-({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}))"; + case "Equals": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} = {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "FromDays": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})*{(long)1000000 * 60 * 60 * 24})"; + case "FromHours": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})*{(long)1000000 * 60 * 60})"; + case "FromMilliseconds": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})*1000)"; + case "FromMinutes": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})*{(long)1000000 * 60})"; + case "FromSeconds": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})*1000000)"; + case "FromTicks": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})/10)"; + case "Parse": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::int8"; case "ParseExact": case "TryParse": - case "TryParseExact": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::int8"; + case "TryParseExact": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::int8"; } } else { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); - var args1 = exp.Arguments.Count == 0 ? null : ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + var args1 = exp.Arguments.Count == 0 ? null : ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Method.Name) { case "Add": return $"({left}+{args1})"; case "Subtract": return $"({left}-({args1}))"; - case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "CompareTo": return $"({left}-({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}))"; + case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "CompareTo": return $"({left}-({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}))"; case "ToString": return $"({left})::varchar"; } } throw new Exception($"PostgreSQLExpression 未现实函数表达式 {exp} 解析"); } - internal override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Object == null) { switch (exp.Method.Name) { - case "ToBoolean": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::varchar not in ('0','false','f','no'))"; - case "ToByte": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::int2"; - case "ToChar": return $"substr(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::char, 1, 1)"; - case "ToDateTime": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::timestamp"; - case "ToDecimal": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::numeric"; - case "ToDouble": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::float8"; - case "ToInt16": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::int2"; - case "ToInt32": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::int4"; - case "ToInt64": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::int8"; - case "ToSByte": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::int2"; - case "ToSingle": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::float4"; - case "ToString": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::varchar"; - case "ToUInt16": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::int2"; - case "ToUInt32": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::int4"; - case "ToUInt64": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})::int8"; + case "ToBoolean": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::varchar not in ('0','false','f','no'))"; + case "ToByte": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::int2"; + case "ToChar": return $"substr(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::char, 1, 1)"; + case "ToDateTime": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::timestamp"; + case "ToDecimal": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::numeric"; + case "ToDouble": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::float8"; + case "ToInt16": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::int2"; + case "ToInt32": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::int4"; + case "ToInt64": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::int8"; + case "ToSByte": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::int2"; + case "ToSingle": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::float4"; + case "ToString": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::varchar"; + case "ToUInt16": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::int2"; + case "ToUInt32": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::int4"; + case "ToUInt64": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})::int8"; } } throw new Exception($"PostgreSQLExpression 未现实函数表达式 {exp} 解析"); diff --git a/FreeSql/SqlServer/Curd/SqlServerSelect.cs b/FreeSql/SqlServer/Curd/SqlServerSelect.cs index 9eba1b8d..21582a8d 100644 --- a/FreeSql/SqlServer/Curd/SqlServerSelect.cs +++ b/FreeSql/SqlServer/Curd/SqlServerSelect.cs @@ -90,10 +90,10 @@ namespace FreeSql.SqlServer.Curd { public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, T9, T10, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new SqlServerSelect(_orm, _commonUtils, _commonExpression, null); SqlServerSelect.CopyData(this, ret); return ret; } public override string ToSql(string field = null) => ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); } - class SqlServerSelect : FreeSql.Internal.CommonProvider.Select2Provider where T1 : class where T2 : class { - public SqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } - public override string ToSql(string field = null) => SqlServerSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); - } + //class SqlServerSelect : FreeSql.Internal.CommonProvider.Select2Provider where T1 : class where T2 : class { + // public SqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } + // public override string ToSql(string field = null) => SqlServerSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); + //} class SqlServerSelect : FreeSql.Internal.CommonProvider.Select3Provider where T1 : class where T2 : class where T3 : class { public SqlServerSelect(IFreeSql orm, CommonUtils commonUtils, CommonExpression commonExpression, object dywhere) : base(orm, commonUtils, commonExpression, dywhere) { } public override string ToSql(string field = null) => SqlServerSelect.ToSqlStatic(_commonUtils, _select, field ?? this.GetAllField().field, _join, _where, _groupby, _having, _orderby, _skip, _limit, _tables, _orm); diff --git a/FreeSql/SqlServer/SqlServerExpression.cs b/FreeSql/SqlServer/SqlServerExpression.cs index 41dfa9ca..48ad6683 100644 --- a/FreeSql/SqlServer/SqlServerExpression.cs +++ b/FreeSql/SqlServer/SqlServerExpression.cs @@ -10,20 +10,20 @@ namespace FreeSql.SqlServer { public SqlServerExpression(CommonUtils common) : base(common) { } - internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Expression == null) { switch (exp.Member.Name) { case "Empty": return "''"; } return null; } - var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Member.Name) { case "Length": return $"len({left})"; } return null; } - internal override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Expression == null) { switch (exp.Member.Name) { case "Now": return "getdate()"; @@ -34,7 +34,7 @@ namespace FreeSql.SqlServer { } return null; } - var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Member.Name) { case "Date": return $"convert(char(10),{left},120)"; case "TimeOfDay": return $"datediff(second, convert(char(10),{left},120), {left})"; @@ -51,7 +51,7 @@ namespace FreeSql.SqlServer { } return null; } - internal override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Expression == null) { switch (exp.Member.Name) { case "Zero": return "0"; @@ -60,7 +60,7 @@ namespace FreeSql.SqlServer { } return null; } - var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Member.Name) { case "Days": return $"floor(({left})/{60 * 60 * 24})"; case "Hours": return $"floor(({left})/{60 * 60}%24)"; @@ -77,13 +77,13 @@ namespace FreeSql.SqlServer { return null; } - internal override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); + internal override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Method.Name) { case "StartsWith": case "EndsWith": case "Contains": - var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (args0Value == "NULL") return $"({left}) IS NULL"; if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(cast({args0Value} as nvarchar)+'%')")}"; if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%'+cast({args0Value} as nvarchar))")}"; @@ -92,79 +92,79 @@ namespace FreeSql.SqlServer { case "ToLower": return $"lower({left})"; case "ToUpper": return $"upper({left})"; case "Substring": - var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString(); else substrArgs1 += "+1"; if (exp.Arguments.Count == 1) return $"left({left}, {substrArgs1})"; - return $"substring({left}, {substrArgs1}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + return $"substring({left}, {substrArgs1}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; case "IndexOf": - var indexOfFindStr = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var indexOfFindStr = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") { - var locateArgs1 = ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName); + var locateArgs1 = ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); if (long.TryParse(locateArgs1, out var testtrylng2)) locateArgs1 = (testtrylng2 + 1).ToString(); else locateArgs1 += "+1"; return $"(charindex({left}, {indexOfFindStr}, {locateArgs1})-1)"; } return $"(charindex({left}, {indexOfFindStr})-1)"; case "PadLeft": - if (exp.Arguments.Count == 1) return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + if (exp.Arguments.Count == 1) return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; case "PadRight": - if (exp.Arguments.Count == 1) return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + if (exp.Arguments.Count == 1) return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; case "Trim": return $"ltrim(rtrim({left}))"; case "TrimStart": return $"ltrim({left})"; case "TrimEnd": return $"rtrim({left})"; - case "Replace": return $"replace({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "CompareTo": return $"({left} - {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + case "Replace": return $"replace({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "CompareTo": return $"({left} - {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; } throw new Exception($"SqlServerExpression 未现实函数表达式 {exp} 解析"); } - internal override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { switch (exp.Method.Name) { - case "Abs": return $"abs({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Sign": return $"sign({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Floor": return $"floor({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Ceiling": return $"ceiling({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + case "Abs": return $"abs({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Sign": return $"sign({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Floor": return $"floor({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Ceiling": return $"ceiling({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; case "Round": - if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - return $"round({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, 0)"; - case "Exp": return $"exp({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Log": return $"log({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Log10": return $"log10({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Pow": return $"power({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Sqrt": return $"sqrt({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Cos": return $"cos({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Sin": return $"sin({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Tan": return $"tan({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Acos": return $"acos({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Asin": return $"asin({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Atan": return $"atan({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Atan2": return $"atan2({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Truncate": return $"floor({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"round({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + return $"round({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, 0)"; + case "Exp": return $"exp({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Log": return $"log({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Log10": return $"log10({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Pow": return $"power({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Sqrt": return $"sqrt({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Cos": return $"cos({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Sin": return $"sin({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Tan": return $"tan({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Acos": return $"acos({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Asin": return $"asin({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Atan": return $"atan({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Atan2": return $"atan2({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "Truncate": return $"floor({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; } throw new Exception($"SqlServerExpression 未现实函数表达式 {exp} 解析"); } - internal override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Object == null) { switch (exp.Method.Name) { - case "Compare": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} - ({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)}))"; - case "DaysInMonth": return $"datepart(day, dateadd(day, -1, dateadd(month, 1, cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as varchar) + '-' + cast({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)} as varchar) + '-1')))"; - case "Equals": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} = {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + case "Compare": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} - ({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}))"; + case "DaysInMonth": return $"datepart(day, dateadd(day, -1, dateadd(month, 1, cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as varchar) + '-' + cast({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as varchar) + '-1')))"; + case "Equals": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} = {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; case "IsLeapYear": - var isLeapYearArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var isLeapYearArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); return $"(({isLeapYearArgs1})%4=0 AND ({isLeapYearArgs1})%100<>0 OR ({isLeapYearArgs1})%400=0)"; - case "Parse": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as datetime)"; + case "Parse": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as datetime)"; case "ParseExact": case "TryParse": - case "TryParseExact": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as datetime)"; + case "TryParseExact": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as datetime)"; } } else { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); - var args1 = exp.Arguments.Count == 0 ? null : ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + var args1 = exp.Arguments.Count == 0 ? null : ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Method.Name) { case "Add": return $"dateadd(second, {args1}, {left})"; case "AddDays": return $"dateadd(day, {args1}, {left})"; @@ -181,60 +181,60 @@ namespace FreeSql.SqlServer { if (exp.Arguments[0].Type.FullName == "System.TimeSpan" || exp.Arguments[0].Type.GenericTypeArguments.FirstOrDefault()?.FullName == "System.TimeSpan") return $"dateadd(second, {args1}*-1, {left})"; break; - case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "CompareTo": return $"(({left}) - ({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}))"; + case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "CompareTo": return $"(({left}) - ({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}))"; case "ToString": return $"convert(varchar, {left}, 121)"; } } throw new Exception($"SqlServerExpression 未现实函数表达式 {exp} 解析"); } - internal override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Object == null) { switch (exp.Method.Name) { - case "Compare": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}-({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)}))"; - case "Equals": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} = {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "FromDays": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})*{60 * 60 * 24})"; - case "FromHours": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})*{60 * 60})"; - case "FromMilliseconds": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})/1000)"; - case "FromMinutes": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})*60)"; - case "FromSeconds": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "FromTicks": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})/10000000)"; - case "Parse": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as bigint)"; + case "Compare": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}-({ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}))"; + case "Equals": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} = {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "FromDays": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})*{60 * 60 * 24})"; + case "FromHours": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})*{60 * 60})"; + case "FromMilliseconds": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})/1000)"; + case "FromMinutes": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})*60)"; + case "FromSeconds": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "FromTicks": return $"(({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})/10000000)"; + case "Parse": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as bigint)"; case "ParseExact": case "TryParse": - case "TryParseExact": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as bigint)"; + case "TryParseExact": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as bigint)"; } } else { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); - var args1 = exp.Arguments.Count == 0 ? null : ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); + var args1 = exp.Arguments.Count == 0 ? null : ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName); switch (exp.Method.Name) { case "Add": return $"({left}+{args1})"; case "Subtract": return $"({left}-({args1}))"; - case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "CompareTo": return $"({left}-({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}))"; + case "Equals": return $"({left} = {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)})"; + case "CompareTo": return $"({left}-({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)}))"; case "ToString": return $"cast({left} as varchar)"; } } throw new Exception($"SqlServerExpression 未现实函数表达式 {exp} 解析"); } - internal override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + internal override string ExpressionLambdaToSqlCallConvert(MethodCallExpression exp, List _tables, List _selectColumnMap, Func getSelectGroupingMapString, SelectTableInfoType tbtype, bool isQuoteName) { if (exp.Object == null) { switch (exp.Method.Name) { - case "ToBoolean": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} not in ('0','false'))"; - case "ToByte": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as tinyint)"; - case "ToChar": return $"substring(cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as nvarchar), 1, 1)"; - case "ToDateTime": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as datetime)"; - case "ToDecimal": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as decimal(36,18))"; - case "ToDouble": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as decimal(32,16))"; - case "ToInt16": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as smallint)"; - case "ToInt32": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as int)"; - case "ToInt64": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as bigint)"; - case "ToSByte": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as tinyint)"; - case "ToSingle": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as decimal(14,7))"; - case "ToString": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as nvarchar)"; - case "ToUInt16": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as smallint)"; - case "ToUInt32": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as int)"; - case "ToUInt64": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} as bigint)"; + case "ToBoolean": return $"({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} not in ('0','false'))"; + case "ToByte": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as tinyint)"; + case "ToChar": return $"substring(cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as nvarchar), 1, 1)"; + case "ToDateTime": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as datetime)"; + case "ToDecimal": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as decimal(36,18))"; + case "ToDouble": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as decimal(32,16))"; + case "ToInt16": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as smallint)"; + case "ToInt32": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as int)"; + case "ToInt64": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as bigint)"; + case "ToSByte": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as tinyint)"; + case "ToSingle": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as decimal(14,7))"; + case "ToString": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as nvarchar)"; + case "ToUInt16": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as smallint)"; + case "ToUInt32": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as int)"; + case "ToUInt64": return $"cast({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, getSelectGroupingMapString, tbtype, isQuoteName)} as bigint)"; } } throw new Exception($"SqlServerExpression 未现实函数表达式 {exp} 解析"); diff --git a/readme.md b/readme.md index fda1e72b..5c09c528 100644 --- a/readme.md +++ b/readme.md @@ -51,7 +51,6 @@ class TopicTypeClass { ``` # Part1: 查询 - ```csharp List t1 = fsql.Select().Where(a => a.Id > 0).ToList(); @@ -103,6 +102,34 @@ sql = fsql.Select() .LeftJoin("TopicType b on b.Id = a.TypeId and b.Name = ?bname", new { bname = "xxx" }) .ToSql(); ``` +### 分组聚合 +```csharp +var groupby = fsql.Select() + .GroupBy(a => new { tt2 = a.Title.Substring(0, 2), mod4 = a.Id % 4 }) + .Having(a => a.Count() > 0 && a.Avg(a.Key.mod4) > 0 && a.Max(a.Key.mod4) > 0) + .Having(a => a.Count() < 300 || a.Avg(a.Key.mod4) < 100) + .OrderBy(a => a.Key.tt2) + .OrderByDescending(a => a.Count()) + .ToList(a => new { a.Key.tt2, cou1 = a.Count(), arg1 = a.Avg(a.Key.mod4) }); +//SELECT substr(a.`Title`, 1, 2) as1, count(1) as2, avg((a.`Id` % 4)) as3 +//FROM `xxx` a +//GROUP BY substr(a.`Title`, 1, 2), (a.`Id` % 4) +//HAVING (count(1) > 0 AND avg((a.`Id` % 4)) > 0 AND max((a.`Id` % 4)) > 0) AND (count(1) < 300 OR avg((a.`Id` % 4)) < 100) +//ORDER BY substr(a.`Title`, 1, 2), count(1) DESC +``` +### 执行SQL返回数据 +```csharp +class xxx { + public int Id { get; set; } + public string Path { get; set; } + public string Title2 { get; set; } +} + +List t6 = fsql.Ado.Query("select * from song"); +List<(int, string ,string)> t7 = fsql.Ado.Query<(int, string, string)>("select * from song"); +List t8 = fsql.Ado.Query("select * from song"); +``` +> 更多资料:[《Select查询数据》](Docs/select.md) # Part2: 添加 ```csharp @@ -135,6 +162,7 @@ var t6 = fsql.Insert().AppendData(items) | ExecuteAffrows | long | 执行SQL语句,返回影响的行数 | | ExecuteIdentity | long | 执行SQL语句,返回自增值 | | ExecuteInserted | List\ | 执行SQL语句,返回插入后的记录 | +> 更多资料:[《Insert添加数据》](Docs/select.md) # Part3: 修改 ```csharp @@ -211,6 +239,7 @@ var t10 = fsql.Update().SetRaw("Title = {0}", "新标题").Where("Id = {0 | - | - | - | - | | ExecuteAffrows | long | | 执行SQL语句,返回影响的行数 | | ExecuteUpdated | List\ | | 执行SQL语句,返回更新后的记录 | +> 更多资料:[《Update更新数据》](Docs/select.md) # Part4: 删除 详情查看:[《Delete 删除数据》](Docs/delete.md)