From 572aa1d8ee559116ae397c623ad7e862a21ccfb5 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Thu, 20 Dec 2018 20:00:33 +0800 Subject: [PATCH] =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F=E5=87=BD=E6=95=B0?= =?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0DateTime/TimeSpan=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E4=B8=94=E5=BC=80=E5=A7=8B=E6=B5=8B=E8=AF=95=E4=B8=8E=E6=95=B4?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MySql/Expression/DateTimeTest.cs | 115 +++ FreeSql.Tests/MySql/Expression/MathTest.cs | 95 +++ FreeSql.Tests/MySql/Expression/StringTest.cs | 663 ++++++++++++++++++ .../TimeSpanTest.cs} | 37 +- FreeSql/Internal/CommonExpression.cs | 32 +- FreeSql/Internal/CommonUtils.cs | 1 + FreeSql/MySql/Curd/MySqlSelect.cs | 25 +- FreeSql/MySql/MySqlAdo/MySqlAdo.cs | 22 +- FreeSql/MySql/MySqlCodeFirst.cs | 15 +- FreeSql/MySql/MySqlExpression.cs | 297 ++++---- FreeSql/MySql/MySqlUtils.cs | 1 + FreeSql/PostgreSQL/Curd/PostgreSQLSelect.cs | 25 +- .../PostgreSQL/PostgreSQLAdo/PostgreSQLAdo.cs | 17 +- FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs | 58 +- FreeSql/PostgreSQL/PostgreSQLExpression.cs | 302 ++++---- FreeSql/PostgreSQL/PostgreSQLUtils.cs | 39 +- FreeSql/SqlServer/Curd/SqlServerSelect.cs | 25 +- .../SqlServer/SqlServerAdo/SqlServerAdo.cs | 17 +- FreeSql/SqlServer/SqlServerCodeFirst.cs | 15 +- FreeSql/SqlServer/SqlServerExpression.cs | 200 ++++-- FreeSql/SqlServer/SqlServerUtils.cs | 1 + 21 files changed, 1542 insertions(+), 460 deletions(-) create mode 100644 FreeSql.Tests/MySql/Expression/DateTimeTest.cs create mode 100644 FreeSql.Tests/MySql/Expression/MathTest.cs create mode 100644 FreeSql.Tests/MySql/Expression/StringTest.cs rename FreeSql.Tests/MySql/{MySqlExpressionTest.cs => Expression/TimeSpanTest.cs} (66%) diff --git a/FreeSql.Tests/MySql/Expression/DateTimeTest.cs b/FreeSql.Tests/MySql/Expression/DateTimeTest.cs new file mode 100644 index 00000000..c43aab04 --- /dev/null +++ b/FreeSql.Tests/MySql/Expression/DateTimeTest.cs @@ -0,0 +1,115 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.MySql.Expression { + public class DateTimeTest { + + ISelect select => g.mysql.Select(); + + [Table(Name = "tb_topic111333")] + class Topic { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int Clicks { get; set; } + public int TestTypeInfoGuid { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + [Table(Name = "TestTypeInfo333")] + class TestTypeInfo { + public int Guid { get; set; } + public int ParentId { get; set; } + public TestTypeParentInfo Parent { get; set; } + public string Name { get; set; } + public DateTime Time { get; set; } + } + [Table(Name = "TestTypeParentInfo23123")] + class TestTypeParentInfo { + public int Id { get; set; } + public string Name { get; set; } + + public List Types { get; set; } + public DateTime Time2 { get; set; } + } + + [Fact] + public void DayOfWeek() { + var data = new List(); + data.Add(select.Where(a => a.CreateTime.DayOfWeek > DateTime.Now.DayOfWeek).ToSql()); + data.Add(select.Where(a => a.Type.Time.DayOfWeek > DateTime.Now.DayOfWeek).ToSql()); + data.Add(select.Where(a => a.Type.Parent.Time2.DayOfWeek > DateTime.Now.DayOfWeek).ToSql()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic111333` a + //WHERE ((dayofweek(a.`CreateTime`) - 1) > (dayofweek(now()) - 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type + //WHERE ((dayofweek(a__Type.`Time`) - 1) > (dayofweek(now()) - 1)); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a__Type.`Guid` as4, a__Type.`ParentId` as5, a__Type.`Name` as6, a__Type.`Time` as7, a.`Title` as8, a.`CreateTime` as9 + //FROM `tb_topic111333` a, `TestTypeInfo333` a__Type, `TestTypeParentInfo23123` a__Type__Parent + //WHERE ((dayofweek(a__Type__Parent.`Time2`) - 1) > (dayofweek(now()) - 1)) + } + [Fact] + public void Day() { + } + [Fact] + public void DayOfYear() { + } + [Fact] + public void Month() { + } + [Fact] + public void Year() { + } + [Fact] + public void Hour() { + } + [Fact] + public void Minute() { + } + [Fact] + public void Second() { + } + [Fact] + public void Millisecond() { + } + [Fact] + public void Ticks() { + } + [Fact] + public void Add() { + } + [Fact] + public void AddDays() { + } + [Fact] + public void AddHours() { + } + [Fact] + public void AddMilliseconds() { + } + [Fact] + public void AddMinutes() { + } + [Fact] + public void AddMonths() { + } + [Fact] + public void AddSeconds() { + } + [Fact] + public void AddTicks() { + } + [Fact] + public void AddYears() { + } + [Fact] + public void Subtract() { + } + } +} diff --git a/FreeSql.Tests/MySql/Expression/MathTest.cs b/FreeSql.Tests/MySql/Expression/MathTest.cs new file mode 100644 index 00000000..efe0bfd0 --- /dev/null +++ b/FreeSql.Tests/MySql/Expression/MathTest.cs @@ -0,0 +1,95 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.MySql.Expression { + public class MathTest { + + ISelect select => g.mysql.Select(); + + [Table(Name = "tb_topic")] + class Topic { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int Clicks { get; set; } + public int TestTypeInfoGuid { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + class TestTypeInfo { + public int Guid { get; set; } + public int ParentId { get; set; } + public TestTypeParentInfo Parent { get; set; } + public string Name { get; set; } + } + class TestTypeParentInfo { + public int Id { get; set; } + public string Name { get; set; } + + public List Types { get; set; } + } + + [Fact] + public void PI() { + var data = new List(); + data.Add(select.Where(a => Math.PI + a.Clicks > 0).ToSql()); + } + [Fact] + public void Abs() { + } + [Fact] + public void Sign() { + } + [Fact] + public void Floor() { + } + [Fact] + public void Ceiling() { + } + [Fact] + public void Round() { + } + [Fact] + public void Exp() { + } + [Fact] + public void Log() { + } + [Fact] + public void Log10() { + } + [Fact] + public void Pow() { + } + [Fact] + public void Sqrt() { + } + [Fact] + public void Cos() { + } + [Fact] + public void Sin() { + } + [Fact] + public void Tan() { + } + [Fact] + public void Acos() { + } + [Fact] + public void Asin() { + } + [Fact] + public void Atan() { + } + [Fact] + public void Atan2() { + } + [Fact] + public void Truncate() { + } + } +} diff --git a/FreeSql.Tests/MySql/Expression/StringTest.cs b/FreeSql.Tests/MySql/Expression/StringTest.cs new file mode 100644 index 00000000..8c4e9ee7 --- /dev/null +++ b/FreeSql.Tests/MySql/Expression/StringTest.cs @@ -0,0 +1,663 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.MySql.Expression { + public class StringTest { + + ISelect select => g.mysql.Select(); + + [Table(Name = "tb_topic")] + class Topic { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int Clicks { get; set; } + public int TestTypeInfoGuid { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + class TestTypeInfo { + public int Guid { get; set; } + public int ParentId { get; set; } + public TestTypeParentInfo Parent { get; set; } + public string Name { get; set; } + } + class TestTypeParentInfo { + public int Id { get; set; } + public string Name { get; set; } + + public List Types { get; set; } + } + + [Fact] + public void StartsWith() { + var list = select.Where(a => a.Title.StartsWith("aaa")).ToList(); + list = select.Where(a => a.Title.StartsWith(a.Title)).ToList(); + list = select.Where(a => a.Title.StartsWith(a.Title + 1)).ToList(); + list = select.Where(a => a.Title.StartsWith(a.Type.Name)).ToList(); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE '%aaa') + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE concat('%', a.`Title`)) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE concat('%', concat(a.`Title`, 1))) + + //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.`Title`) LIKE concat('%', a__Type.`Name`)) + list = select.Where(a => (a.Title + "aaa").StartsWith("aaa")).ToList(); + list = select.Where(a => (a.Title + "aaa").StartsWith(a.Title)).ToList(); + list = select.Where(a => (a.Title + "aaa").StartsWith(a.Title + 1)).ToList(); + list = select.Where(a => (a.Title + "aaa").StartsWith(a.Type.Name)).ToList(); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE '%aaa') + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat('%', a.`Title`)) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat('%', concat(a.`Title`, 1))) + + //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((concat(a.`Title`, 'aaa')) LIKE concat('%', a__Type.`Name`)) + } + [Fact] + public void EndsWith() { + var list = select.Where(a => a.Title.EndsWith("aaa")).ToList(); + list = select.Where(a => a.Title.EndsWith(a.Title)).ToList(); + list = select.Where(a => a.Title.EndsWith(a.Title + 1)).ToList(); + list = select.Where(a => a.Title.EndsWith(a.Type.Name)).ToList(); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE 'aaa%') + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE concat(a.`Title`, '%')) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE concat(concat(a.`Title`, 1), '%')) + + //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.`Title`) LIKE concat(a__Type.`Name`, '%')) + list = select.Where(a => (a.Title + "aaa").EndsWith("aaa")).ToList(); + list = select.Where(a => (a.Title + "aaa").EndsWith(a.Title)).ToList(); + list = select.Where(a => (a.Title + "aaa").EndsWith(a.Title + 1)).ToList(); + list = select.Where(a => (a.Title + "aaa").EndsWith(a.Type.Name)).ToList(); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE 'aaa%') + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat(a.`Title`, '%')) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat(concat(a.`Title`, 1), '%')) + + //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((concat(a.`Title`, 'aaa')) LIKE concat(a__Type.`Name`, '%')) + } + [Fact] + public void Contains() { + var ToList = select.Where(a => a.Title.Contains("aaa")).ToList(); + ToList = select.Where(a => a.Title.Contains(a.Title)).ToList(); + ToList = select.Where(a => a.Title.Contains(a.Title + 1)).ToList(); + ToList = select.Where(a => a.Title.Contains(a.Type.Name)).ToList(); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE '%aaa%') + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE concat('%', a.`Title`, '%')) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((a.`Title`) LIKE concat('%', a.`Title` +1, '%')) + + //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.`Title`) LIKE concat('%', a__Type.`Name`, '%')) + ToList = select.Where(a => (a.Title + "aaa").Contains("aaa")).ToList(); + ToList = select.Where(a => (a.Title + "aaa").Contains(a.Title)).ToList(); + ToList = select.Where(a => (a.Title + "aaa").Contains(a.Title + 1)).ToList(); + ToList = select.Where(a => (a.Title + "aaa").Contains(a.Type.Name)).ToList(); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE '%aaa%') + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat('%', a.`Title`, '%')) + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE((concat(a.`Title`, 'aaa')) LIKE concat('%', concat(a.`Title`, 1), '%')) + + //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((concat(a.`Title`, 'aaa')) LIKE concat('%', a__Type.`Name`, '%')) + } + [Fact] + public void ToLower() { + var data = new List(); + data.Add(select.Where(a => a.Title.ToLower() == "aaa").ToList()); + data.Add(select.Where(a => a.Title.ToLower() == a.Title).ToList()); + data.Add(select.Where(a => a.Title.ToLower() == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.ToLower() == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE(lower(a.`Title`) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE(lower(a.`Title`) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE(lower(a.`Title`) = concat(a.`Title`, 1)); + + //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(lower(a.`Title`) = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.ToLower() + "aaa").ToLower() == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.ToLower() + "aaa").ToLower() == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.ToLower() + "aaa").ToLower() == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.ToLower() + "aaa").ToLower() == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE(lower(concat(lower(a.`Title`), 'aaa')) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE(lower(concat(lower(a.`Title`), 'aaa')) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE(lower(concat(lower(a.`Title`), 'aaa')) = concat(a.`Title`, 1)); + + //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(lower(concat(lower(a.`Title`), 'aaa')) = a__Type.`Name`) + } + [Fact] + public void ToUpper() { + var data = new List(); + data.Add(select.Where(a => a.Title.ToUpper() == "aaa").ToList()); + data.Add(select.Where(a => a.Title.ToUpper() == a.Title).ToList()); + data.Add(select.Where(a => a.Title.ToUpper() == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.ToUpper() == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (upper(a.`Title`) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (upper(a.`Title`) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (upper(a.`Title`) = concat(a.`Title`, 1)); + + //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 (upper(a.`Title`) = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.ToUpper() + "aaa").ToUpper() == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.ToUpper() + "aaa").ToUpper() == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.ToUpper() + "aaa").ToUpper() == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.ToUpper() + "aaa").ToUpper() == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (upper(concat(upper(a.`Title`), 'aaa')) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (upper(concat(upper(a.`Title`), 'aaa')) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (upper(concat(upper(a.`Title`), 'aaa')) = concat(a.`Title`, 1)); + + //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 (upper(concat(upper(a.`Title`), 'aaa')) = a__Type.`Name`) + } + [Fact] + public void Substring() { + var data = new List(); + data.Add(select.Where(a => a.Title.Substring(0) == "aaa").ToList()); + data.Add(select.Where(a => a.Title.Substring(0) == a.Title).ToList()); + data.Add(select.Where(a => a.Title.Substring(0) == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.Substring(0) == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (substr(a.`Title`, 1) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (substr(a.`Title`, 1) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (substr(a.`Title`, 1) = concat(a.`Title`, 1)); + + //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 (substr(a.`Title`, 1) = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.Substring(0) + "aaa").Substring(a.Title.Length) == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.Substring(0) + "aaa").Substring(0, a.Title.Length) == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.Substring(0) + "aaa").Substring(0, 3) == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.Substring(0) + "aaa").Substring(1, 2) == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (substr(concat(substr(a.`Title`, 1), 'aaa'), char_length(a.`Title`) + 1) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (substr(concat(substr(a.`Title`, 1), 'aaa'), 1, char_length(a.`Title`)) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (substr(concat(substr(a.`Title`, 1), 'aaa'), 1, 3) = concat(a.`Title`, 1)); + + //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 (substr(concat(substr(a.`Title`, 1), 'aaa'), 2, 2) = a__Type.`Name`) + } + [Fact] + public void Length() { + var data = new List(); + data.Add(select.Where(a => a.Title.Length == 0).ToList()); + data.Add(select.Where(a => a.Title.Length == 1).ToList()); + data.Add(select.Where(a => a.Title.Length == a.Title.Length + 1).ToList()); + data.Add(select.Where(a => a.Title.Length == a.Type.Name.Length).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (char_length(a.`Title`) = 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (char_length(a.`Title`) = 1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (char_length(a.`Title`) = char_length(a.`Title`) + 1); + + //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 (char_length(a.`Title`) = char_length(a__Type.`Name`)); + data.Add(select.Where(a => (a.Title + "aaa").Length == 0).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").Length == 1).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").Length == a.Title.Length + 1).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").Length == a.Type.Name.Length).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (char_length(concat(a.`Title`, 'aaa')) = 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (char_length(concat(a.`Title`, 'aaa')) = 1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (char_length(concat(a.`Title`, 'aaa')) = char_length(a.`Title`) + 1); + + //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 (char_length(concat(a.`Title`, 'aaa')) = char_length(a__Type.`Name`)) + } + [Fact] + public void IndexOf() { + var data = new List(); + data.Add(select.Where(a => a.Title.IndexOf("aaa") == -1).ToList()); + data.Add(select.Where(a => a.Title.IndexOf("aaa", 2) == -1).ToList()); + data.Add(select.Where(a => a.Title.IndexOf("aaa", 2) == (a.Title.Length + 1)).ToList()); + data.Add(select.Where(a => a.Title.IndexOf("aaa", 2) == a.Type.Name.Length + 1).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((locate(a.`Title`, 'aaa') - 1) = -1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((locate(a.`Title`, 'aaa', 3) - 1) = -1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((locate(a.`Title`, 'aaa', 3) - 1) = char_length(a.`Title`) + 1); + + //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 ((locate(a.`Title`, 'aaa', 3) - 1) = char_length(a__Type.`Name`) + 1); + data.Add(select.Where(a => (a.Title + "aaa").IndexOf("aaa") == -1).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").IndexOf("aaa", 2) == -1).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").IndexOf("aaa", 2) == (a.Title.Length + 1)).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").IndexOf("aaa", 2) == a.Type.Name.Length + 1).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((locate(concat(a.`Title`, 'aaa'), 'aaa') - 1) = -1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((locate(concat(a.`Title`, 'aaa'), 'aaa', 3) - 1) = -1); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE ((locate(concat(a.`Title`, 'aaa'), 'aaa', 3) - 1) = char_length(a.`Title`) + 1); + + //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 ((locate(concat(a.`Title`, 'aaa'), 'aaa', 3) - 1) = char_length(a__Type.`Name`) + 1) + } + [Fact] + public void PadLeft() { + var data = new List(); + data.Add(select.Where(a => a.Title.PadLeft(10, 'a') == "aaa").ToList()); + data.Add(select.Where(a => a.Title.PadLeft(10, 'a') == a.Title).ToList()); + data.Add(select.Where(a => a.Title.PadLeft(10, 'a') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.PadLeft(10, 'a') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (lpad(a.`Title`, 10, 'a') = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (lpad(a.`Title`, 10, 'a') = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (lpad(a.`Title`, 10, 'a') = concat(a.`Title`, 1)); + + //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 (lpad(a.`Title`, 10, 'a') = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.PadLeft(10, 'a') + "aaa").PadLeft(20, 'b') == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.PadLeft(10, 'a') + "aaa").PadLeft(20, 'b') == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.PadLeft(10, 'a') + "aaa").PadLeft(20, 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.PadLeft(10, 'a') + "aaa").PadLeft(20, 'b') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (lpad(concat(lpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (lpad(concat(lpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (lpad(concat(lpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = concat(a.`Title`, 1)); + + //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 (lpad(concat(lpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = a__Type.`Name`) + } + [Fact] + public void PadRight() { + var data = new List(); + data.Add(select.Where(a => a.Title.PadRight(10, 'a') == "aaa").ToList()); + data.Add(select.Where(a => a.Title.PadRight(10, 'a') == a.Title).ToList()); + data.Add(select.Where(a => a.Title.PadRight(10, 'a') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.PadRight(10, 'a') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rpad(a.`Title`, 10, 'a') = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rpad(a.`Title`, 10, 'a') = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rpad(a.`Title`, 10, 'a') = concat(a.`Title`, 1)); + + //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 (rpad(a.`Title`, 10, 'a') = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.PadRight(10, 'a') + "aaa").PadRight(20, 'b') == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.PadRight(10, 'a') + "aaa").PadRight(20, 'b') == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.PadRight(10, 'a') + "aaa").PadRight(20, 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.PadRight(10, 'a') + "aaa").PadRight(20, 'b') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rpad(concat(rpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rpad(concat(rpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rpad(concat(rpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = concat(a.`Title`, 1)); + + //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 (rpad(concat(rpad(a.`Title`, 10, 'a'), 'aaa'), 20, 'b') = a__Type.`Name`) + } + [Fact] + public void Trim() { + var data = new List(); + data.Add(select.Where(a => a.Title.Trim() == "aaa").ToList()); + data.Add(select.Where(a => a.Title.Trim('a') == a.Title).ToList()); + data.Add(select.Where(a => a.Title.Trim('a', 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.Trim('a', 'b', 'c') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(a.`Title`) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim('a' from a.`Title`) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim('b' from trim('a' from a.`Title`)) = concat(a.`Title`, 1)); + + //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 (trim('c' from trim('b' from trim('a' from a.`Title`))) = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.Trim() + "aaa").Trim() == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.Trim('a') + "aaa").Trim('a') == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.Trim('a', 'b') + "aaa").Trim('a', 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.Trim('a', 'b', 'c') + "aaa").Trim('a', 'b', 'c') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(concat(trim(a.`Title`), 'aaa')) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim('a' from concat(trim('a' from a.`Title`), 'aaa')) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim('b' from trim('a' from concat(trim('b' from trim('a' from a.`Title`)), 'aaa'))) = concat(a.`Title`, 1)); + + //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 (trim('c' from trim('b' from trim('a' from concat(trim('c' from trim('b' from trim('a' from a.`Title`))), 'aaa')))) = a__Type.`Name`) + } + [Fact] + public void TrimStart() { + var data = new List(); + data.Add(select.Where(a => a.Title.TrimStart() == "aaa").ToList()); + data.Add(select.Where(a => a.Title.TrimStart('a') == a.Title).ToList()); + data.Add(select.Where(a => a.Title.TrimStart('a', 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.TrimStart('a', 'b', 'c') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (ltrim(a.`Title`) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'a' from trim(leading 'a' from a.`Title`)) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'b' from trim(leading 'b' from trim(trailing 'a' from trim(leading 'a' from a.`Title`)))) = concat(a.`Title`, 1)); + + //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 (trim(trailing 'c' from trim(leading 'c' from trim(trailing 'b' from trim(leading 'b' from trim(trailing 'a' from trim(leading 'a' from a.`Title`)))))) = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.TrimStart() + "aaa").TrimStart() == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.TrimStart('a') + "aaa").TrimStart('a') == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.TrimStart('a', 'b') + "aaa").TrimStart('a', 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.TrimStart('a', 'b', 'c') + "aaa").TrimStart('a', 'b', 'c') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (ltrim(concat(ltrim(a.`Title`), 'aaa')) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'a' from trim(leading 'a' from concat(trim(trailing 'a' from trim(leading 'a' from a.`Title`)), 'aaa'))) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'b' from trim(leading 'b' from trim(trailing 'a' from trim(leading 'a' from concat(trim(trailing 'b' from trim(leading 'b' from trim(trailing 'a' from trim(leading 'a' from a.`Title`)))), 'aaa'))))) = concat(a.`Title`, 1)); + + //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 (trim(trailing 'c' from trim(leading 'c' from trim(trailing 'b' from trim(leading 'b' from trim(trailing 'a' from trim(leading 'a' from concat(trim(trailing 'c' from trim(leading 'c' from trim(trailing 'b' from trim(leading 'b' from trim(trailing 'a' from trim(leading 'a' from a.`Title`)))))), 'aaa'))))))) = a__Type.`Name`) + } + [Fact] + public void TrimEnd() { + var data = new List(); + data.Add(select.Where(a => a.Title.TrimEnd() == "aaa").ToList()); + data.Add(select.Where(a => a.Title.TrimEnd('a') == a.Title).ToList()); + data.Add(select.Where(a => a.Title.TrimEnd('a', 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.TrimEnd('a', 'b', 'c') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rtrim(a.`Title`) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'a' from a.`Title`) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'b' from trim(trailing 'a' from a.`Title`)) = concat(a.`Title`, 1)); + + //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 (trim(trailing 'c' from trim(trailing 'b' from trim(trailing 'a' from a.`Title`))) = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.TrimEnd() + "aaa").TrimEnd() == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.TrimEnd('a') + "aaa").TrimEnd('a') == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.TrimEnd('a', 'b') + "aaa").TrimEnd('a', 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.TrimEnd('a', 'b', 'c') + "aaa").TrimEnd('a', 'b', 'c') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (rtrim(concat(rtrim(a.`Title`), 'aaa')) = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'a' from concat(trim(trailing 'a' from a.`Title`), 'aaa')) = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (trim(trailing 'b' from trim(trailing 'a' from concat(trim(trailing 'b' from trim(trailing 'a' from a.`Title`)), 'aaa'))) = concat(a.`Title`, 1)); + + //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 (trim(trailing 'c' from trim(trailing 'b' from trim(trailing 'a' from concat(trim(trailing 'c' from trim(trailing 'b' from trim(trailing 'a' from a.`Title`))), 'aaa')))) = a__Type.`Name`) + } + [Fact] + public void Replace() { + var data = new List(); + data.Add(select.Where(a => a.Title.Replace("a", "b") == "aaa").ToList()); + data.Add(select.Where(a => a.Title.Replace("a", "b").Replace("b", "c") == a.Title).ToList()); + data.Add(select.Where(a => a.Title.Replace("a", "b").Replace("b", "c").Replace("c", "a") == (a.Title + 1)).ToList()); + data.Add(select.Where(a => a.Title.Replace("a", "b").Replace("b", "c").Replace(a.Type.Name, "a") == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (replace(a.`Title`, 'a', 'b') = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (replace(replace(a.`Title`, 'a', 'b'), 'b', 'c') = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (replace(replace(replace(a.`Title`, 'a', 'b'), 'b', 'c'), 'c', 'a') = concat(a.`Title`, 1)); + + //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 (replace(replace(replace(a.`Title`, 'a', 'b'), 'b', 'c'), a__Type.`Name`, 'a') = a__Type.`Name`); + data.Add(select.Where(a => (a.Title.Replace("a", "b") + "aaa").TrimEnd() == "aaa").ToList()); + data.Add(select.Where(a => (a.Title.Replace("a", "b").Replace("b", "c") + "aaa").TrimEnd('a') == a.Title).ToList()); + data.Add(select.Where(a => (a.Title.Replace("a", "b").Replace("b", "c").Replace("c", "a") + "aaa").TrimEnd('a', 'b') == (a.Title + 1)).ToList()); + data.Add(select.Where(a => (a.Title.Replace("a", "b").Replace("b", "c").Replace(a.Type.Name, "a") + "aaa").TrimEnd('a', 'b', 'c') == a.Type.Name).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (concat(replace(a.`Title`, 'a', 'b'), 'aaa') = 'aaa'); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (concat(replace(replace(a.`Title`, 'a', 'b'), 'b', 'c'), 'aaa') = a.`Title`); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (concat(replace(replace(replace(a.`Title`, 'a', 'b'), 'b', 'c'), 'c', 'a'), 'aaa') = concat(a.`Title`, 1)); + + //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 (concat(replace(replace(replace(a.`Title`, 'a', 'b'), 'b', 'c'), a__Type.`Name`, 'a'), 'aaa') = a__Type.`Name`) + } + [Fact] + public void CompareTo() { + var data = new List(); + data.Add(select.Where(a => a.Title.CompareTo(a.Title) == 0).ToList()); + data.Add(select.Where(a => a.Title.CompareTo(a.Title) > 0).ToList()); + data.Add(select.Where(a => a.Title.CompareTo(a.Title + 1) == 0).ToList()); + data.Add(select.Where(a => a.Title.CompareTo(a.Title + a.Type.Name) == 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (strcmp(a.`Title`, a.`Title`) = 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (strcmp(a.`Title`, a.`Title`) > 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (strcmp(a.`Title`, concat(a.`Title`, 1)) = 0); + + //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 (strcmp(a.`Title`, concat(a.`Title`, a__Type.`Name`)) = 0); + data.Add(select.Where(a => (a.Title + "aaa").CompareTo("aaa") == 0).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").CompareTo(a.Title) > 0).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").CompareTo(a.Title + 1) == 0).ToList()); + data.Add(select.Where(a => (a.Title + "aaa").CompareTo(a.Type.Name) == 0).ToList()); + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (strcmp(concat(a.`Title`, 'aaa'), 'aaa') = 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (strcmp(concat(a.`Title`, 'aaa'), a.`Title`) > 0); + + //SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 + //FROM `tb_topic` a + //WHERE (strcmp(concat(a.`Title`, 'aaa'), concat(a.`Title`, 1)) = 0); + + //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 (strcmp(concat(a.`Title`, 'aaa'), a__Type.`Name`) = 0) + } + } +} diff --git a/FreeSql.Tests/MySql/MySqlExpressionTest.cs b/FreeSql.Tests/MySql/Expression/TimeSpanTest.cs similarity index 66% rename from FreeSql.Tests/MySql/MySqlExpressionTest.cs rename to FreeSql.Tests/MySql/Expression/TimeSpanTest.cs index b0fdfd10..b62b1341 100644 --- a/FreeSql.Tests/MySql/MySqlExpressionTest.cs +++ b/FreeSql.Tests/MySql/Expression/TimeSpanTest.cs @@ -4,8 +4,8 @@ using System.Collections.Generic; using System.Linq; using Xunit; -namespace FreeSql.Tests.MySql { - public class MySqlExpressionTest { +namespace FreeSql.Tests.MySql.Expression { + public class TimeSpanTest { ISelect select => g.mysql.Select(); @@ -33,50 +33,43 @@ namespace FreeSql.Tests.MySql { } [Fact] - public void StartsWith() { + public void Days() { } [Fact] - public void EndsWith() { + public void Hours() { } [Fact] - public void Contains() { + public void Milliseconds() { } [Fact] - public void ToLower() { + public void Minutes() { } [Fact] - public void ToUpper() { - + public void Seconds() { } [Fact] - public void Substring() { + public void Ticks() { } [Fact] - public void Length() { + public void TotalDays() { } [Fact] - public void IndexOf() { + public void TotalHours() { } [Fact] - public void PadLeft() { + public void TotalMilliseconds() { } [Fact] - public void PadRight() { + public void TotalMinutes() { } [Fact] - public void Trim() { + public void TotalSeconds() { } [Fact] - public void TrimStart() { + public void Add() { } [Fact] - public void TrimEnd() { - } - [Fact] - public void Replace() { - } - [Fact] - public void CompareTo() { + public void Subtract() { } } } diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs index b8c27ef9..23851400 100644 --- a/FreeSql/Internal/CommonExpression.cs +++ b/FreeSql/Internal/CommonExpression.cs @@ -160,11 +160,27 @@ namespace FreeSql.Internal { 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.Constant: return _common.FormatSql("{0}", (exp as ConstantExpression)?.Value); + case ExpressionType.Call: + var exp3 = exp as MethodCallExpression; + if (exp3.Object.Type.FullName == "System.String") return ExpressionLambdaToSqlCallString(exp3, _tables, _selectColumnMap, tbtype, isQuoteName); + if (exp3.Object.Type.FullName == "System.Math") return ExpressionLambdaToSqlCallMath(exp3, _tables, _selectColumnMap, tbtype, isQuoteName); + if (exp3.Object.Type.FullName == "System.DateTime" || exp3.Object.Type.GenericTypeArguments.FirstOrDefault()?.FullName == "System.DateTime") return ExpressionLambdaToSqlCallDateTime(exp3, _tables, _selectColumnMap, tbtype, isQuoteName); + if (exp3.Object.Type.FullName == "System.TimeSpan" || exp3.Object.Type.GenericTypeArguments.FirstOrDefault()?.FullName == "System.TimeSpan") return ExpressionLambdaToSqlCallTimeSpan(exp3, _tables, _selectColumnMap, tbtype, isQuoteName); + throw new Exception($"MySqlExpression 未现实函数表达式 {exp3} 解析"); case ExpressionType.MemberAccess: + var exp4 = exp as MemberExpression; + var extRet = ""; + if (exp4.Expression == null && exp4.Type.FullName == "System.DateTime" && exp4.Member.Name == "Now") return ExpressionLambdaToSqlMemberAccessDateTime(exp4, _tables, _selectColumnMap, tbtype, isQuoteName); + if (exp4.Expression.Type.FullName == "System.String") extRet = ExpressionLambdaToSqlMemberAccessString(exp4, _tables, _selectColumnMap, tbtype, isQuoteName); + else if (exp4.Expression.Type.FullName == "System.Math") extRet = ExpressionLambdaToSqlMemberAccessMath(exp4, _tables, _selectColumnMap, tbtype, isQuoteName); + else if (exp4.Expression.Type.FullName == "System.DateTime" || exp4.Type.GenericTypeArguments.FirstOrDefault()?.FullName == "System.DateTime") extRet = ExpressionLambdaToSqlMemberAccessDateTime(exp4, _tables, _selectColumnMap, tbtype, isQuoteName); + else if (exp4.Expression.Type.FullName == "System.TimeSpan" || exp4.Type.GenericTypeArguments.FirstOrDefault()?.FullName == "System.TimeSpan") extRet = ExpressionLambdaToSqlMemberAccessTimeSpan(exp4, _tables, _selectColumnMap, tbtype, isQuoteName); + if (string.IsNullOrEmpty(extRet) == false) return extRet; + var expStack = new Stack(); expStack.Push(exp); MethodCallExpression callExp = null; - var exp2 = (exp as MemberExpression).Expression; + var exp2 = exp4.Expression; while (true) { switch(exp2.NodeType) { case ExpressionType.Constant: @@ -188,7 +204,7 @@ namespace FreeSql.Internal { break; } if (expStack.First().NodeType != ExpressionType.Parameter) return _common.FormatSql("{0}", Expression.Lambda(exp).Compile().DynamicInvoke()); - if (callExp != null) return ExpressionLambdaToSqlCall(callExp, _tables, _selectColumnMap, tbtype, isQuoteName); + if (callExp != null) return ExpressionLambdaToSql(callExp, _tables, _selectColumnMap, tbtype, isQuoteName); if (_tables == null) { var pp = expStack.Pop() as ParameterExpression; var memberExp = expStack.Pop() as MemberExpression; @@ -255,7 +271,6 @@ namespace FreeSql.Internal { } if (isQuoteName) name2 = _common.QuoteSqlName(name2); return $"{alias2}.{name2}"; - case ExpressionType.Call: return ExpressionLambdaToSqlCall(exp as MethodCallExpression, _tables, _selectColumnMap, tbtype, isQuoteName); } if (dicExpressionOperator.TryGetValue(exp.NodeType, out var tryoper) == false) return ""; var expBinary = exp as BinaryExpression; @@ -268,10 +283,17 @@ namespace FreeSql.Internal { left = tmp; } if (right == "NULL") tryoper = tryoper == "=" ? " IS " : " IS NOT "; + if (tryoper == "+" && (expBinary.Left.Type.FullName == "System.String" || expBinary.Right.Type.FullName == "System.String")) return _common.StringConcat(left, right, expBinary.Left.Type, expBinary.Right.Type); return $"{left} {tryoper} {right}"; } - internal abstract string ExpressionLambdaToSqlCall(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName); - + internal abstract string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName); + internal abstract string ExpressionLambdaToSqlMemberAccessMath(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); } } diff --git a/FreeSql/Internal/CommonUtils.cs b/FreeSql/Internal/CommonUtils.cs index 8e6f118b..e174f185 100644 --- a/FreeSql/Internal/CommonUtils.cs +++ b/FreeSql/Internal/CommonUtils.cs @@ -16,6 +16,7 @@ namespace FreeSql.Internal { internal abstract string QuoteSqlName(string name); internal abstract string QuoteParamterName(string name); internal abstract string IsNull(string sql, object value); + internal abstract string StringConcat(string left, string right, Type leftType, Type rightType); internal ICodeFirst CodeFirst { get; set; } internal TableInfo GetTableByEntity(Type entity) => Utils.GetTableByEntity(entity, this); diff --git a/FreeSql/MySql/Curd/MySqlSelect.cs b/FreeSql/MySql/Curd/MySqlSelect.cs index a37f1886..5e766461 100644 --- a/FreeSql/MySql/Curd/MySqlSelect.cs +++ b/FreeSql/MySql/Curd/MySqlSelect.cs @@ -10,7 +10,10 @@ namespace FreeSql.MySql.Curd { class MySqlSelect : FreeSql.Internal.CommonProvider.Select1Provider where T1 : class { - internal static string ToSqlStatic(CommonUtils _commonUtils, string _select, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having, string _orderby, int _skip, int _limit, List _tables) { + internal static string ToSqlStatic(CommonUtils _commonUtils, string _select, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having, string _orderby, int _skip, int _limit, List _tables, IFreeSql _orm) { + if (_orm.CodeFirst.IsAutoSyncStructure) + _orm.CodeFirst.SyncStructure(_tables.Select(a => a.Table.Type).ToArray()); + var sb = new StringBuilder(); sb.Append(_select).Append(field).Append(" \r\nFROM "); var tbsjoin = _tables.Where(a => a.Type != SelectTableInfoType.From).ToArray(); @@ -73,42 +76,42 @@ namespace FreeSql.MySql.Curd { public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new MySqlSelect(_orm, _commonUtils, _commonExpression, null); MySqlSelect.CopyData(this, ret); return ret; } public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new MySqlSelect(_orm, _commonUtils, _commonExpression, null); MySqlSelect.CopyData(this, ret); return ret; } 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); + 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); + 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); + 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.Select4Provider where T1 : class where T2 : class where T3 : class where T4 : 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); + 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.Select5Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : 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); + 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.Select6Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : 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); + 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.Select7Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : 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); + 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.Select8Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : 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); + 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.Select9Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : 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); + 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.Select10Provider where T1 : class 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 { 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); + 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/MySqlAdo/MySqlAdo.cs b/FreeSql/MySql/MySqlAdo/MySqlAdo.cs index ebcee181..33c1d44d 100644 --- a/FreeSql/MySql/MySqlAdo/MySqlAdo.cs +++ b/FreeSql/MySql/MySqlAdo/MySqlAdo.cs @@ -23,6 +23,7 @@ namespace FreeSql.MySql { } } } + static DateTime dt1970 = new DateTime(1970, 1, 1); public override object AddslashesProcessParam(object param) { if (param == null) return "NULL"; if (param is bool || param is bool?) @@ -33,21 +34,24 @@ namespace FreeSql.MySql { return ((Enum)param).ToInt64(); else if (decimal.TryParse(string.Concat(param), out var trydec)) return param; - else if (param is DateTime) { - DateTime dt = (DateTime)param; - return string.Concat("'", dt.ToString("yyyy-MM-dd HH:mm:ss"), "'"); - } else if (param is DateTime?) { - DateTime? dt = param as DateTime?; - return string.Concat("'", dt.Value.ToString("yyyy-MM-dd HH:mm:ss"), "'"); + else if (param is DateTime) + return string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss"), "'"); + else if (param is DateTime?) + return string.Concat("'", (param as DateTime?).Value.ToString("yyyy-MM-dd HH:mm:ss"), "'"); + else if (param is TimeSpan) { + var ts = (TimeSpan)param; + return string.Concat("'", ts.Ticks > 0 ? "" : "-", ts.TotalHours, dt1970.AddTicks(Math.Abs(ts.Ticks)).ToString(":mm:ss.fff"), "'"); + } else if (param is TimeSpan) { + var ts = (param as TimeSpan?).Value; + return string.Concat("'", ts.Ticks > 0 ? "" : "-", ts.TotalHours, dt1970.AddTicks(Math.Abs(ts.Ticks)).ToString(":mm:ss.fff"), "'"); } else if (param is IEnumerable) { var sb = new StringBuilder(); var ie = param as IEnumerable; foreach (var z in ie) sb.Append(",").Append(AddslashesProcessParam(z)); return sb.Length == 0 ? "(NULL)" : sb.Remove(0, 1).Insert(0, "(").Append(")").ToString(); - } else { - return string.Concat("'", param.ToString().Replace("'", "''"), "'"); - //if (param is string) return string.Concat('N', nparms[a]); } + return string.Concat("'", param.ToString().Replace("'", "''"), "'"); + //if (param is string) return string.Concat('N', nparms[a]); } protected override DbCommand CreateCommand() { diff --git a/FreeSql/MySql/MySqlCodeFirst.cs b/FreeSql/MySql/MySqlCodeFirst.cs index 602da7fa..5fda0b99 100644 --- a/FreeSql/MySql/MySqlCodeFirst.cs +++ b/FreeSql/MySql/MySqlCodeFirst.cs @@ -169,12 +169,21 @@ where a.table_schema in ({0}) and a.table_name in ({1})".FormatMySql(isRenameTab return sb.Length == 0 ? null : sb.ToString(); } + Dictionary dicSyced = new Dictionary(); public bool SyncStructure() => this.SyncStructure(typeof(TEntity)); public bool SyncStructure(params Type[] entityTypes) { - var ddl = this.GetComparisonDDLStatements(entityTypes); - if (string.IsNullOrEmpty(ddl)) return true; + if (entityTypes == null) return true; + var syncTypes = entityTypes.Where(a => dicSyced.ContainsKey(a.FullName) == false).ToArray(); + if (syncTypes.Any() == false) return true; + var ddl = this.GetComparisonDDLStatements(syncTypes); + if (string.IsNullOrEmpty(ddl)) { + foreach (var syncType in syncTypes) dicSyced.Add(syncType.FullName, true); + return true; + } try { - return _orm.Ado.ExecuteNonQuery(CommandType.Text, ddl) > 0; + var affrows = _orm.Ado.ExecuteNonQuery(CommandType.Text, ddl); + foreach (var syncType in syncTypes) dicSyced.Add(syncType.FullName, true); + return affrows > 0; } catch { return false; } diff --git a/FreeSql/MySql/MySqlExpression.cs b/FreeSql/MySql/MySqlExpression.cs index ffc782f4..eb728bbc 100644 --- a/FreeSql/MySql/MySqlExpression.cs +++ b/FreeSql/MySql/MySqlExpression.cs @@ -2,6 +2,7 @@ using FreeSql.Internal.Model; using System; using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; namespace FreeSql.MySql { @@ -9,150 +10,174 @@ namespace FreeSql.MySql { public MySqlExpression(CommonUtils common) : base(common) { } - internal override string ExpressionLambdaToSqlCall(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { - if (exp.Object.Type.FullName == "System.String") { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); - switch (exp.Method.Name) { - case "StartsWith": - case "EndsWith": - case "Contains": - var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); - if (args0Value == "NULL") return $"({left}) IS NULL"; - if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"concat('%', {args0Value})")}"; - if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"concat({args0Value}, '%')")}"; - if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}"; - return $"({left}) like concat('%', {args0Value}, '%')"; - case "ToLower": return $"lower({left})"; - case "ToUpper": return $"upper({left})"; - case "Substring": return $"substr({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} + 1, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Length": return $"char_length({left})"; - case "IndexOf": - var indexOfFindStr = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); - if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"(locate({left}, {indexOfFindStr}, ParseLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName) + 1) - 1)"; - return $"(locate({left}, {indexOfFindStr}) - 1)"; - case "PadLeft": return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "PadRight": return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Trim": - case "TrimStart": - case "TrimEnd": - if (exp.Arguments.Count == 0) { - if (exp.Method.Name == "Trim") return $"trim({left})"; - if (exp.Method.Name == "TrimStart") return $"ltrim({left})"; - if (exp.Method.Name == "TrimStart") return $"rtrim({left})"; + internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Member.Name) { + case "Length": return $"char_length({left})"; + } + return null; + } + + internal override string ExpressionLambdaToSqlMemberAccessMath(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Member.Name) { + case "PI": return $"pi()"; + } + return null; + } + + internal override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + if (exp.Expression == null && exp.Member.Name == "Now") return "now()"; + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Member.Name) { + case "DayOfWeek": return $"(dayofweek({left}) - 1)"; + case "Day": return $"dayofmonth({left})"; + case "DayOfYear": return $"dayofyear({left})"; + case "Month": return $"month({left})"; + case "Year": return $"year({left})"; + case "Hour": return $"hour({left})"; + case "Minute": return $"minute({left})"; + case "Second": return $"second({left})"; + case "Millisecond": return $"floor(microsecond({left}) / 1000)"; + case "Ticks": return $"(time_to_sec({left}) * 10000000 + 621355968000000000)"; + } + return null; + } + + internal override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Member.Name) { + case "Days": return $"floor(time_to_sec({left}) / {60 * 60 * 24})"; + case "Hours": return $"extract(hour from {left})"; + case "Milliseconds": return $"floor(extract(microsecond from {left}) / 1000)"; + case "Minutes": return $"extract(minute from {left})"; + case "Seconds": return $"extract(second from {left})"; + case "Ticks": return $"(time_to_sec({left}) * 10000000 + extract(microsecond from {left}) * 10)"; + case "TotalDays": return $"floor(extract(hour from {left}) / 24)"; + case "TotalHours": return $"floor(time_to_sec({left}) / {60 * 60})"; + case "TotalMilliseconds": return $"(time_to_sec({left}) * 1000 + floor(extract(microsecond from {left}) / 1000))"; + case "TotalMinutes": return $"floor(time_to_sec({left}) / 60)"; + case "TotalSeconds": return $"time_to_sec({left})"; + } + 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); + switch (exp.Method.Name) { + case "StartsWith": + case "EndsWith": + case "Contains": + var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + if (args0Value == "NULL") return $"({left}) IS NULL"; + if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"concat('%', {args0Value})")}"; + if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"concat({args0Value}, '%')")}"; + if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}"; + return $"({left}) LIKE concat('%', {args0Value}, '%')"; + case "ToLower": return $"lower({left})"; + case "ToUpper": return $"upper({left})"; + case "Substring": + var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, 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": + var indexOfFindStr = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") { + var locateArgs1 = ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, 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)})"; + 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)})"; + case "Trim": + case "TrimStart": + case "TrimEnd": + if (exp.Arguments.Count == 0) { + if (exp.Method.Name == "Trim") return $"trim({left})"; + if (exp.Method.Name == "TrimStart") return $"ltrim({left})"; + if (exp.Method.Name == "TrimEnd") return $"rtrim({left})"; + } + foreach (var argsTrim02 in exp.Arguments) { + var argsTrim01s = new[] { argsTrim02 }; + if (argsTrim02.NodeType == ExpressionType.NewArrayInit) { + var arritem = argsTrim02 as NewArrayExpression; + argsTrim01s = arritem.Expressions.ToArray(); } - foreach (var argsTrim01 in exp.Arguments) { + 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 == "TrimStart") left = $"trim(trailing {ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, tbtype, isQuoteName)} from {left})"; + if (exp.Method.Name == "TrimEnd") left = $"trim(trailing {ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, 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)})"; - } + } + 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)})"; } + throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); + } - if (exp.Object.Type.FullName == "System.Math") { - 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 "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)})"; - case "Sqrt": return $"sqrt({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "PI": return $"pi()"; - 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)"; - } + internal override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, List _tables, List _selectColumnMap, 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 "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)"; } + throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); + } - //dayofweek = DayOfWeek - //dayofmonth = Day - //dayofyear = DayOfYear - //month = Month - //year = Year - //hour = Hour - //minute = Minute - //second = Second - /* - * date_add(date,interval expr type) - date_sub(date,interval expr type) - adddate(date,interval expr type) - subdate(date,interval expr type) - 对日期时间进行加减法运算 - (adddate()和subdate()是date_add()和date_sub()的同义词,也 - 可以用运算符+和-而不是函数 - date是一个datetime或date值,expr对date进行加减法的一个表 - 达式字符串type指明表达式expr应该如何被解释 -  [type值 含义 期望的expr格式]: -  second 秒 seconds -  minute 分钟 minutes -  hour 时间 hours -  day 天 days -  month 月 months -  year 年 years -  minute_second 分钟和秒 "minutes:seconds" -  hour_minute 小时和分钟 "hours:minutes" -  day_hour 天和小时 "days hours" -  year_month 年和月 "years-months" -  hour_second 小时, 分钟, "hours:minutes:seconds" -  day_minute 天, 小时, 分钟 "days hours:minutes" -  day_second 天, 小时, 分钟, 秒 "days - hours:minutes:seconds" - expr中允许任何标点做分隔符,如果所有是date值时结果是一个 -date值,否则结果是一个datetime值) - 如果type关键词不完整,则mysql从右端取值,day_second因为缺 -少小时分钟等于minute_second) - 如果增加month、year_month或year,天数大于结果月份的最大天 -数则使用最大天数) -mysql> select "1997-12-31 23:59:59" + interval 1 second; - -  -> 1998-01-01 00:00:00 -mysql> select interval 1 day + "1997-12-31"; -  -> 1998-01-01 -mysql> select "1998-01-01" - interval 1 second; -  -> 1997-12-31 23:59:59 -mysql> select date_add("1997-12-31 23:59:59",interval 1 -second); -  -> 1998-01-01 00:00:00 -mysql> select date_add("1997-12-31 23:59:59",interval 1 -day); -  -> 1998-01-01 23:59:59 -mysql> select date_add("1997-12-31 23:59:59",interval -"1:1" minute_second); -  -> 1998-01-01 00:01:00 -mysql> select date_sub("1998-01-01 00:00:00",interval "1 -1:1:1" day_second); -  -> 1997-12-30 22:58:59 -mysql> select date_add("1998-01-01 00:00:00", interval "-1 -10" day_hour); -  -> 1997-12-30 14:00:00 -mysql> select date_sub("1998-01-02", interval 31 day); -  -> 1997-12-02 -mysql> select extract(year from "1999-07-02"); -  -> 1999 -mysql> select extract(year_month from "1999-07-02 -01:02:03"); -  -> 199907 -mysql> select extract(day_minute from "1999-07-02 -01:02:03"); -  -> 20102 - */ - - //convert - var xxx = DateTime.Now.ToString(""); - - + internal override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); + var args1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Method.Name) { + case "Add": return $"date_add({left}, interval (time_to_sec({args1}) * 1000000 + extract(microsecond from {args1})) microsecond)"; + case "AddDays": return $"date_add({left}, interval {args1} day)"; + case "AddHours": return $"date_add({left}, interval {args1} hour)"; + case "AddMilliseconds": return $"date_add({left}, interval {args1} microsecond)"; + case "AddMinutes": return $"date_add({left}, interval {args1} minute)"; + case "AddMonths": return $"date_add({left}, interval {args1} month)"; + case "AddSeconds": return $"date_add({left}, interval {args1} second)"; + case "AddTicks": return $"date_add({left}, interval ({args1}) / 10 microsecond)"; + case "AddYears": return $"date_add({left}, interval {args1} year)"; + case "Subtract": + if (exp.Arguments[0].Type.FullName == "System.DateTime" || exp.Arguments[0].Type.GenericTypeArguments.FirstOrDefault()?.FullName == "System.DateTime") + return $"({left} - {args1})"; + if (exp.Arguments[0].Type.FullName == "System.TimeSpan" || exp.Arguments[0].Type.GenericTypeArguments.FirstOrDefault()?.FullName == "System.TimeSpan") + return $"date_sub({left}, interval (time_to_sec({args1}) * 1000000 + extract(microsecond from {args1})) microsecond)"; + break; + } + throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); + } + internal override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); + var args1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Method.Name) { + case "Add": return $"(date_add('1970-1-1', interval (time_to_sec({left}) * 1000000 + extract(microsecond from {left}) + time_to_sec({args1}) * 1000000 + extract(microsecond from {args1})) microsecond)) microsecond) - date_add('1970-1-1', interval 0 microsecond) second))"; + case "Subtract": return $"(date_add('1970-1-1', interval (time_to_sec({left}) * 1000000 + extract(microsecond from {left}) - time_to_sec({args1}) * 1000000 - extract(microsecond from {args1})) microsecond) - date_add('1970-1-1', interval 0 second))"; + } throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); } } diff --git a/FreeSql/MySql/MySqlUtils.cs b/FreeSql/MySql/MySqlUtils.cs index 6fc0f3aa..7f30c163 100644 --- a/FreeSql/MySql/MySqlUtils.cs +++ b/FreeSql/MySql/MySqlUtils.cs @@ -44,5 +44,6 @@ namespace FreeSql.MySql { internal override string QuoteSqlName(string name) => $"`{name.Trim('`').Replace(".", "`.`")}`"; internal override string QuoteParamterName(string name) => $"?{name}"; internal override string IsNull(string sql, object value) => $"ifnull({sql}, {value})"; + internal override string StringConcat(string left, string right, Type leftType, Type rightType) => $"concat({left}, {right})"; } } diff --git a/FreeSql/PostgreSQL/Curd/PostgreSQLSelect.cs b/FreeSql/PostgreSQL/Curd/PostgreSQLSelect.cs index e74bdc7a..ed369b6b 100644 --- a/FreeSql/PostgreSQL/Curd/PostgreSQLSelect.cs +++ b/FreeSql/PostgreSQL/Curd/PostgreSQLSelect.cs @@ -10,7 +10,10 @@ namespace FreeSql.PostgreSQL.Curd { class PostgreSQLSelect : FreeSql.Internal.CommonProvider.Select1Provider where T1 : class { - internal static string ToSqlStatic(CommonUtils _commonUtils, string _select, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having, string _orderby, int _skip, int _limit, List _tables) { + internal static string ToSqlStatic(CommonUtils _commonUtils, string _select, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having, string _orderby, int _skip, int _limit, List _tables, IFreeSql _orm) { + if (_orm.CodeFirst.IsAutoSyncStructure) + _orm.CodeFirst.SyncStructure(_tables.Select(a => a.Table.Type).ToArray()); + var sb = new StringBuilder(); sb.Append(_select).Append(field).Append(" \r\nFROM "); var tbsjoin = _tables.Where(a => a.Type != SelectTableInfoType.From).ToArray(); @@ -75,42 +78,42 @@ namespace FreeSql.PostgreSQL.Curd { public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new PostgreSQLSelect(_orm, _commonUtils, _commonExpression, null); PostgreSQLSelect.CopyData(this, ret); return ret; } public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new PostgreSQLSelect(_orm, _commonUtils, _commonExpression, null); PostgreSQLSelect.CopyData(this, ret); return ret; } 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); + 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); + 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); + 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.Select4Provider where T1 : class where T2 : class where T3 : class where T4 : 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); + 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.Select5Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : 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); + 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.Select6Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : 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); + 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.Select7Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : 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); + 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.Select8Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : 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); + 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.Select9Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : 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); + 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.Select10Provider where T1 : class 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 { 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); + 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/PostgreSQLAdo/PostgreSQLAdo.cs b/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLAdo.cs index 9967b07a..ada5a4d4 100644 --- a/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLAdo.cs +++ b/FreeSql/PostgreSQL/PostgreSQLAdo/PostgreSQLAdo.cs @@ -23,6 +23,7 @@ namespace FreeSql.PostgreSQL { } } } + static DateTime dt1970 = new DateTime(1970, 1, 1); public override object AddslashesProcessParam(object param) { if (param == null) return "NULL"; if (param is bool || param is bool?) @@ -31,12 +32,16 @@ namespace FreeSql.PostgreSQL { return string.Concat("'", param.ToString().Replace("'", "''"), "'"); else if (decimal.TryParse(string.Concat(param), out var trydec)) return param; - else if (param is DateTime) { - DateTime dt = (DateTime)param; - return string.Concat("'", dt.ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "'"); - } else if (param is DateTime?) { - DateTime? dt = param as DateTime?; - return string.Concat("'", dt.Value.ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "'"); + else if (param is DateTime) + return string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "'"); + else if (param is DateTime?) + return string.Concat("'", (param as DateTime?).Value.ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "'"); + else if (param is TimeSpan) { + var ts = (TimeSpan)param; + return string.Concat("'", ts.Ticks > 0 ? "" : "-", ts.TotalHours, dt1970.AddTicks(Math.Abs(ts.Ticks)).ToString(":mm:ss.ffffff"), "'"); + } else if (param is TimeSpan) { + var ts = (param as TimeSpan?).Value; + return string.Concat("'", ts.Ticks > 0 ? "" : "-", ts.TotalHours, dt1970.AddTicks(Math.Abs(ts.Ticks)).ToString(":mm:ss.ffffff"), "'"); } else if (param is IEnumerable) { var sb = new StringBuilder(); var ie = param as IEnumerable; diff --git a/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs b/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs index 2d4991ce..5924ba2c 100644 --- a/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs +++ b/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs @@ -100,8 +100,8 @@ namespace FreeSql.PostgreSQL { if (enumType == null && type.FullName.StartsWith("System.Nullable`1[") && type.GenericTypeArguments.Length == 1 && type.GenericTypeArguments.First().IsEnum) enumType = type.GenericTypeArguments.First(); if (enumType != null) { var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ? - (NpgsqlDbType.Bigint, "int8", $"int8{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true) : - (NpgsqlDbType.Integer, "int4", $"int4{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true); + (NpgsqlDbType.Varchar, "varchar", $"varchar(32){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true) : + (NpgsqlDbType.Varchar, "varchar", $"varchar(32){(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true); if (_dicCsToDb.ContainsKey(type.FullName) == false) { lock (_dicCsToDbLock) { if (_dicCsToDb.ContainsKey(type.FullName) == false) @@ -116,6 +116,7 @@ namespace FreeSql.PostgreSQL { public string GetComparisonDDLStatements() => this.GetComparisonDDLStatements(typeof(TEntity)); public string GetComparisonDDLStatements(params Type[] entityTypes) { var sb = new StringBuilder(); + var seqcols = new List<(ColumnInfo, string[], bool)>(); //序列 foreach (var entityType in entityTypes) { if (sb.Length > 0) sb.Append("\r\n"); var tb = _commonUtils.GetTableByEntity(entityType); @@ -134,13 +135,10 @@ namespace FreeSql.PostgreSQL { } else { //创建表 - var seqcols = new List(); sb.Append("CREATE TABLE IF NOT EXISTS ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ("); foreach (var tbcol in tb.Columns.Values) { - sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" "); - sb.Append(tbcol.Attribute.DbType.ToUpper()); - if (tbcol.Attribute.IsIdentity && tbcol.Attribute.DbType.IndexOf("serial", StringComparison.CurrentCultureIgnoreCase) == -1) seqcols.Add(tbcol); - sb.Append(","); + sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType.ToUpper()).Append(","); + if (tbcol.Attribute.IsIdentity) seqcols.Add((tbcol, tbname, true)); } if (tb.Primarys.Any() == false) sb.Remove(sb.Length - 1, 1); @@ -187,38 +185,54 @@ where ns.nspname = {0} and c.relname = {1}".FormatPostgreSQL(isRenameTable ? tbo if (addcols.TryGetValue(column, out var trycol)) { if (trycol.Attribute.DbType.ToLower().StartsWith(sqlType.ToLower()) == false || - (trycol.Attribute.DbType.IndexOf("NOT NULL") == -1) != is_nullable || - trycol.Attribute.IsIdentity != is_identity) { - sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(column)).Append(" TYPE ").Append(trycol.Attribute.DbType.ToUpper()); - if (trycol.Attribute.IsIdentity) sb.Append(" AUTO_INCREMENT"); - sb.Append(";\r\n"); + (trycol.Attribute.DbType.IndexOf("NOT NULL") == -1) != is_nullable) { + sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(column)).Append(" TYPE ").Append(trycol.Attribute.DbType.ToUpper()).Append(";\r\n"); } + if (trycol.Attribute.IsIdentity != is_identity) seqcols.Add((trycol, tbname, trycol.Attribute.IsIdentity)); addcols.Remove(column); - } else + } else { + if (trycol.Attribute.IsIdentity != is_identity) seqcols.Add((trycol, tbname, trycol.Attribute.IsIdentity)); surplus.Add(column, true); //记录剩余字段 + } } foreach (var addcol in addcols.Values) { if (string.IsNullOrEmpty(addcol.Attribute.OldName) == false && surplus.ContainsKey(addcol.Attribute.OldName)) { //修改列名 sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" RENAME COLUMN ").Append(_commonUtils.QuoteSqlName(addcol.Attribute.OldName)).Append(" TO ").Append(_commonUtils.QuoteSqlName(addcol.Attribute.Name)).Append(";\r\n"); - if (addcol.Attribute.IsIdentity) sb.Append(" AUTO_INCREMENT"); - sb.Append(";\r\n"); - } else { //添加列 - sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD COLUMN ").Append(_commonUtils.QuoteSqlName(addcol.Attribute.Name)).Append(" ").Append(addcol.Attribute.DbType.ToUpper()); - if (addcol.Attribute.IsIdentity) sb.Append(" AUTO_INCREMENT"); - sb.Append(";\r\n"); + sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD COLUMN ").Append(_commonUtils.QuoteSqlName(addcol.Attribute.Name)).Append(" ").Append(addcol.Attribute.DbType.ToUpper()).Append(";\r\n"); } } } + foreach(var seqcol in seqcols) { + var tbname = seqcol.Item2; + var seqname = Utils.GetCsName($"{tbname[0]}.{tbname[1]}_{seqcol.Item1.Attribute.Name}_sequence_name"); + var tbname2 = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"); + var colname2 = _commonUtils.QuoteSqlName(seqcol.Item1.Attribute.Name); + sb.Append("ALTER TABLE ").Append(tbname2).Append(" ALTER COLUMN ").Append(colname2).Append(" SET DEFAULT null;"); + sb.Append("DROP SEQUENCE IF EXISTS ").Append(seqname).Append(";"); + if (seqcol.Item3) { + sb.Append("CREATE SEQUENCE ").Append(seqname).Append(" START WITH (select coalesce(max(").Append(colname2).Append("),1) from ").Append(tbname2).Append(");"); + sb.Append("ALTER TABLE ").Append(tbname2).Append(" ALTER COLUMN ").Append(colname2).Append(" SET DEFAULT nextval('").Append(seqname).Append("'::regclass);"); + } + } return sb.Length == 0 ? null : sb.ToString(); } + Dictionary dicSyced = new Dictionary(); public bool SyncStructure() => this.SyncStructure(typeof(TEntity)); public bool SyncStructure(params Type[] entityTypes) { - var ddl = this.GetComparisonDDLStatements(entityTypes); - if (string.IsNullOrEmpty(ddl)) return true; + if (entityTypes == null) return true; + var syncTypes = entityTypes.Where(a => dicSyced.ContainsKey(a.FullName) == false).ToArray(); + if (syncTypes.Any() == false) return true; + var ddl = this.GetComparisonDDLStatements(syncTypes); + if (string.IsNullOrEmpty(ddl)) { + foreach (var syncType in syncTypes) dicSyced.Add(syncType.FullName, true); + return true; + } try { - return _orm.Ado.ExecuteNonQuery(CommandType.Text, ddl) > 0; + var affrows = _orm.Ado.ExecuteNonQuery(CommandType.Text, ddl); + foreach (var syncType in syncTypes) dicSyced.Add(syncType.FullName, true); + return affrows > 0; } catch { return false; } diff --git a/FreeSql/PostgreSQL/PostgreSQLExpression.cs b/FreeSql/PostgreSQL/PostgreSQLExpression.cs index 0b3be41c..2c8a6ebc 100644 --- a/FreeSql/PostgreSQL/PostgreSQLExpression.cs +++ b/FreeSql/PostgreSQL/PostgreSQLExpression.cs @@ -2,6 +2,7 @@ using FreeSql.Internal.Model; using System; using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; namespace FreeSql.PostgreSQL { @@ -9,151 +10,176 @@ namespace FreeSql.PostgreSQL { public PostgreSQLExpression(CommonUtils common) : base(common) { } - internal override string ExpressionLambdaToSqlCall(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { - if (exp.Object.Type.FullName == "System.String") { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); - switch (exp.Method.Name) { - case "StartsWith": - case "EndsWith": - case "Contains": - var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); - if (args0Value == "NULL") return $"({left}) IS NULL"; - if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"concat('%', {args0Value})")}"; - if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"concat({args0Value}, '%')")}"; - if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}"; - return $"({left}) like concat('%', {args0Value}, '%')"; - case "ToLower": return $"lower({left})"; - case "ToUpper": return $"upper({left})"; - case "Substring": return $"substr({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} + 1, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Length": return $"char_length({left})"; - case "IndexOf": - var indexOfFindStr = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); - if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"(locate({left}, {indexOfFindStr}, ParseLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName) + 1) - 1)"; - return $"(locate({left}, {indexOfFindStr}) - 1)"; - case "PadLeft": return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "PadRight": return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Trim": - case "TrimStart": - case "TrimEnd": - if (exp.Arguments.Count == 0) { - if (exp.Method.Name == "Trim") return $"trim({left})"; - if (exp.Method.Name == "TrimStart") return $"ltrim({left})"; - if (exp.Method.Name == "TrimStart") return $"rtrim({left})"; - } - foreach (var argsTrim01 in exp.Arguments) { - 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 == "TrimStart") left = $"trim(trailing {ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, 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)})"; - } + internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Member.Name) { + case "Length": return $"char_length({left})"; } + throw new Exception($"PostgreSQLExpression 未现实函数表达式 {exp} 解析"); + } - if (exp.Object.Type.FullName == "System.Math") { - 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 "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)})"; - case "Sqrt": return $"sqrt({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "PI": return $"pi()"; - 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)"; - } + internal override string ExpressionLambdaToSqlMemberAccessMath(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Member.Name) { + case "PI": return $"pi()"; } + throw new Exception($"PostgreSQLExpression 未现实函数表达式 {exp} 解析"); + } - //dayofweek = DayOfWeek - //dayofmonth = Day - //dayofyear = DayOfYear - //month = Month - //year = Year - //hour = Hour - //minute = Minute - //second = Second - /* - * date_add(date,interval expr type) - date_sub(date,interval expr type) - adddate(date,interval expr type) - subdate(date,interval expr type) - 对日期时间进行加减法运算 - (adddate()和subdate()是date_add()和date_sub()的同义词,也 - 可以用运算符+和-而不是函数 - date是一个datetime或date值,expr对date进行加减法的一个表 - 达式字符串type指明表达式expr应该如何被解释 -  [type值 含义 期望的expr格式]: -  second 秒 seconds -  minute 分钟 minutes -  hour 时间 hours -  day 天 days -  month 月 months -  year 年 years -  minute_second 分钟和秒 "minutes:seconds" -  hour_minute 小时和分钟 "hours:minutes" -  day_hour 天和小时 "days hours" -  year_month 年和月 "years-months" -  hour_second 小时, 分钟, "hours:minutes:seconds" -  day_minute 天, 小时, 分钟 "days hours:minutes" -  day_second 天, 小时, 分钟, 秒 "days - hours:minutes:seconds" - expr中允许任何标点做分隔符,如果所有是date值时结果是一个 -date值,否则结果是一个datetime值) - 如果type关键词不完整,则mysql从右端取值,day_second因为缺 -少小时分钟等于minute_second) - 如果增加month、year_month或year,天数大于结果月份的最大天 -数则使用最大天数) -mysql> select "1997-12-31 23:59:59" + interval 1 second; + internal override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + if (exp.Expression == null && exp.Member.Name == "Now") return "current_timestamp"; + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Member.Name) { + case "DayOfWeek": return $"extract(dow from ({left})::timestamp)"; + case "Day": return $"extract(day from ({left})::timestamp)"; + case "DayOfYear": return $"extract(doy from ({left})::timestamp)"; + case "Month": return $"extract(month from ({left})::timestamp)"; + case "Year": return $"extract(year from ({left})::timestamp)"; + case "Hour": return $"extract(hour from ({left})::timestamp)"; + case "Minute": return $"extract(minute from ({left})::timestamp)"; + case "Second": return $"extract(second from ({left})::timestamp)"; + case "Millisecond": return $"(extract(milliseconds from ({left})::timestamp) - extract(second from ({left})::timestamp) * 1000)"; + case "Ticks": return $"(extract(epoch from ({left})::timestamp) * 10000000 + 621355968000000000)"; + } + throw new Exception($"PostgreSQLExpression 未现实函数表达式 {exp} 解析"); + } -  -> 1998-01-01 00:00:00 -mysql> select interval 1 day + "1997-12-31"; -  -> 1998-01-01 -mysql> select "1998-01-01" - interval 1 second; -  -> 1997-12-31 23:59:59 -mysql> select date_add("1997-12-31 23:59:59",interval 1 -second); -  -> 1998-01-01 00:00:00 -mysql> select date_add("1997-12-31 23:59:59",interval 1 -day); -  -> 1998-01-01 23:59:59 -mysql> select date_add("1997-12-31 23:59:59",interval -"1:1" minute_second); -  -> 1998-01-01 00:01:00 -mysql> select date_sub("1998-01-01 00:00:00",interval "1 -1:1:1" day_second); -  -> 1997-12-30 22:58:59 -mysql> select date_add("1998-01-01 00:00:00", interval "-1 -10" day_hour); -  -> 1997-12-30 14:00:00 -mysql> select date_sub("1998-01-02", interval 31 day); -  -> 1997-12-02 -mysql> select extract(year from "1999-07-02"); -  -> 1999 -mysql> select extract(year_month from "1999-07-02 -01:02:03"); -  -> 199907 -mysql> select extract(day_minute from "1999-07-02 -01:02:03"); -  -> 20102 - */ + internal override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Member.Name) { + case "Days": return $"floor(extract(epoch from ({left})::interval) / {60 * 60 * 24})"; + case "Hours": return $"extract(hour from ({left})::interval)"; + case "Milliseconds": return $"(extract(milliseconds from ({left})::interval) - extract(second from ({left})::interval) * 1000)"; + case "Minutes": return $"extract(minute from ({left})::interval)"; + case "Seconds": return $"extract(second from ({left})::interval)"; + case "Ticks": return $"(extract(epoch from ({left})::interval) * 10000000)"; + case "TotalDays": return $"floor(extract(epoch from ({left})::interval) / {60 * 60 * 24})"; + case "TotalHours": return $"floor(extract(epoch from ({left})::interval) / {60 * 60})"; + case "TotalMilliseconds": return $"(epoch from ({left})::interval + extract(milliseconds from ({left})::interval) - extract(second from ({left})::interval) * 1000)"; + case "TotalMinutes": return $"floor(extract(epoch from ({left})::interval) / 60)"; + case "TotalSeconds": return $"extract(epoch from ({left})::interval)"; + } + throw new Exception($"PostgreSQLExpression 未现实函数表达式 {exp} 解析"); + } + internal override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Method.Name) { + case "StartsWith": + case "EndsWith": + case "Contains": + var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, 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"; + } + if (exp.Method.Name == "StartsWith") return $"({left}) {likeOpt} {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' || ({args0Value})::varchar)")}"; + if (exp.Method.Name == "EndsWith") return $"({left}) {likeOpt} {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(({args0Value})::varchar || '%')")}"; + if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) {likeOpt} {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}"; + return $"({left}) {likeOpt} ('%' || ({args0Value})::varchar || '%')"; + case "ToLower": return $"lower({left})"; + case "ToUpper": return $"upper({left})"; + case "Substring": + var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, 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)"; + 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)})"; + 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)})"; + case "Trim": + case "TrimStart": + case "TrimEnd": + if (exp.Arguments.Count == 0) { + if (exp.Method.Name == "Trim") return $"trim({left})"; + if (exp.Method.Name == "TrimStart") return $"ltrim({left})"; + if (exp.Method.Name == "TrimEnd") return $"rtrim({left})"; + } + var trimArg = ""; + foreach (var argsTrim02 in exp.Arguments) { + var argsTrim01s = new[] { argsTrim02 }; + if (argsTrim02.NodeType == ExpressionType.NewArrayInit) { + var arritem = argsTrim02 as NewArrayExpression; + argsTrim01s = arritem.Expressions.ToArray(); + } + foreach (var argsTrim01 in argsTrim01s) { + var trimChr = ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, tbtype, isQuoteName).Trim('"'); + if (trimChr.Length == 1) trimArg += trimChr; + else trimArg += $" || ({trimArg})"; + } + } + if (exp.Method.Name == "Trim") left = $"trim({left}, {trimArg})"; + if (exp.Method.Name == "TrimStart") left = $"ltrim({left}, {trimArg})"; + if (exp.Method.Name == "TrimEnd") left = $"rtrim({left}, {trimArg})"; + 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)})"; + } + throw new Exception($"PostgreSQLExpression 未现实函数表达式 {exp} 解析"); + } - //convert - var xxx = DateTime.Now.ToString(""); + internal override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, List _tables, List _selectColumnMap, 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 "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)"; + } + throw new Exception($"PostgreSQLExpression 未现实函数表达式 {exp} 解析"); + } - - throw new Exception($"MySqlExpression 未现实函数表达式 {exp} 解析"); + internal override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); + var args1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Method.Name) { + case "Add": return $"(({left})::timestamp + ({args1})::interval)"; + case "AddDays": return $"(({left})::timestamp + (({args1}) || ' day')::interval)"; + case "AddHours": return $"(({left})::timestamp + (({args1}) || ' hour')::interval)"; + case "AddMilliseconds": return $"(({left})::timestamp + (({args1}) || ' milliseconds')::interval)"; + case "AddMinutes": return $"(({left})::timestamp + (({args1}) || ' minute')::interval)"; + case "AddMonths": return $"(({left})::timestamp + (({args1}) || ' month')::interval)"; + case "AddSeconds": return $"(({left})::timestamp + (({args1}) || ' second')::interval)"; + case "AddTicks": return $"(({left})::timestamp + (({args1}) / 10 || ' microseconds')::interval)"; + case "AddYears": return $"(({left})::timestamp + (({args1}) || ' year')::interval)"; + case "Subtract": + if (exp.Arguments[0].Type.FullName == "System.DateTime" || exp.Arguments[0].Type.GenericTypeArguments.FirstOrDefault()?.FullName == "System.DateTime") + return $"(({left})::timestamp - ({args1})::timestamp)"; + if (exp.Arguments[0].Type.FullName == "System.TimeSpan" || exp.Arguments[0].Type.GenericTypeArguments.FirstOrDefault()?.FullName == "System.TimeSpan") + return $"(({left})::timestamp - ({args1})::interval)"; + break; + } + throw new Exception($"PostgreSQLExpression 未现实函数表达式 {exp} 解析"); + } + internal override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); + var args1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Method.Name) { + case "Add": return $"(({left})::interval + ({args1})::interval)"; + case "Subtract": return $"(({left})::interval - ({args1})::interval)"; + } + throw new Exception($"PostgreSQLExpression 未现实函数表达式 {exp} 解析"); } } } diff --git a/FreeSql/PostgreSQL/PostgreSQLUtils.cs b/FreeSql/PostgreSQL/PostgreSQLUtils.cs index 62fefcbf..39ea1bd0 100644 --- a/FreeSql/PostgreSQL/PostgreSQLUtils.cs +++ b/FreeSql/PostgreSQL/PostgreSQLUtils.cs @@ -1,8 +1,10 @@ using FreeSql.Internal; -using MySql.Data.MySqlClient; +using Npgsql; +using NpgsqlTypes; using System; using System.Collections.Generic; using System.Data.Common; +using System.Linq; namespace FreeSql.PostgreSQL { @@ -14,35 +16,44 @@ namespace FreeSql.PostgreSQL { internal override DbParameter AppendParamter(List _params, string parameterName, object value) { if (string.IsNullOrEmpty(parameterName)) parameterName = $"p_{_params?.Count}"; - MySqlParameter ret = null; - if (value == null) ret = new MySqlParameter { ParameterName = $"{parameterName}", Value = DBNull.Value }; + NpgsqlParameter ret = null; + if (value == null) ret = new NpgsqlParameter { ParameterName = $"{parameterName}", Value = DBNull.Value }; else { var type = value.GetType(); - ret = new MySqlParameter { + ret = new NpgsqlParameter { ParameterName = parameterName, Value = value }; - var tp = _orm.CodeFirst.GetDbInfo(type)?.type; - if (tp != null) ret.MySqlDbType = (MySqlDbType)tp.Value; + if (value.GetType().IsEnum || value.GetType().GenericTypeArguments.FirstOrDefault()?.IsEnum == true) { + ret.DataTypeName = ""; + } else { + var tp = _orm.CodeFirst.GetDbInfo(type)?.type; + if (tp != null) ret.NpgsqlDbType = (NpgsqlDbType)tp.Value; + } } _params?.Add(ret); return ret; } internal override DbParameter[] GetDbParamtersByObject(string sql, object obj) => - Utils.GetDbParamtersByObject(sql, obj, "?", (name, type, value) => { - var cp = new MySqlParameter { + Utils.GetDbParamtersByObject(sql, obj, "@", (name, type, value) => { + var ret = new NpgsqlParameter { ParameterName = name, Value = value ?? DBNull.Value }; - var tp = _orm.CodeFirst.GetDbInfo(type)?.type; - if (tp != null) cp.MySqlDbType = (MySqlDbType)tp.Value; - return cp; + if (value.GetType().IsEnum || value.GetType().GenericTypeArguments.FirstOrDefault()?.IsEnum == true) { + ret.DataTypeName = ""; + } else { + var tp = _orm.CodeFirst.GetDbInfo(type)?.type; + if (tp != null) ret.NpgsqlDbType = (NpgsqlDbType)tp.Value; + } + return ret; }); internal override string FormatSql(string sql, params object[] args) => sql?.FormatMySql(args); - internal override string QuoteSqlName(string name) => $"`{name.Trim('`').Replace(".", "`.`")}`"; - internal override string QuoteParamterName(string name) => $"?{name}"; - internal override string IsNull(string sql, object value) => $"ifnull({sql}, {value})"; + internal override string QuoteSqlName(string name) => $"\"{name.Trim('"').Replace(".", "\".\"")}\""; + internal override string QuoteParamterName(string name) => $"@{name}"; + internal override string IsNull(string sql, object value) => $"coalesce({sql}, {value})"; + internal override string StringConcat(string left, string right, Type leftType, Type rightType) => $"{left} || {right}"; } } diff --git a/FreeSql/SqlServer/Curd/SqlServerSelect.cs b/FreeSql/SqlServer/Curd/SqlServerSelect.cs index 58a337a9..9eba1b8d 100644 --- a/FreeSql/SqlServer/Curd/SqlServerSelect.cs +++ b/FreeSql/SqlServer/Curd/SqlServerSelect.cs @@ -10,7 +10,10 @@ namespace FreeSql.SqlServer.Curd { class SqlServerSelect : FreeSql.Internal.CommonProvider.Select1Provider where T1 : class { - internal static string ToSqlStatic(CommonUtils _commonUtils, string _select, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having, string _orderby, int _skip, int _limit, List _tables) { + internal static string ToSqlStatic(CommonUtils _commonUtils, string _select, string field, StringBuilder _join, StringBuilder _where, string _groupby, string _having, string _orderby, int _skip, int _limit, List _tables, IFreeSql _orm) { + if (_orm.CodeFirst.IsAutoSyncStructure) + _orm.CodeFirst.SyncStructure(_tables.Select(a => a.Table.Type).ToArray()); + var sb = new StringBuilder(); sb.Append(_select); if (_limit > 0) sb.Append("TOP ").Append(_skip + _limit).Append(" "); @@ -85,42 +88,42 @@ namespace FreeSql.SqlServer.Curd { public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new SqlServerSelect(_orm, _commonUtils, _commonExpression, null); SqlServerSelect.CopyData(this, ret); return ret; } public override ISelect From(Expression, T2, T3, T4, T5, T6, T7, T8, T9, ISelectFromExpression>> exp) { this.InternalFrom(exp?.Body); var ret = new SqlServerSelect(_orm, _commonUtils, _commonExpression, null); SqlServerSelect.CopyData(this, ret); return ret; } 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); + 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); + 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); + 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.Select4Provider where T1 : class where T2 : class where T3 : class where T4 : 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); + 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.Select5Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : 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); + 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.Select6Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : 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); + 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.Select7Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : 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); + 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.Select8Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : 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); + 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.Select9Provider where T1 : class where T2 : class where T3 : class where T4 : class where T5 : class where T6 : class where T7 : class where T8 : class where T9 : 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); + 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.Select10Provider where T1 : class 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 { 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); + 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/SqlServerAdo/SqlServerAdo.cs b/FreeSql/SqlServer/SqlServerAdo/SqlServerAdo.cs index 8adf87f4..2dbb9e14 100644 --- a/FreeSql/SqlServer/SqlServerAdo/SqlServerAdo.cs +++ b/FreeSql/SqlServer/SqlServerAdo/SqlServerAdo.cs @@ -23,6 +23,7 @@ namespace FreeSql.SqlServer { } } } + static DateTime dt1970 = new DateTime(1970, 1, 1); public override object AddslashesProcessParam(object param) { if (param == null) return "NULL"; if (param is bool || param is bool?) @@ -31,12 +32,16 @@ namespace FreeSql.SqlServer { return string.Concat("'", param.ToString().Replace("'", "''"), "'"); else if (decimal.TryParse(string.Concat(param), out var trydec)) return param; - else if (param is DateTime) { - DateTime dt = (DateTime)param; - return string.Concat("'", dt.ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "'"); - } else if (param is DateTime?) { - DateTime? dt = param as DateTime?; - return string.Concat("'", dt.Value.ToString("yyyy-MM-dd HH:mm:ss.ffffff"), "'"); + else if (param is DateTime) + return string.Concat("'", ((DateTime)param).ToString("yyyy-MM-dd HH:mm:ss.fff"), "'"); + else if (param is DateTime?) + return string.Concat("'", (param as DateTime?).Value.ToString("yyyy-MM-dd HH:mm:ss.fff"), "'"); + else if (param is TimeSpan) { + var ts = (TimeSpan)param; + return string.Concat("'", dt1970.Add(ts).ToString("yyyy-MM-dd HH:mm:ss.fff"), "'"); + } else if (param is TimeSpan) { + var ts = (param as TimeSpan?).Value; + return string.Concat("'", dt1970.Add(ts).ToString("yyyy-MM-dd HH:mm:ss.fff"), "'"); } else if (param is IEnumerable) { var sb = new StringBuilder(); var ie = param as IEnumerable; diff --git a/FreeSql/SqlServer/SqlServerCodeFirst.cs b/FreeSql/SqlServer/SqlServerCodeFirst.cs index 3777c7d2..262629c3 100644 --- a/FreeSql/SqlServer/SqlServerCodeFirst.cs +++ b/FreeSql/SqlServer/SqlServerCodeFirst.cs @@ -160,12 +160,21 @@ where a.object_id in (object_id(N'[{0}].[{1}]'))", isRenameTable ? tboldname : t return sb.Length == 0 ? null : sb.ToString(); } + Dictionary dicSyced = new Dictionary(); public bool SyncStructure() => this.SyncStructure(typeof(TEntity)); public bool SyncStructure(params Type[] entityTypes) { - var ddl = this.GetComparisonDDLStatements(entityTypes); - if (string.IsNullOrEmpty(ddl)) return true; + if (entityTypes == null) return true; + var syncTypes = entityTypes.Where(a => dicSyced.ContainsKey(a.FullName) == false).ToArray(); + if (syncTypes.Any() == false) return true; + var ddl = this.GetComparisonDDLStatements(syncTypes); + if (string.IsNullOrEmpty(ddl)) { + foreach (var syncType in syncTypes) dicSyced.Add(syncType.FullName, true); + return true; + } try { - return _orm.Ado.ExecuteNonQuery(CommandType.Text, ddl) > 0; + var affrows = _orm.Ado.ExecuteNonQuery(CommandType.Text, ddl); + foreach (var syncType in syncTypes) dicSyced.Add(syncType.FullName, true); + return affrows > 0; } catch { return false; } diff --git a/FreeSql/SqlServer/SqlServerExpression.cs b/FreeSql/SqlServer/SqlServerExpression.cs index 709d472a..3fe0fdaf 100644 --- a/FreeSql/SqlServer/SqlServerExpression.cs +++ b/FreeSql/SqlServer/SqlServerExpression.cs @@ -2,6 +2,7 @@ using FreeSql.Internal.Model; using System; using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; namespace FreeSql.SqlServer { @@ -9,73 +10,146 @@ namespace FreeSql.SqlServer { public SqlServerExpression(CommonUtils common) : base(common) { } - internal override string ExpressionLambdaToSqlCall(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { - if (exp.Object.Type.FullName == "System.String") { - var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); - switch (exp.Method.Name) { - case "StartsWith": - case "EndsWith": - case "Contains": - var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); - if (args0Value == "NULL") return $"({left}) IS NULL"; - if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"concat('%', {args0Value})")}"; - if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"concat({args0Value}, '%')")}"; - if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}"; - return $"({left}) like concat('%', {args0Value}, '%')"; - case "ToLower": return $"lower({left})"; - case "ToUpper": return $"upper({left})"; - case "Substring": return $"substr({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)} + 1, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Length": return $"char_length({left})"; - case "IndexOf": - var indexOfFindStr = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); - if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"(locate({left}, {indexOfFindStr}, ParseLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName) + 1) - 1)"; - return $"(locate({left}, {indexOfFindStr}) - 1)"; - case "PadLeft": return $"lpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "PadRight": return $"rpad({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "Trim": - case "TrimStart": - case "TrimEnd": - if (exp.Arguments.Count == 0) { - if (exp.Method.Name == "Trim") return $"trim({left})"; - if (exp.Method.Name == "TrimStart") return $"ltrim({left})"; - if (exp.Method.Name == "TrimStart") return $"rtrim({left})"; - } - foreach (var argsTrim01 in exp.Arguments) { - 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 == "TrimStart") left = $"trim(trailing {ExpressionLambdaToSql(argsTrim01, _tables, _selectColumnMap, 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)})"; - } + internal override string ExpressionLambdaToSqlMemberAccessString(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Member.Name) { + case "Length": return $"len({left})"; } + throw new Exception($"SqlServerExpression 未现实函数表达式 {exp} 解析"); + } - if (exp.Object.Type.FullName == "System.Math") { - 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 "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)})"; - case "Sqrt": return $"sqrt({ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; - case "PI": return $"pi()"; - 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)"; - } + internal override string ExpressionLambdaToSqlMemberAccessMath(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Member.Name) { + case "PI": return $"pi()"; } + throw new Exception($"SqlServerExpression 未现实函数表达式 {exp} 解析"); + } + internal override string ExpressionLambdaToSqlMemberAccessDateTime(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + if (exp.Expression == null && exp.Member.Name == "Now") return "getdate()"; + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Member.Name) { + case "DayOfWeek": return $"(datepart(weekday, {left}) - 1)"; + case "Day": return $"datepart(day, {left})"; + case "DayOfYear": return $"datepart(dayofyear, {left})"; + case "Month": return $"datepart(month, {left})"; + case "Year": return $"datepart(year, {left})"; + case "Hour": return $"datepart(hour, {left})"; + case "Minute": return $"datepart(minute, {left})"; + case "Second": return $"datepart(second, {left})"; + case "Millisecond": return $"datepart(millisecond, {left})"; + case "Ticks": return $"(datediff(second, '1970-1-1', {left}) * 10000000 + 621355968000000000)"; + } + throw new Exception($"SqlServerExpression 未现实函数表达式 {exp} 解析"); + } + + internal override string ExpressionLambdaToSqlMemberAccessTimeSpan(MemberExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Expression, _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Member.Name) { + case "Days": return $"datediff(day, '1970-1-1', {left})"; + case "Hours": return $"datepart(hour, '1970-1-1', {left})"; + case "Milliseconds": return $"datepart(millisecond, {left})"; + case "Minutes": return $"datepart(minute, {left})"; + case "Seconds": return $"datepart(second, {left})"; + case "Ticks": return $"(datediff(millisecond, '1970-1-1', {left}) * 10000)"; + case "TotalDays": return $"datediff(day, '1970-1-1', {left})"; + case "TotalHours": return $"datediff(hour, '1970-1-1', {left})"; + case "TotalMilliseconds": return $"datediff(millisecond, '1970-1-1', {left})"; + case "TotalMinutes": return $"datediff(minute, '1970-1-1', {left})"; + case "TotalSeconds": return $"datediff(second, '1970-1-1', {left})"; + } + throw new Exception($"SqlServerExpression 未现实函数表达式 {exp} 解析"); + } + internal override string ExpressionLambdaToSqlCallString(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Method.Name) { + case "StartsWith": + case "EndsWith": + case "Contains": + var args0Value = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + if (args0Value == "NULL") return $"({left}) IS NULL"; + if (exp.Method.Name == "StartsWith") return $"({left}) LIKE {(args0Value.StartsWith("'") ? args0Value.Insert(1, "%") : $"('%' + cast({args0Value} as nvarchar))")}"; + if (exp.Method.Name == "EndsWith") return $"({left}) LIKE {(args0Value.EndsWith("'") ? args0Value.Insert(args0Value.Length - 1, "%") : $"(cast({args0Value} as nvarchar) + '%')")}"; + if (args0Value.StartsWith("'") && args0Value.EndsWith("'")) return $"({left}) LIKE {args0Value.Insert(1, "%").Insert(args0Value.Length, "%")}"; + return $"({left}) LIKE ('%' + cast({args0Value} as nvarchar) + '%')"; + case "ToLower": return $"lower({left})"; + case "ToUpper": return $"upper({left})"; + case "Substring": + var substrArgs1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + if (long.TryParse(substrArgs1, out var testtrylng1)) substrArgs1 = (testtrylng1 + 1).ToString(); + else substrArgs1 += " + 1"; + if (exp.Arguments.Count == 1) return $"substring({left}, {substrArgs1})"; + return $"substring({left}, {substrArgs1}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + case "IndexOf": + var indexOfFindStr = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + if (exp.Arguments.Count > 1 && exp.Arguments[1].Type.FullName == "System.Int32") return $"(charindex({left}, {indexOfFindStr}, {ExpressionLambdaToSql(exp.Arguments[1], _tables, _selectColumnMap, tbtype, isQuoteName)} + 1) - 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)})"; + 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)})"; + 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 $"strcmp({left}, {ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName)})"; + } + throw new Exception($"SqlServerExpression 未现实函数表达式 {exp} 解析"); + } + + internal override string ExpressionLambdaToSqlCallMath(MethodCallExpression exp, List _tables, List _selectColumnMap, 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 "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 $"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)}, 0)"; + } + throw new Exception($"SqlServerExpression 未现实函数表达式 {exp} 解析"); + } + + internal override string ExpressionLambdaToSqlCallDateTime(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); + var args1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Method.Name) { + case "Add": return $"dateadd(millisecond, datediff(millisecond, '1970-1-1', {args1}), {left})"; + case "AddDays": return $"dateadd(day, {args1}, {left})"; + case "AddHours": return $"dateadd(hour, {args1}, {left})"; + case "AddMilliseconds": return $"dateadd(millisecond, {args1}, {left})"; + case "AddMinutes": return $"dateadd(minute, {args1}, {left})"; + case "AddMonths": return $"dateadd(month, {args1}, {left})"; + case "AddSeconds": return $"dateadd(second, {args1}, {left})"; + case "AddTicks": return $"dateadd(millisecond, {args1} / 10000, {left})"; + case "AddYears": return $"dateadd(year, {args1}, {left})"; + case "Subtract": return $"dateadd(millisecond, -datediff(millisecond, '1970-1-1', {args1}), {left})"; + } + throw new Exception($"SqlServerExpression 未现实函数表达式 {exp} 解析"); + } + internal override string ExpressionLambdaToSqlCallTimeSpan(MethodCallExpression exp, List _tables, List _selectColumnMap, SelectTableInfoType tbtype, bool isQuoteName) { + var left = ExpressionLambdaToSql(exp.Object, _tables, _selectColumnMap, tbtype, isQuoteName); + var args1 = ExpressionLambdaToSql(exp.Arguments[0], _tables, _selectColumnMap, tbtype, isQuoteName); + switch (exp.Method.Name) { + case "Add": return $"dateadd(millisecond, datediff(millisecond, '1970-1-1', {args1}), {left})"; + case "Subtract": return $"dateadd(millisecond, -datediff(millisecond, '1970-1-1', {args1}), {left})"; + } throw new Exception($"SqlServerExpression 未现实函数表达式 {exp} 解析"); } } diff --git a/FreeSql/SqlServer/SqlServerUtils.cs b/FreeSql/SqlServer/SqlServerUtils.cs index 5671eedd..6c9ca91e 100644 --- a/FreeSql/SqlServer/SqlServerUtils.cs +++ b/FreeSql/SqlServer/SqlServerUtils.cs @@ -45,5 +45,6 @@ namespace FreeSql.SqlServer { internal override string QuoteSqlName(string name) => $"[{name.TrimStart('[').TrimEnd(']').Replace(".", "].[")}]"; internal override string QuoteParamterName(string name) => $"@{name}"; internal override string IsNull(string sql, object value) => $"isnull({sql}, {value})"; + internal override string StringConcat(string left, string right, Type leftType, Type rightType) => $"{(leftType.FullName == "System.String" ? left : $"cast({left} as nvarchar)")} + {(rightType.FullName == "System.String" ? right : $"cast({right} as nvarchar)")}"; } }