From df07b7bcc4b6cfb16ced1566c0e0b1dc3e320a4f Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Wed, 19 Dec 2018 12:06:04 +0800 Subject: [PATCH 1/6] =?UTF-8?q?SqlServer=20CodeFirst=20=E9=80=82=E9=85=8D?= =?UTF-8?q?=E5=AE=8C=E6=88=90=EF=BC=88=E5=90=8C=E6=AD=A5=E7=BB=93=E6=9E=84?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Docs/codefirst.md | 16 +--- .../Generator/MySqlTemplateGeneratorTest.cs | 2 +- .../SqlServer/SqlServerCodeFirstTest.cs | 70 +++++++++++++++++ FreeSql.Tests/g.cs | 3 +- FreeSql/MySql/MySqlDbFirst.cs | 10 +++ FreeSql/PostgreSQL/PostgreSQLDbFirst.cs | 10 +++ FreeSql/SqlServer/SqlServerCodeFirst.cs | 77 +++++++++++-------- FreeSql/SqlServer/SqlServerDbFirst.cs | 10 +++ .../Models/for-table.cs.freesql | 3 +- 9 files changed, 153 insertions(+), 48 deletions(-) create mode 100644 FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs diff --git a/Docs/codefirst.md b/Docs/codefirst.md index 0bafd459..46ef96a8 100644 --- a/Docs/codefirst.md +++ b/Docs/codefirst.md @@ -1,18 +1,10 @@ # CodeFirst -### 支持的类型 +| 数据库 | 支持的类型类型 | +| - | - | +| MySql | bool, sbyte, short, int, long, byte, ushort, uint, ulong, double, float, decimal, Guid, TimeSpan, DateTime
bool?, sbyte?, short?, int?, long?, byte?, ushort?, uint?, ulong?, double?, float?, decimal?, Guid?, TimeSpan?, DateTime?
byte[], string, Enum & FlagsEnum
MygisPoint, MygisLineString, MygisPolygon, MygisMultiPoint, MygisMultiLineString, MygisMultiPolygon | +| SqlServer | bool, sbyte, short, int, long, byte, ushort, uint, ulong, double, float, decimal, Guid, TimeSpan, DateTime, DateTimeOffset
bool?, sbyte?, short?, int?, long?, byte?, ushort?, uint?, ulong?, double?, float?, decimal?, Guid?, TimeSpan?, DateTime?, DateTimeOffset?
byte[], string, Enum & FlagsEnum | -bool, byte, short, int, long, byte, ushort, uint, ulong, double, float, decimal, int, Guid - -bool?, byte?, short?, int?, long?, byte?, ushort?, uint?, ulong?, double?, float?, decimal?, int?, Guid? - -TimeSpan, DateTime - -TimeSpan?, DateTime? - -byte[], string - -MygisPoint, MygisLineString, MygisPolygon, MygisMultiPoint, MygisMultiLineString, MygisMultiPolygon ```csharp IFreeSql fsql = new FreeSql.FreeSqlBuilder() diff --git a/FreeSql.Tests/Generator/MySqlTemplateGeneratorTest.cs b/FreeSql.Tests/Generator/MySqlTemplateGeneratorTest.cs index ff0e085b..51d97a35 100644 --- a/FreeSql.Tests/Generator/MySqlTemplateGeneratorTest.cs +++ b/FreeSql.Tests/Generator/MySqlTemplateGeneratorTest.cs @@ -21,7 +21,7 @@ namespace FreeSql.Tests.Generator { [Fact] public void BuildRichEntityNavigationObject() { var gen = new TemplateGenerator(); - gen.Build(g.mysql.DbFirst, @"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\rich-entity-navigation-object", @"C:\Users\28810\Desktop\新建文件夹 (9)", "cccddd"); + gen.Build(g.mysql.DbFirst, @"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\rich-entity-navigation-object", @"C:\Users\28810\Desktop\新建文件夹 (9)", "ManagerDB"); } } } diff --git a/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs b/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs new file mode 100644 index 00000000..96785091 --- /dev/null +++ b/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs @@ -0,0 +1,70 @@ +using FreeSql.DataAnnotations; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.SqlServer { + public class SqlServerCodeFirstTest { + [Fact] + public void GetComparisonDDLStatements() { + + var sql = g.sqlserver.CodeFirst.GetComparisonDDLStatements(); + + + } + + + [Table(Name = "tb_alltype")] + class TableAllType { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + + [Column(OldName = "testFieldBool1111")] + public bool testFieldBool { get; set; } + public sbyte testFieldSByte { get; set; } + public short testFieldShort { get; set; } + public int testFieldInt { get; set; } + public long testFieldLong { get; set; } + public byte testFieldByte { get; set; } + public ushort testFieldUShort { get; set; } + public uint testFieldUInt { get; set; } + public ulong testFieldULong { get; set; } + public double testFieldDouble { get; set; } + public float testFieldFloat { get; set; } + public decimal testFieldDecimal { get; set; } + public TimeSpan testFieldTimeSpan { get; set; } + public DateTime testFieldDateTime { get; set; } + public DateTimeOffset testFieldDateTimeOffset { get; set; } + public byte[] testFieldBytes { get; set; } + public string testFieldString { get; set; } + public Guid testFieldGuid { get; set; } + + public bool? testFieldBoolNullable { get; set; } + public sbyte? testFieldSByteNullable { get; set; } + public short? testFieldShortNullable { get; set; } + public int? testFieldIntNullable { get; set; } + public long? testFielLongNullable { get; set; } + public byte? testFieldByteNullable { get; set; } + public ushort? testFieldUShortNullable { get; set; } + public uint? testFieldUIntNullable { get; set; } + public ulong? testFieldULongNullable { get; set; } + public double? testFieldDoubleNullable { get; set; } + public float? testFieldFloatNullable { get; set; } + public decimal? testFieldDecimalNullable { get; set; } + public TimeSpan? testFieldTimeSpanNullable { get; set; } + public DateTime? testFieldDateTimeNullable { get; set; } + public DateTimeOffset? testFieldDateTimeNullableOffset { get; set; } + public Guid? testFieldGuidNullable { get; set; } + + public TableAllTypeEnumType1 testFieldEnum1 { get; set; } + public TableAllTypeEnumType1? testFieldEnum1Nullable { get; set; } + public TableAllTypeEnumType2 testFieldEnum2 { get; set; } + public TableAllTypeEnumType2? testFieldEnum2Nullable { get; set; } + } + + public enum TableAllTypeEnumType1 { e1, e2, e3, e5 } + [Flags] public enum TableAllTypeEnumType2 { f1, f2, f3 } + } +} diff --git a/FreeSql.Tests/g.cs b/FreeSql.Tests/g.cs index 1f7f39b0..9ca30775 100644 --- a/FreeSql.Tests/g.cs +++ b/FreeSql.Tests/g.cs @@ -6,7 +6,8 @@ using System.Text; public class g { public static IFreeSql mysql = new FreeSql.FreeSqlBuilder() - .UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10") + //.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10") + .UseConnectionString(FreeSql.DataType.MySql, "Data Source=123.207.16.102;Port=3306;User ID=root;Password=qwe369258/*-;Initial Catalog=ManagerDB;Charset=utf8;SslMode=none;Max pool size=10") .Build(); public static IFreeSql sqlserver = new FreeSql.FreeSqlBuilder() diff --git a/FreeSql/MySql/MySqlDbFirst.cs b/FreeSql/MySql/MySqlDbFirst.cs index 942c52ba..af4e4db1 100644 --- a/FreeSql/MySql/MySqlDbFirst.cs +++ b/FreeSql/MySql/MySqlDbFirst.cs @@ -358,6 +358,16 @@ where a.constraint_schema in ({1}) and a.table_name in ({0}) and not isnull(posi if (ret == 0) ret = t1.Name.CompareTo(t2.Name); return ret; }); + foreach(var loc4 in loc1) { + var dicUniques = new Dictionary>(); + dicUniques.Add(string.Join(",", loc4.Primarys.Select(a => a.Name)), loc4.Primarys); + foreach(var loc5 in loc4.Uniques) { + var dickey = string.Join(",", loc5.Select(a => a.Name)); + if (dicUniques.ContainsKey(dickey)) continue; + dicUniques.Add(dickey, loc5); + } + loc4.Uniques = dicUniques.Values.ToList(); + } loc2.Clear(); loc3.Clear(); diff --git a/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs b/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs index f232571d..bbff5851 100644 --- a/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs +++ b/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs @@ -357,6 +357,16 @@ where a.constraint_schema in ({1}) and a.table_name in ({0}) and not isnull(posi if (ret == 0) ret = t1.Name.CompareTo(t2.Name); return ret; }); + foreach (var loc4 in loc1) { + var dicUniques = new Dictionary>(); + dicUniques.Add(string.Join(",", loc4.Primarys.Select(a => a.Name)), loc4.Primarys); + foreach (var loc5 in loc4.Uniques) { + var dickey = string.Join(",", loc5.Select(a => a.Name)); + if (dicUniques.ContainsKey(dickey)) continue; + dicUniques.Add(dickey, loc5); + } + loc4.Uniques = dicUniques.Values.ToList(); + } loc2.Clear(); loc3.Clear(); diff --git a/FreeSql/SqlServer/SqlServerCodeFirst.cs b/FreeSql/SqlServer/SqlServerCodeFirst.cs index 49fda5d8..8d648818 100644 --- a/FreeSql/SqlServer/SqlServerCodeFirst.cs +++ b/FreeSql/SqlServer/SqlServerCodeFirst.cs @@ -22,40 +22,51 @@ namespace FreeSql.SqlServer { public bool IsAutoSyncStructure { get; set; } = true; - static readonly Dictionary _dicCsToDb = new Dictionary() { - { "System.Boolean", (SqlDbType.Bit, "bit","bit NOT NULL", null, false) },{ "System.Nullable`1[System.Boolean]", (SqlDbType.Bit, "bit","bit", null, true) }, + static object _dicCsToDbLock = new object(); + static Dictionary _dicCsToDb = new Dictionary() { + { typeof(bool).FullName, (SqlDbType.Bit, "bit","bit NOT NULL", null, false) },{ typeof(bool?).FullName, (SqlDbType.Bit, "bit","bit", null, true) }, - { "System.SByte", (SqlDbType.TinyInt, "tinyint", "tinyint NOT NULL", false, false) },{ "System.Nullable`1[System.SByte]", (SqlDbType.TinyInt, "tinyint", "tinyint", false, true) }, - { "System.Int16", (SqlDbType.SmallInt, "smallint","smallint NOT NULL", false, false) },{ "System.Nullable`1[System.Int16]", (SqlDbType.SmallInt, "smallint", "smallint", false, true) }, - { "System.Int32", (SqlDbType.Int, "int", "int NOT NULL", false, false) },{ "System.Nullable`1[System.Int32]", (SqlDbType.Int, "int", "int", false, true) }, - { "System.Int64", (SqlDbType.BigInt, "bigint","bigint NOT NULL", false, false) },{ "System.Nullable`1[System.Int64]", (SqlDbType.BigInt, "bigint","bigint", false, true) }, + { typeof(sbyte).FullName, (SqlDbType.TinyInt, "tinyint", "tinyint NOT NULL", false, false) },{ typeof(sbyte?).FullName, (SqlDbType.TinyInt, "tinyint", "tinyint", false, true) }, + { typeof(short).FullName, (SqlDbType.SmallInt, "smallint","smallint NOT NULL", false, false) },{ typeof(short?).FullName, (SqlDbType.SmallInt, "smallint", "smallint", false, true) }, + { typeof(int).FullName, (SqlDbType.Int, "int", "int NOT NULL", false, false) },{ typeof(int?).FullName, (SqlDbType.Int, "int", "int", false, true) }, + { typeof(long).FullName, (SqlDbType.BigInt, "bigint","bigint NOT NULL", false, false) },{ typeof(long?).FullName, (SqlDbType.BigInt, "bigint","bigint", false, true) }, - { "System.Byte", (SqlDbType.TinyInt, "tinyint","tinyint NOT NULL", true, false) },{ "System.Nullable`1[System.Byte]", (SqlDbType.TinyInt, "tinyint","tinyint", true, true) }, - { "System.UInt16", (SqlDbType.SmallInt, "smallint","smallint NOT NULL", true, false) },{ "System.Nullable`1[System.UInt16]", (SqlDbType.SmallInt, "smallint", "smallint", true, true) }, - { "System.UInt32", (SqlDbType.Int, "int", "int NOT NULL", true, false) },{ "System.Nullable`1[System.UInt32]", (SqlDbType.Int, "int", "int", true, true) }, - { "System.UInt64", (SqlDbType.BigInt, "bigint", "bigint NOT NULL", true, false) },{ "System.Nullable`1[System.UInt64]", (SqlDbType.BigInt, "bigint", "bigint", true, true) }, + { typeof(byte).FullName, (SqlDbType.TinyInt, "tinyint","tinyint NOT NULL", true, false) },{ typeof(byte?).FullName, (SqlDbType.TinyInt, "tinyint","tinyint", true, true) }, + { typeof(ushort).FullName, (SqlDbType.SmallInt, "smallint","smallint NOT NULL", true, false) },{ typeof(ushort?).FullName, (SqlDbType.SmallInt, "smallint", "smallint", true, true) }, + { typeof(uint).FullName, (SqlDbType.Int, "int", "int NOT NULL", true, false) },{ typeof(uint?).FullName, (SqlDbType.Int, "int", "int", true, true) }, + { typeof(ulong).FullName, (SqlDbType.BigInt, "bigint", "bigint NOT NULL", true, false) },{ typeof(ulong?).FullName, (SqlDbType.BigInt, "bigint", "bigint", true, true) }, - { "System.Double", (SqlDbType.Float, "double", "double NOT NULL", false, false) },{ "System.Nullable`1[System.Double]", (SqlDbType.Float, "double", "double", false, true) }, - { "System.Single", (SqlDbType.Real, "float","float NOT NULL", false, false) },{ "System.Nullable`1[System.Single]", (SqlDbType.Real, "float","float", false, true) }, - { "System.Decimal", (SqlDbType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false) },{ "System.Nullable`1[System.Decimal]", (SqlDbType.Decimal, "decimal", "decimal(10,2)", false, true) }, + { typeof(double).FullName, (SqlDbType.Float, "float", "float NOT NULL", false, false) },{ typeof(double?).FullName, (SqlDbType.Float, "float", "float", false, true) }, + { typeof(float).FullName, (SqlDbType.Real, "real","real NOT NULL", false, false) },{ typeof(float?).FullName, (SqlDbType.Real, "real","real", false, true) }, + { typeof(decimal).FullName, (SqlDbType.Decimal, "decimal", "decimal(10,2) NOT NULL", false, false) },{ typeof(decimal?).FullName, (SqlDbType.Decimal, "decimal", "decimal(10,2)", false, true) }, - { "System.TimeSpan", (SqlDbType.Time, "time","time NOT NULL", false, false) },{ "System.Nullable`1[System.TimeSpan]", (SqlDbType.Time, "time", "time",false, true) }, - { "System.DateTime", (SqlDbType.DateTime, "datetime", "datetime NOT NULL", false, false) },{ "System.Nullable`1[System.DateTime]", (SqlDbType.DateTime, "datetime", "datetime", false, true) }, - { "System.DateTimeOffset", (SqlDbType.DateTimeOffset, "datetimeoffset", "datetimeoffset NOT NULL", false, false) },{ "System.Nullable`1[System.DateTime]", (SqlDbType.DateTimeOffset, "datetimeoffset", "datetimeoffset", false, true) }, + { typeof(TimeSpan).FullName, (SqlDbType.Time, "time","time NOT NULL", false, false) },{ typeof(TimeSpan?).FullName, (SqlDbType.Time, "time", "time",false, true) }, + { typeof(DateTime).FullName, (SqlDbType.DateTime, "datetime", "datetime NOT NULL", false, false) },{ typeof(DateTime?).FullName, (SqlDbType.DateTime, "datetime", "datetime", false, true) }, + { typeof(DateTimeOffset).FullName, (SqlDbType.DateTimeOffset, "datetimeoffset", "datetimeoffset NOT NULL", false, false) },{ typeof(DateTimeOffset?).FullName, (SqlDbType.DateTimeOffset, "datetimeoffset", "datetimeoffset", false, true) }, - { "System.Byte[]", (SqlDbType.VarBinary, "varbinary", "varbinary(255)", false, null) }, - { "System.String", (SqlDbType.NVarChar, "nvarchar", "nvarchar(255)", false, null) }, + { typeof(byte[]).FullName, (SqlDbType.VarBinary, "varbinary", "varbinary(255)", false, null) }, + { typeof(string).FullName, (SqlDbType.NVarChar, "nvarchar", "nvarchar(255)", false, null) }, - { "System.Guid", (SqlDbType.UniqueIdentifier, "uniqueidentifier", "uniqueidentifier", false, false) },{ "System.Guid", (SqlDbType.UniqueIdentifier, "uniqueidentifier", "uniqueidentifier", false, true) }, + { typeof(Guid).FullName, (SqlDbType.UniqueIdentifier, "uniqueidentifier", "uniqueidentifier NOT NULL", false, false) },{ typeof(Guid?).FullName, (SqlDbType.UniqueIdentifier, "uniqueidentifier", "uniqueidentifier", false, true) }, }; public (int type, string dbtype, string dbtypeFull, bool? isnullable)? GetDbInfo(Type type) { + if (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new (int, string, string, bool?)?(((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable)); var enumType = type.IsEnum ? type : null; if (enumType == null && type.FullName.StartsWith("System.Nullable`1[") && type.GenericTypeArguments.Length == 1 && type.GenericTypeArguments.First().IsEnum) enumType = type.GenericTypeArguments.First(); if (enumType != null) { - return ((int)SqlDbType.Int, "int", "int", type.IsEnum ? false : true); + var newItem = enumType.GetCustomAttributes(typeof(FlagsAttribute), false).Any() ? + (SqlDbType.BigInt, "bigint", $"bigint{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true) : + (SqlDbType.Int, "int", $"int{(type.IsEnum ? " NOT NULL" : "")}", false, type.IsEnum ? false : true); + if (_dicCsToDb.ContainsKey(type.FullName) == false) { + lock (_dicCsToDbLock) { + if (_dicCsToDb.ContainsKey(type.FullName) == false) + _dicCsToDb.Add(type.FullName, newItem); + } + } + return ((int)newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5); } - return _dicCsToDb.TryGetValue(type.FullName, out var trydc) ? new (int, string, string, bool?)?(((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable)) : null; + return null; } public string GetComparisonDDLStatements() => this.GetComparisonDDLStatements(typeof(TEntity)); @@ -70,11 +81,11 @@ namespace FreeSql.SqlServer { var isRenameTable = false; var tbname = tb.DbName.Split(new[] { '.' }, 2); if (tbname.Length == 1) tbname = new[] { "dbo", tbname[0] }; - if (_orm.Ado.ExecuteScalar(CommandType.Text, "select 1 from dbo.sysobjects where id = object_id(N'[{0}].[{1}]') and OBJECTPROPERTY(id, N'IsUserTable')".FormatMySql(tbname)) == null) { //表不存在 + if (_orm.Ado.ExecuteScalar(CommandType.Text, string.Format("select 1 from dbo.sysobjects where id = object_id(N'[{0}].[{1}]') and OBJECTPROPERTY(id, N'IsUserTable') = 1", tbname)) == null) { //表不存在 - if (tboldname != null && _orm.Ado.ExecuteScalar(CommandType.Text, "select 1 from dbo.sysobjects where id = object_id(N'[{0}].[{1}]') and OBJECTPROPERTY(id, N'IsUserTable')".FormatMySql(tboldname)) != null) { //旧表存在 + if (tboldname != null && _orm.Ado.ExecuteScalar(CommandType.Text, string.Format("select 1 from dbo.sysobjects where id = object_id(N'[{0}].[{1}]') and OBJECTPROPERTY(id, N'IsUserTable') = 1", tboldname)) != null) { //旧表存在 //修改表名 - sb.Append(_commonUtils.FormatSql("EXEC sp_rename {0}, {1} GO \r\n", _commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}"), _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"))); + sb.Append(_commonUtils.FormatSql("EXEC sp_rename {0}, {1} \r\nGO \r\n", _commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}"), _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"))); isRenameTable = true; } else { @@ -87,7 +98,7 @@ namespace FreeSql.SqlServer { if (tbcol.Attribute.IsPrimary) sb.Append(" primary key"); sb.Append(","); } - sb.Remove(sb.Length - 1, 1).Append("\r\n) GO \r\n"); + sb.Remove(sb.Length - 1, 1).Append("\r\n) \r\nGO \r\n"); continue; } } @@ -96,7 +107,7 @@ namespace FreeSql.SqlServer { foreach (var tbcol in tb.Columns) addcols.Add(tbcol.Value.Attribute.Name, tbcol.Value); var surplus = new Dictionary(StringComparer.CurrentCultureIgnoreCase); var dbcols = new List(); - var sql = @"select + var sql = string.Format(@"select a.name 'Column' ,b.name + case when b.name in ('Char', 'VarChar', 'NChar', 'NVarChar', 'Binary', 'VarBinary') then '(' + @@ -105,14 +116,14 @@ a.name 'Column' else cast(a.max_length as varchar) end + ')' when b.name in ('Numeric', 'Decimal') then '(' + cast(a.precision as varchar) + ',' + cast(a.scale as varchar) + ')' else '' end as 'SqlType' -,a.is_nullable 'IsNullable' -,a.is_identity 'IsIdentity' +,case when a.is_nullable = 1 then '1' else '0' end 'IsNullable' +,case when a.is_identity = 1 then '1' else '0' end 'IsIdentity' from sys.columns a inner join sys.types b on b.user_type_id = a.user_type_id left join sys.extended_properties AS c ON c.major_id = a.object_id AND c.minor_id = a.column_id left join sys.tables d on d.object_id = a.object_id left join sys.schemas e on e.schema_id = d.schema_id -where a.object_id in (object_id(N'[{0}].[{1}]'))".FormatMySql(isRenameTable ? tboldname : tbname); +where a.object_id in (object_id(N'[{0}].[{1}]'))", isRenameTable ? tboldname : tbname); var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); foreach (var row in ds) { string column = string.Concat(row[0]); @@ -126,7 +137,7 @@ where a.object_id in (object_id(N'[{0}].[{1}]'))".FormatMySql(isRenameTable ? tb trycol.Attribute.IsIdentity != is_identity) { sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(column)).Append(" ").Append(trycol.Attribute.DbType.ToUpper()); if (trycol.Attribute.IsIdentity && trycol.Attribute.DbType.IndexOf("identity", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" identity(1,1)"); - sb.Append(" GO \r\n"); + sb.Append(" \r\nGO \r\n"); } addcols.Remove(column); } else @@ -134,15 +145,15 @@ where a.object_id in (object_id(N'[{0}].[{1}]'))".FormatMySql(isRenameTable ? tb } foreach (var addcol in addcols.Values) { if (string.IsNullOrEmpty(addcol.Attribute.OldName) == false && surplus.ContainsKey(addcol.Attribute.OldName)) { //修改列名 - sb.Append(_commonUtils.FormatSql("EXEC sp_rename {0}, {1}, 'COLUMN' GO \r\n", _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{addcol.Attribute.OldName}"), _commonUtils.QuoteSqlName(addcol.Attribute.Name))); + sb.Append(_commonUtils.FormatSql("EXEC sp_rename {0}, {1}, 'COLUMN' \r\nGO \r\n", $"{tbname[0]}.{tbname[1]}.{addcol.Attribute.OldName}", addcol.Attribute.Name)); sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(addcol.Attribute.Name)).Append(" ").Append(addcol.Attribute.DbType.ToUpper()); if (addcol.Attribute.IsIdentity && addcol.Attribute.DbType.IndexOf("identity", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" identity(1,1)"); - sb.Append(" GO \r\n"); + sb.Append(" \r\nGO \r\n"); } else { //添加列 sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD ").Append(_commonUtils.QuoteSqlName(addcol.Attribute.Name)).Append(" ").Append(addcol.Attribute.DbType.ToUpper()); if (addcol.Attribute.IsIdentity && addcol.Attribute.DbType.IndexOf("identity", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" identity(1,1)"); - sb.Append(" GO \r\n"); + sb.Append(" \r\nGO \r\n"); } } } diff --git a/FreeSql/SqlServer/SqlServerDbFirst.cs b/FreeSql/SqlServer/SqlServerDbFirst.cs index e57c2037..361d0761 100644 --- a/FreeSql/SqlServer/SqlServerDbFirst.cs +++ b/FreeSql/SqlServer/SqlServerDbFirst.cs @@ -374,6 +374,16 @@ where b.object_id in ({0}) if (ret == 0) ret = t1.Name.CompareTo(t2.Name); return ret; }); + foreach (var loc4 in loc1) { + var dicUniques = new Dictionary>(); + dicUniques.Add(string.Join(",", loc4.Primarys.Select(a => a.Name)), loc4.Primarys); + foreach (var loc5 in loc4.Uniques) { + var dickey = string.Join(",", loc5.Select(a => a.Name)); + if (dicUniques.ContainsKey(dickey)) continue; + dicUniques.Add(dickey, loc5); + } + loc4.Uniques = dicUniques.Values.ToList(); + } loc2.Clear(); loc3.Clear(); diff --git a/Templates/MySql/rich-entity-navigation-object/Models/for-table.cs.freesql b/Templates/MySql/rich-entity-navigation-object/Models/for-table.cs.freesql index e9be6c3a..a33178b3 100644 --- a/Templates/MySql/rich-entity-navigation-object/Models/for-table.cs.freesql +++ b/Templates/MySql/rich-entity-navigation-object/Models/for-table.cs.freesql @@ -231,7 +231,8 @@ namespace test.Model { var affrows = mysql.Update<{#UString(table.Name)}>().Where(a => {#parmsByWhereLambda}).ExecuteAffrows(); if (affrows > 0) return; }{/if} - {if pks.Count > 0}this.{#UString(idensCol.Name)} = {#GetCsType(idensCol).Replace("?", "") == "long" ? "" : ("(" + GetCsType(idensCol) + ")")}mysql.Insert<{#UString(table.Name)}>().AppendData(this).ExecuteIdentity();{else}mysql.Insert<{#UString(table.Name)}>().AppendData(this).ExecuteAffrows();{/if} + {if idens > 0}this.{#UString(idensCol.Name)} = {#GetCsType(idensCol).Replace("?", "") == "long" ? "" : ("(" + GetCsType(idensCol) + ")")}mysql.Insert<{#UString(table.Name)}>().AppendData(this).ExecuteIdentity();{else} + mysql.Insert<{#UString(table.Name)}>().AppendData(this).ExecuteAffrows();{/if} } {/if} } From 751b2405330e147300fdd4fbe192e1379c00465a Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Wed, 19 Dec 2018 12:06:54 +0800 Subject: [PATCH 2/6] =?UTF-8?q?SqlServer=20CodeFirst=20=E9=80=82=E9=85=8D?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FreeSql.Tests/g.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/FreeSql.Tests/g.cs b/FreeSql.Tests/g.cs index 9ca30775..1f7f39b0 100644 --- a/FreeSql.Tests/g.cs +++ b/FreeSql.Tests/g.cs @@ -6,8 +6,7 @@ using System.Text; public class g { public static IFreeSql mysql = new FreeSql.FreeSqlBuilder() - //.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10") - .UseConnectionString(FreeSql.DataType.MySql, "Data Source=123.207.16.102;Port=3306;User ID=root;Password=qwe369258/*-;Initial Catalog=ManagerDB;Charset=utf8;SslMode=none;Max pool size=10") + .UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10") .Build(); public static IFreeSql sqlserver = new FreeSql.FreeSqlBuilder() From d619d29cfa00bde9f019857505c091d2b97c249a Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Wed, 19 Dec 2018 15:17:44 +0800 Subject: [PATCH 3/6] =?UTF-8?q?sqlserver=20CodeFirst=20DbFirst=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E9=80=9A=E8=BF=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FreeSql.Tests/Class1.cs | 127 +----- .../Generator/MySqlTemplateGeneratorTest.cs | 2 +- .../SqlServerTemplateGeneratorTest.cs | 27 ++ .../SqlServer/SqlServerCodeFirstTest.cs | 164 +++++++- .../SqlServer/SqlServerDbFirstTest.cs | 21 + FreeSql/Generator/TemplateGenerator.cs | 1 + FreeSql/MySql/MySqlDbFirst.cs | 2 +- FreeSql/PostgreSQL/PostgreSQLDbFirst.cs | 2 +- FreeSql/SqlServer/SqlServerDbFirst.cs | 377 +++++++++--------- .../{Models => Model}/for-table.cs.freesql | 44 +- .../rich-entity-navigation-object/readme.md | 94 +++++ .../{Models => Model}/for-table.cs.freesql | 0 .../simple-entity-navigation-object/readme.md | 94 +++++ .../{Models => Model}/for-table.cs.freesql | 0 Templates/MySql/simple-entity/readme.md | 94 +++++ .../rich-entity-navigation-object/Const.cs | 5 + .../Model/for-table.cs.freesql | 240 +++++++++++ .../rich-entity-navigation-object/readme.md | 94 +++++ .../Model/for-table.cs.freesql | 59 +++ .../simple-entity-navigation-object/readme.md | 94 +++++ .../simple-entity/Model/for-table.cs.freesql | 33 ++ Templates/SqlServer/simple-entity/readme.md | 94 +++++ 22 files changed, 1336 insertions(+), 332 deletions(-) create mode 100644 FreeSql.Tests/Generator/SqlServerTemplateGeneratorTest.cs create mode 100644 FreeSql.Tests/SqlServer/SqlServerDbFirstTest.cs rename Templates/MySql/rich-entity-navigation-object/{Models => Model}/for-table.cs.freesql (85%) rename Templates/MySql/simple-entity-navigation-object/{Models => Model}/for-table.cs.freesql (100%) rename Templates/MySql/simple-entity/{Models => Model}/for-table.cs.freesql (100%) create mode 100644 Templates/SqlServer/rich-entity-navigation-object/Const.cs create mode 100644 Templates/SqlServer/rich-entity-navigation-object/Model/for-table.cs.freesql create mode 100644 Templates/SqlServer/rich-entity-navigation-object/readme.md create mode 100644 Templates/SqlServer/simple-entity-navigation-object/Model/for-table.cs.freesql create mode 100644 Templates/SqlServer/simple-entity-navigation-object/readme.md create mode 100644 Templates/SqlServer/simple-entity/Model/for-table.cs.freesql create mode 100644 Templates/SqlServer/simple-entity/readme.md diff --git a/FreeSql.Tests/Class1.cs b/FreeSql.Tests/Class1.cs index da9da817..5f282702 100644 --- a/FreeSql.Tests/Class1.cs +++ b/FreeSql.Tests/Class1.cs @@ -1,126 +1 @@ - -//using System; -//using System.Collections; -//using System.Collections.Generic; -//using System.Linq; -//using System.Text; -//using System.Text.RegularExpressions; -//using FreeSql; -//using FreeSql.DatabaseModel; - -////namespace TplDynamicCodeGenerate { -//public class TplDynamicCodeGenerate_view1 : FreeSql.Generator.TemplateEngin.ITemplateOutput { -// public FreeSql.Generator.TemplateEngin.TemplateReturnInfo OuTpUt(StringBuilder tOuTpUt, IDictionary oPtIoNs, string rEfErErFiLeNaMe, FreeSql.Generator.TemplateEngin tEmPlAtEsEnDeR) { -// FreeSql.Generator.TemplateEngin.TemplateReturnInfo rTn = tOuTpUt == null ? -// new FreeSql.Generator.TemplateEngin.TemplateReturnInfo { Sb = (tOuTpUt = new StringBuilder()), Blocks = new Dictionary() } : -// new FreeSql.Generator.TemplateEngin.TemplateReturnInfo { Sb = tOuTpUt, Blocks = new Dictionary() }; -// Dictionary TPL__blocks = rTn.Blocks; -// Stack TPL__blocks_stack = new Stack(); -// int[] TPL__blocks_stack_peek; -// List TPL__forc = new List(); -// Func pRoCeSsOpTiOnS = new Func(delegate () { -// IDictionary nEwoPtIoNs = new Hashtable(); -// foreach (DictionaryEntry oPtIoNs_dE in oPtIoNs) -// nEwoPtIoNs[oPtIoNs_dE.Key] = oPtIoNs_dE.Value; -// foreach (IDictionary TPL__forc_dIc in TPL__forc) -// foreach (DictionaryEntry TPL__forc_dIc_dE in TPL__forc_dIc) -// nEwoPtIoNs[TPL__forc_dIc_dE.Key] = TPL__forc_dIc_dE.Value; -// return nEwoPtIoNs; -// }); -// FreeSql.Generator.TemplateEngin.TemplateIf tPlIf = delegate (object exp) { -// if (exp is bool) return (bool)exp; -// if (exp == null) return false; -// if (exp is int && (int)exp == 0) return false; -// if (exp is string && (string)exp == string.Empty) return false; -// if (exp is long && (long)exp == 0) return false; -// if (exp is short && (short)exp == 0) return false; -// if (exp is byte && (byte)exp == 0) return false; -// if (exp is double && (double)exp == 0) return false; -// if (exp is float && (float)exp == 0) return false; -// if (exp is decimal && (decimal)exp == 0) return false; -// return true; -// }; -// FreeSql.Generator.TemplateEngin.TemplatePrint print = delegate (object[] pArMs) { -// if (pArMs == null || pArMs.Length == 0) return; -// foreach (object pArMs_A in pArMs) if (pArMs_A != null) tOuTpUt.Append(pArMs_A); -// }; -// FreeSql.Generator.TemplateEngin.TemplatePrint Print = prin -// dynamic index = oPtIoNs["index"]; -// dynamic col = oPtIoNs["col"]; -// dynamic table = oPtIoNs["table"]; -// dynamic dbfirst = oPtIoNs["dbfirst"]; t; -// tOuTpUt.Append("using System;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Reflection;\r\nusing System.Threading.Tasks;\r\nusing Newtonsoft.Json;\r\nusing FreeSql.DataAnnotations;\r\n"); - -// var dbf = dbfirst as FreeSql.IDbFirst; -// var cols = (table.Columns as List); - -// Func UString = stra => stra.Substring(0, 1).ToUpper() + stra.Substring(1); -// Func GetCsType = cola3 => { -// if (cola3.DbType == (int)MySql.Data.MySqlClient.MySqlDbType.Enum || cola3.DbType == (int)MySql.Data.MySqlClient.MySqlDbType.Set) { -// return $"{UString(cola3.Table.Name)}{cola3.Name.ToUpper()}{(cola3.IsNullable ? "?" : "")}"; -// } -// return dbf.GetCsType(cola3); -// }; - -// tOuTpUt.Append("\r\nnamespace test.Model {\r\n\r\n [JsonObject(MemberSerialization.OptIn), Table(Name = \""); -// Print(!string.IsNullOrEmpty(table.Schema) ? table.Schema + "." : ""); -// tOuTpUt.Append(""); -// Print(table.Name); -// tOuTpUt.Append("\""); -// if (tPlIf(cols.Where(cola003 => cola003.Name.ToLower() == "is_deleted" || cola003.Name.ToLower() == "isdeleted").Any())) { -// tOuTpUt.Append(", SelectFilter = \"a.IsDeleted = 1\""); -// } -// tOuTpUt.Append(")]\r\n public partial class "); -// Print(UString(table.Name)); -// tOuTpUt.Append(" {"); -// //new Action(delegate () { -// IDictionary TPL__tmp1 = new Hashtable(); -// TPL__forc.Add(TPL__tmp1); -// var TPL__tmp2 = table.Columns; -// var TPL__tmp3 = col; -// var TPL__tmp4 = index; -// index = 0; -// if (TPL__tmp2 != null) -// foreach (var TPL__tmp5 in TPL__tmp2) { -// TPL__tmp1["index"] = ++index; -// TPL__tmp1["col"] = TPL__tmp5; -// col = TPL__tmp5; -// tOuTpUt.Append("\r\n "); -// if (tPlIf(string.IsNullOrEmpty(col.Coment) == false)) { -// tOuTpUt.Append("/// \r\n /// "); -// Print(col.Coment.Replace("\r\n", "\n").Replace("\n", "\r\n /// ")); -// tOuTpUt.Append("\r\n /// "); -// } -// tOuTpUt.Append("\r\n [JsonProperty, Column(Name = \""); -// Print(col.Name); -// tOuTpUt.Append("\", DbType = \""); -// Print(col.DbTypeTextFull); -// tOuTpUt.Append("\""); -// if (tPlIf(col.IsPrimary == true)) { -// tOuTpUt.Append(", IsPrimary = true"); -// } -// tOuTpUt.Append(""); -// if (tPlIf(col.IsIdentity == true)) { -// tOuTpUt.Append(", IsIdentity = true"); -// } -// tOuTpUt.Append(""); -// if (tPlIf(col.IsNullable == true)) { -// tOuTpUt.Append(", IsNullable = true"); -// } -// tOuTpUt.Append(")]\r\n public "); -// Print(GetCsType(col)); -// tOuTpUt.Append(" "); -// Print(UString(col.Name)); -// tOuTpUt.Append(" { get; set; }\r\n "); -// } -// col = TPL__tmp3; -// index = TPL__tmp4; -// TPL__forc.RemoveAt(TPL__forc.Count - 1); -// //})(); -// tOuTpUt.Append("\r\n }\r\n"); -// tEmPlAtEsEnDeR.RenderFile2(tOuTpUt, pRoCeSsOpTiOnS(), "../../include/enumtype.tpl", rEfErErFiLeNaMe); -// tOuTpUt.Append("\r\n}"); -// return rTn; -// } -//} -////} + \ No newline at end of file diff --git a/FreeSql.Tests/Generator/MySqlTemplateGeneratorTest.cs b/FreeSql.Tests/Generator/MySqlTemplateGeneratorTest.cs index 51d97a35..ff0e085b 100644 --- a/FreeSql.Tests/Generator/MySqlTemplateGeneratorTest.cs +++ b/FreeSql.Tests/Generator/MySqlTemplateGeneratorTest.cs @@ -21,7 +21,7 @@ namespace FreeSql.Tests.Generator { [Fact] public void BuildRichEntityNavigationObject() { var gen = new TemplateGenerator(); - gen.Build(g.mysql.DbFirst, @"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\rich-entity-navigation-object", @"C:\Users\28810\Desktop\新建文件夹 (9)", "ManagerDB"); + gen.Build(g.mysql.DbFirst, @"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\rich-entity-navigation-object", @"C:\Users\28810\Desktop\新建文件夹 (9)", "cccddd"); } } } diff --git a/FreeSql.Tests/Generator/SqlServerTemplateGeneratorTest.cs b/FreeSql.Tests/Generator/SqlServerTemplateGeneratorTest.cs new file mode 100644 index 00000000..759fbb1f --- /dev/null +++ b/FreeSql.Tests/Generator/SqlServerTemplateGeneratorTest.cs @@ -0,0 +1,27 @@ +using FreeSql.DataAnnotations; +using FreeSql.Generator; +using System; +using Xunit; + +namespace FreeSql.Tests.Generator { + public class SqlServerTemplateGeneratorTest { + + [Fact] + public void BuildSimpleEntity() { + var gen = new TemplateGenerator(); + gen.Build(g.sqlserver.DbFirst, @"C:\Users\28810\Desktop\github\FreeSql\Templates\SqlServer\simple-entity", @"C:\Users\28810\Desktop\新建文件夹 (9)", "shop"); + } + + [Fact] + public void BuildSimpleEntityNavigationObject () { + var gen = new TemplateGenerator(); + gen.Build(g.sqlserver.DbFirst, @"C:\Users\28810\Desktop\github\FreeSql\Templates\SqlServer\simple-entity-navigation-object", @"C:\Users\28810\Desktop\新建文件夹 (9)", "shop"); + } + + [Fact] + public void BuildRichEntityNavigationObject() { + var gen = new TemplateGenerator(); + gen.Build(g.sqlserver.DbFirst, @"C:\Users\28810\Desktop\github\FreeSql\Templates\SqlServer\rich-entity-navigation-object", @"C:\Users\28810\Desktop\新建文件夹 (9)", "shop"); + } + } +} diff --git a/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs b/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs index 96785091..ec50497a 100644 --- a/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs +++ b/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs @@ -11,17 +11,175 @@ namespace FreeSql.Tests.SqlServer { public void GetComparisonDDLStatements() { var sql = g.sqlserver.CodeFirst.GetComparisonDDLStatements(); - + sql = g.sqlserver.CodeFirst.GetComparisonDDLStatements(); } + [JsonObject(MemberSerialization.OptIn), Table(Name = "dbo.tb_alltype")] + public partial class Tb_alltype { - [Table(Name = "tb_alltype")] + [JsonProperty, Column(Name = "Id", DbType = "int", IsPrimary = true, IsIdentity = true)] + public int Id { get; set; } + + + [JsonProperty, Column(Name = "testFieldBool1111", DbType = "bit")] + public bool TestFieldBool1111 { get; set; } + + + [JsonProperty, Column(Name = "testFieldBoolNullable", DbType = "bit", IsNullable = true)] + public bool? TestFieldBoolNullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldByte", DbType = "tinyint")] + public sbyte TestFieldByte { get; set; } + + + [JsonProperty, Column(Name = "testFieldByteNullable", DbType = "tinyint", IsNullable = true)] + public sbyte? TestFieldByteNullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldBytes", DbType = "varbinary(255)", IsNullable = true)] + public byte[] TestFieldBytes { get; set; } + + + [JsonProperty, Column(Name = "testFieldDateTime", DbType = "datetime")] + public DateTime TestFieldDateTime { get; set; } + + + [JsonProperty, Column(Name = "testFieldDateTimeNullable", DbType = "datetime", IsNullable = true)] + public DateTime? TestFieldDateTimeNullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldDateTimeNullableOffset", DbType = "datetimeoffset", IsNullable = true)] + public DateTime? TestFieldDateTimeNullableOffset { get; set; } + + + [JsonProperty, Column(Name = "testFieldDateTimeOffset", DbType = "datetimeoffset")] + public DateTime TestFieldDateTimeOffset { get; set; } + + + [JsonProperty, Column(Name = "testFieldDecimal", DbType = "decimal(10,2)")] + public decimal TestFieldDecimal { get; set; } + + + [JsonProperty, Column(Name = "testFieldDecimalNullable", DbType = "decimal(10,2)", IsNullable = true)] + public decimal? TestFieldDecimalNullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldDouble", DbType = "float")] + public double TestFieldDouble { get; set; } + + + [JsonProperty, Column(Name = "testFieldDoubleNullable", DbType = "float", IsNullable = true)] + public double? TestFieldDoubleNullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldEnum1", DbType = "int")] + public int TestFieldEnum1 { get; set; } + + + [JsonProperty, Column(Name = "testFieldEnum1Nullable", DbType = "int", IsNullable = true)] + public int? TestFieldEnum1Nullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldEnum2", DbType = "bigint")] + public long TestFieldEnum2 { get; set; } + + + [JsonProperty, Column(Name = "testFieldEnum2Nullable", DbType = "bigint", IsNullable = true)] + public long? TestFieldEnum2Nullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldFloat", DbType = "real")] + public float TestFieldFloat { get; set; } + + + [JsonProperty, Column(Name = "testFieldFloatNullable", DbType = "real", IsNullable = true)] + public float? TestFieldFloatNullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldGuid", DbType = "uniqueidentifier")] + public Guid TestFieldGuid { get; set; } + + + [JsonProperty, Column(Name = "testFieldGuidNullable", DbType = "uniqueidentifier", IsNullable = true)] + public Guid? TestFieldGuidNullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldInt", DbType = "int")] + public int TestFieldInt { get; set; } + + + [JsonProperty, Column(Name = "testFieldIntNullable", DbType = "int", IsNullable = true)] + public int? TestFieldIntNullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldLong", DbType = "bigint")] + public long TestFieldLong { get; set; } + + + [JsonProperty, Column(Name = "testFieldSByte", DbType = "tinyint")] + public sbyte TestFieldSByte { get; set; } + + + [JsonProperty, Column(Name = "testFieldSByteNullable", DbType = "tinyint", IsNullable = true)] + public sbyte? TestFieldSByteNullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldShort", DbType = "smallint")] + public short TestFieldShort { get; set; } + + + [JsonProperty, Column(Name = "testFieldShortNullable", DbType = "smallint", IsNullable = true)] + public short? TestFieldShortNullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldString", DbType = "nvarchar(255)", IsNullable = true)] + public string TestFieldString { get; set; } + + + [JsonProperty, Column(Name = "testFieldTimeSpan", DbType = "time")] + public TimeSpan TestFieldTimeSpan { get; set; } + + + [JsonProperty, Column(Name = "testFieldTimeSpanNullable", DbType = "time", IsNullable = true)] + public TimeSpan? TestFieldTimeSpanNullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldUInt", DbType = "int")] + public int TestFieldUInt { get; set; } + + + [JsonProperty, Column(Name = "testFieldUIntNullable", DbType = "int", IsNullable = true)] + public int? TestFieldUIntNullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldULong", DbType = "bigint")] + public long TestFieldULong { get; set; } + + + [JsonProperty, Column(Name = "testFieldULongNullable", DbType = "bigint", IsNullable = true)] + public long? TestFieldULongNullable { get; set; } + + + [JsonProperty, Column(Name = "testFieldUShort", DbType = "smallint")] + public short TestFieldUShort { get; set; } + + + [JsonProperty, Column(Name = "testFieldUShortNullable", DbType = "smallint", IsNullable = true)] + public short? TestFieldUShortNullable { get; set; } + + + [JsonProperty, Column(Name = "testFielLongNullable", DbType = "bigint", IsNullable = true)] + public long? TestFielLongNullable { get; set; } + } + + [Table(Name = "tb_alltype")] class TableAllType { [Column(IsIdentity = true, IsPrimary = true)] public int Id { get; set; } - [Column(OldName = "testFieldBool1111")] + [Column(Name = "testFieldBool1111")] public bool testFieldBool { get; set; } public sbyte testFieldSByte { get; set; } public short testFieldShort { get; set; } diff --git a/FreeSql.Tests/SqlServer/SqlServerDbFirstTest.cs b/FreeSql.Tests/SqlServer/SqlServerDbFirstTest.cs new file mode 100644 index 00000000..3887afe7 --- /dev/null +++ b/FreeSql.Tests/SqlServer/SqlServerDbFirstTest.cs @@ -0,0 +1,21 @@ +using FreeSql.DataAnnotations; +using System; +using Xunit; + +namespace FreeSql.Tests.SqlServer { + public class SqlServerDbFirstTest { + [Fact] + public void GetDatabases() { + + var t1 = g.sqlserver.DbFirst.GetDatabases(); + + } + + [Fact] + public void GetTablesByDatabase() { + + var t2 = g.sqlserver.DbFirst.GetTablesByDatabase(g.sqlserver.DbFirst.GetDatabases()[0]); + + } + } +} diff --git a/FreeSql/Generator/TemplateGenerator.cs b/FreeSql/Generator/TemplateGenerator.cs index 4b0281f3..d97c255e 100644 --- a/FreeSql/Generator/TemplateGenerator.cs +++ b/FreeSql/Generator/TemplateGenerator.cs @@ -34,6 +34,7 @@ namespace FreeSql.Generator { if (fi.Name.StartsWith("for-table.")) { foreach (var table in tables) { var result = tpl.RenderFile(file, new Dictionary() { { "table", table }, { "dbfirst", dbfirst } }); + if (result.EndsWith("return;")) continue; var outputName = table.Name + outputExtension; var mcls = Regex.Match(result, @"\s+class\s+(\w+)"); if (mcls.Success) outputName = mcls.Groups[1].Value + outputExtension; diff --git a/FreeSql/MySql/MySqlDbFirst.cs b/FreeSql/MySql/MySqlDbFirst.cs index af4e4db1..455e27ae 100644 --- a/FreeSql/MySql/MySqlDbFirst.cs +++ b/FreeSql/MySql/MySqlDbFirst.cs @@ -360,7 +360,7 @@ where a.constraint_schema in ({1}) and a.table_name in ({0}) and not isnull(posi }); foreach(var loc4 in loc1) { var dicUniques = new Dictionary>(); - dicUniques.Add(string.Join(",", loc4.Primarys.Select(a => a.Name)), loc4.Primarys); + if (loc4.Primarys.Count > 0) dicUniques.Add(string.Join(",", loc4.Primarys.Select(a => a.Name)), loc4.Primarys); foreach(var loc5 in loc4.Uniques) { var dickey = string.Join(",", loc5.Select(a => a.Name)); if (dicUniques.ContainsKey(dickey)) continue; diff --git a/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs b/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs index bbff5851..4325abf3 100644 --- a/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs +++ b/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs @@ -359,7 +359,7 @@ where a.constraint_schema in ({1}) and a.table_name in ({0}) and not isnull(posi }); foreach (var loc4 in loc1) { var dicUniques = new Dictionary>(); - dicUniques.Add(string.Join(",", loc4.Primarys.Select(a => a.Name)), loc4.Primarys); + if (loc4.Primarys.Count > 0) dicUniques.Add(string.Join(",", loc4.Primarys.Select(a => a.Name)), loc4.Primarys); foreach (var loc5 in loc4.Uniques) { var dickey = string.Join(",", loc5.Select(a => a.Name)); if (dicUniques.ContainsKey(dickey)) continue; diff --git a/FreeSql/SqlServer/SqlServerDbFirst.cs b/FreeSql/SqlServer/SqlServerDbFirst.cs index 361d0761..02036f2f 100644 --- a/FreeSql/SqlServer/SqlServerDbFirst.cs +++ b/FreeSql/SqlServer/SqlServerDbFirst.cs @@ -60,7 +60,6 @@ namespace FreeSql.SqlServer { { (int)SqlDbType.Int, ("(int?)", "int.Parse({0})", "{0}.ToString()", "int?", typeof(int), typeof(int?), "{0}.Value", "GetInt32") }, { (int)SqlDbType.BigInt, ("(long?)", "long.Parse({0})", "{0}.ToString()", "long?", typeof(long), typeof(long?), "{0}.Value", "GetInt64") }, - { (int)SqlDbType.Decimal, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") }, { (int)SqlDbType.SmallMoney, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") }, { (int)SqlDbType.Money, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") }, { (int)SqlDbType.Decimal, ("(decimal?)", "decimal.Parse({0})", "{0}.ToString()", "decimal?", typeof(decimal), typeof(decimal?), "{0}.Value", "GetDecimal") }, @@ -86,7 +85,7 @@ namespace FreeSql.SqlServer { { (int)SqlDbType.NVarChar, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, { (int)SqlDbType.NText, ("", "{0}.Replace(StringifySplit, \"|\")", "{0}.Replace(\"|\", StringifySplit)", "string", typeof(string), typeof(string), "{0}", "GetString") }, - { (int)SqlDbType.UniqueIdentifier, ("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "MygisGeometry", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") }, + { (int)SqlDbType.UniqueIdentifier, ("(Guid?)", "Guid.Parse({0})", "{0}.ToString()", "Guid?", typeof(Guid), typeof(Guid?), "{0}.Value", "GetGuid") }, }; public string GetCsConvert(DbColumnInfo column) => _dicDbToCs.TryGetValue(column.DbType, out var trydc) ? (column.IsNullable ? trydc.csConvert : trydc.csConvert.Replace("?", "")) : null; @@ -104,11 +103,22 @@ namespace FreeSql.SqlServer { } public List GetTablesByDatabase(params string[] database) { - List loc1 = null; - Dictionary loc2 = new Dictionary(); - Dictionary> loc3 = new Dictionary>(); + var olddatabase = ""; + using (var conn = _orm.Ado.MasterPool.Get(TimeSpan.FromSeconds(5))) { + olddatabase = conn.Value.Database; + } + var dbs = database?.ToArray() ?? new[] { olddatabase }; + var tables = new List(); - var sql = @" + foreach (var db in dbs) { + if (string.IsNullOrEmpty(db)) continue; + + var loc1 = new List(); + var loc2 = new Dictionary(); + var loc3 = new Dictionary>(); + + var sql = $@" +use {db}; select a.Object_id ,b.name 'Owner' @@ -135,34 +145,37 @@ from sys.procedures a inner join sys.schemas b on b.schema_id = a.schema_id where a.type = 'P' and charindex('$NPSP', a.name) = 0 and charindex('diagram', a.name) = 0 order by type desc, b.name, a.name +; +use {olddatabase}; "; - var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); - if (ds == null) return loc1; + var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; - var loc6 = new List(); - var loc66 = new List(); - foreach (object[] row in ds) { - int object_id = int.Parse(string.Concat(row[0])); - var owner = string.Concat(row[1]); - var table = string.Concat(row[2]); - Enum.TryParse(string.Concat(row[3]), out var type); - loc2.Add(object_id, new DbTableInfo { Id = object_id.ToString(), Schema = owner, Name = table, Type = type }); - loc3.Add(object_id, new Dictionary()); - switch (type) { - case DbTableType.VIEW: - case DbTableType.TABLE: - loc6.Add(object_id); - break; - case DbTableType.StoreProcedure: - loc66.Add(object_id); - break; + var loc6 = new List(); + var loc66 = new List(); + foreach (object[] row in ds) { + int object_id = int.Parse(string.Concat(row[0])); + var owner = string.Concat(row[1]); + var table = string.Concat(row[2]); + Enum.TryParse(string.Concat(row[3]), out var type); + loc2.Add(object_id, new DbTableInfo { Id = object_id.ToString(), Schema = owner, Name = table, Type = type }); + loc3.Add(object_id, new Dictionary()); + switch (type) { + case DbTableType.VIEW: + case DbTableType.TABLE: + loc6.Add(object_id); + break; + case DbTableType.StoreProcedure: + loc66.Add(object_id); + break; + } } - } - if (loc6.Count == 0) return loc1; - var loc8 = string.Join(",", loc6.Select(a => string.Concat(a))); - var loc88 = string.Join(",", loc66.Select(a => string.Concat(a))); + if (loc6.Count == 0) return loc1; + var loc8 = string.Join(",", loc6.Select(a => string.Concat(a))); + var loc88 = string.Join(",", loc66.Select(a => string.Concat(a))); + + var tsql_place = @" - var tsql_place = @" select isnull(e.name,'') + '.' + isnull(d.name,'') ,a.Object_id @@ -187,50 +200,52 @@ left join sys.tables d on d.object_id = a.object_id left join sys.schemas e on e.schema_id = d.schema_id where a.object_id in ({1}) "; - sql = string.Format(tsql_place, @" + sql = string.Format(tsql_place, @" ,a.is_nullable 'IsNullable' ,a.is_identity 'IsIdentity' from sys.columns", loc8); - if (loc88.Length > 0) { - sql += "union all" + - string.Format(tsql_place.Replace( - "left join sys.extended_properties AS c ON c.major_id = a.object_id AND c.minor_id = a.column_id", - "left join sys.extended_properties AS c ON c.major_id = a.object_id AND c.minor_id = a.parameter_id"), @" + if (loc88.Length > 0) { + sql += "union all" + + string.Format(tsql_place.Replace( + "left join sys.extended_properties AS c ON c.major_id = a.object_id AND c.minor_id = a.column_id", + "left join sys.extended_properties AS c ON c.major_id = a.object_id AND c.minor_id = a.parameter_id"), @" ,cast(0 as bit) 'IsNullable' ,a.is_output 'IsIdentity' from sys.parameters", loc88); - } - ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); - if (ds == null) return loc1; + } + sql = $"use {db};{sql};use {olddatabase}; "; + ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; - foreach (object[] row in ds) { - var table_id = string.Concat(row[0]); - var object_id = int.Parse(string.Concat(row[1])); - var column = string.Concat(row[2]); - var type = string.Concat(row[3]); - var max_length = int.Parse(string.Concat(row[4])); - var sqlType = string.Concat(row[5]); - var comment = string.Concat(row[6]); - var is_nullable = bool.Parse(string.Concat(row[7])); - var is_identity = bool.Parse(string.Concat(row[8])); - if (max_length == 0) max_length = -1; + foreach (object[] row in ds) { + var table_id = string.Concat(row[0]); + var object_id = int.Parse(string.Concat(row[1])); + var column = string.Concat(row[2]); + var type = string.Concat(row[3]); + var max_length = int.Parse(string.Concat(row[4])); + var sqlType = string.Concat(row[5]); + var comment = string.Concat(row[6]); + var is_nullable = bool.Parse(string.Concat(row[7])); + var is_identity = bool.Parse(string.Concat(row[8])); + if (max_length == 0) max_length = -1; - loc3[object_id].Add(column, new DbColumnInfo { - Name = column, - MaxLength = max_length, - IsIdentity = is_identity, - IsNullable = is_nullable, - IsPrimary = false, - DbTypeText = type, - DbTypeTextFull = sqlType, - Table = loc2[object_id], - Coment = comment - }); - loc3[object_id][column].DbType = this.GetDbType(loc3[object_id][column]); - loc3[object_id][column].CsType = this.GetCsTypeInfo(loc3[object_id][column]); - } + loc3[object_id].Add(column, new DbColumnInfo { + Name = column, + MaxLength = max_length, + IsIdentity = is_identity, + IsNullable = is_nullable, + IsPrimary = false, + DbTypeText = type, + DbTypeTextFull = sqlType, + Table = loc2[object_id], + Coment = comment + }); + loc3[object_id][column].DbType = this.GetDbType(loc3[object_id][column]); + loc3[object_id][column].CsType = this.GetCsTypeInfo(loc3[object_id][column]); + } - sql = string.Format(@" + sql = $@" +use {db}; select a.object_id 'Object_id' ,c.name 'Column' @@ -242,53 +257,55 @@ select from sys.index_columns a inner join sys.indexes b on b.object_id = a.object_id and b.index_id = a.index_id left join sys.columns c on c.object_id = a.object_id and c.column_id = a.column_id -where a.object_id in ({0}) -", loc8); - ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); - if (ds == null) return loc1; +where a.object_id in ({loc8}) +; +use {olddatabase}; +"; + ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; - var indexColumns = new Dictionary>>(); - var uniqueColumns = new Dictionary>>(); - foreach (object[] row in ds) { - int object_id = int.Parse(string.Concat(row[0])); - string column = string.Concat(row[1]); - int index_id = int.Parse(string.Concat(row[2])); - bool is_unique = bool.Parse(string.Concat(row[3])); - bool is_primary_key = bool.Parse(string.Concat(row[4])); - bool is_clustered = bool.Parse(string.Concat(row[5])); - int is_desc = int.Parse(string.Concat(row[6])); + var indexColumns = new Dictionary>>(); + var uniqueColumns = new Dictionary>>(); + foreach (object[] row in ds) { + int object_id = int.Parse(string.Concat(row[0])); + string column = string.Concat(row[1]); + int index_id = int.Parse(string.Concat(row[2])); + bool is_unique = bool.Parse(string.Concat(row[3])); + bool is_primary_key = bool.Parse(string.Concat(row[4])); + bool is_clustered = bool.Parse(string.Concat(row[5])); + int is_desc = int.Parse(string.Concat(row[6])); - if (loc3.ContainsKey(object_id) == false || loc3[object_id].ContainsKey(column) == false) continue; - DbColumnInfo loc9 = loc3[object_id][column]; - if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key; + if (loc3.ContainsKey(object_id) == false || loc3[object_id].ContainsKey(column) == false) continue; + DbColumnInfo loc9 = loc3[object_id][column]; + if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key; - Dictionary> loc10 = null; - List loc11 = null; - if (!indexColumns.TryGetValue(object_id, out loc10)) - indexColumns.Add(object_id, loc10 = new Dictionary>()); - if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); - if (is_unique) { - if (!uniqueColumns.TryGetValue(object_id, out loc10)) - uniqueColumns.Add(object_id, loc10 = new Dictionary>()); + Dictionary> loc10 = null; + List loc11 = null; + if (!indexColumns.TryGetValue(object_id, out loc10)) + indexColumns.Add(object_id, loc10 = new Dictionary>()); if (!loc10.TryGetValue(index_id, out loc11)) loc10.Add(index_id, loc11 = new List()); loc11.Add(loc9); + if (is_unique) { + if (!uniqueColumns.TryGetValue(object_id, out loc10)) + uniqueColumns.Add(object_id, loc10 = new Dictionary>()); + if (!loc10.TryGetValue(index_id, out loc11)) + loc10.Add(index_id, loc11 = new List()); + loc11.Add(loc9); + } } - } - foreach (var object_id in indexColumns.Keys) { - foreach (List columns in indexColumns[object_id].Values) - loc2[object_id].Indexes.Add(columns); - } - foreach (var object_id in uniqueColumns.Keys) { - foreach (var columns in uniqueColumns[object_id].Values) { - columns.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); - loc2[object_id].Uniques.Add(columns); + foreach (var object_id in indexColumns.Keys) { + foreach (List columns in indexColumns[object_id].Values) + loc2[object_id].Indexes.Add(columns); + } + foreach (var object_id in uniqueColumns.Keys) { + foreach (var columns in uniqueColumns[object_id].Values) { + columns.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); + loc2[object_id].Uniques.Add(columns); + } } - } - sql = string.Format(@" + sql = $@" select b.object_id 'Object_id' ,c.name 'Column' @@ -302,92 +319,96 @@ from sys.foreign_key_columns a inner join sys.tables b on b.object_id = a.parent_object_id inner join sys.columns c on c.object_id = a.parent_object_id and c.column_id = a.parent_column_id inner join sys.columns d on d.object_id = a.referenced_object_id and d.column_id = a.referenced_column_id -where b.object_id in ({0}) -", loc8); - ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); - if (ds == null) return loc1; +where b.object_id in ({loc8}) +; +use {olddatabase}; +"; + ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); + if (ds == null) return loc1; - var fkColumns = new Dictionary>(); - foreach (object[] row in ds) { - int object_id, fk_id, referenced_object_id; - int.TryParse(string.Concat(row[0]), out object_id); - var column = string.Concat(row[1]); - int.TryParse(string.Concat(row[2]), out fk_id); - int.TryParse(string.Concat(row[3]), out referenced_object_id); - var is_foreign_key = bool.Parse(string.Concat(row[4])); - var referenced_column = string.Concat(row[5]); - var referenced_db = string.Concat(row[6]); - var referenced_table = string.Concat(row[7]); - DbColumnInfo loc9 = loc3[object_id][column]; - DbTableInfo loc10 = null; - DbColumnInfo loc11 = null; - bool isThisSln = referenced_object_id != 0; + var fkColumns = new Dictionary>(); + foreach (object[] row in ds) { + int object_id, fk_id, referenced_object_id; + int.TryParse(string.Concat(row[0]), out object_id); + var column = string.Concat(row[1]); + int.TryParse(string.Concat(row[2]), out fk_id); + int.TryParse(string.Concat(row[3]), out referenced_object_id); + var is_foreign_key = bool.Parse(string.Concat(row[4])); + var referenced_column = string.Concat(row[5]); + var referenced_db = string.Concat(row[6]); + var referenced_table = string.Concat(row[7]); + DbColumnInfo loc9 = loc3[object_id][column]; + DbTableInfo loc10 = null; + DbColumnInfo loc11 = null; + bool isThisSln = referenced_object_id != 0; - if (isThisSln) { - loc10 = loc2[referenced_object_id]; - loc11 = loc3[referenced_object_id][referenced_column]; - } else { + if (isThisSln) { + loc10 = loc2[referenced_object_id]; + loc11 = loc3[referenced_object_id][referenced_column]; + } else { + } + Dictionary loc12 = null; + DbForeignInfo loc13 = null; + if (!fkColumns.TryGetValue(object_id, out loc12)) + fkColumns.Add(object_id, loc12 = new Dictionary()); + if (!loc12.TryGetValue(fk_id, out loc13)) + loc12.Add(fk_id, loc13 = new DbForeignInfo { Table = loc2[object_id], ReferencedTable = loc10 }); + loc13.Columns.Add(loc9); + loc13.ReferencedColumns.Add(loc11); } - Dictionary loc12 = null; - DbForeignInfo loc13 = null; - if (!fkColumns.TryGetValue(object_id, out loc12)) - fkColumns.Add(object_id, loc12 = new Dictionary()); - if (!loc12.TryGetValue(fk_id, out loc13)) - loc12.Add(fk_id, new DbForeignInfo { Table = loc2[object_id], ReferencedTable = loc10 }); - loc13.Columns.Add(loc9); - loc13.ReferencedColumns.Add(loc11); - } - foreach (var table_id in fkColumns.Keys) - foreach (var fk in fkColumns[table_id].Values) - loc2[table_id].Foreigns.Add(fk); + foreach (var table_id in fkColumns.Keys) + foreach (var fk in fkColumns[table_id].Values) + loc2[table_id].Foreigns.Add(fk); - foreach (var table_id in loc3.Keys) { - foreach (var loc5 in loc3[table_id].Values) { - loc2[table_id].Columns.Add(loc5); - if (loc5.IsIdentity) loc2[table_id].Identitys.Add(loc5); - if (loc5.IsPrimary) loc2[table_id].Primarys.Add(loc5); - } - } - foreach (var loc4 in loc2.Values) { - if (loc4.Primarys.Count == 0 && loc4.Uniques.Count > 0) { - foreach (var loc5 in loc4.Uniques[0]) { - loc5.IsPrimary = true; - loc4.Primarys.Add(loc5); + foreach (var table_id in loc3.Keys) { + foreach (var loc5 in loc3[table_id].Values) { + loc2[table_id].Columns.Add(loc5); + if (loc5.IsIdentity) loc2[table_id].Identitys.Add(loc5); + if (loc5.IsPrimary) loc2[table_id].Primarys.Add(loc5); } } - loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); - loc4.Columns.Sort((c1, c2) => { - int compare = c2.IsPrimary.CompareTo(c1.IsPrimary); - if (compare == 0) { - bool b1 = loc4.Foreigns.Find(fk => fk.Columns.Find(c3 => c3.Name == c1.Name) != null) != null; - bool b2 = loc4.Foreigns.Find(fk => fk.Columns.Find(c3 => c3.Name == c2.Name) != null) != null; - compare = b2.CompareTo(b1); + foreach (var loc4 in loc2.Values) { + if (loc4.Primarys.Count == 0 && loc4.Uniques.Count > 0) { + foreach (var loc5 in loc4.Uniques[0]) { + loc5.IsPrimary = true; + loc4.Primarys.Add(loc5); + } } - if (compare == 0) compare = c1.Name.CompareTo(c2.Name); - return compare; + loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); + loc4.Columns.Sort((c1, c2) => { + int compare = c2.IsPrimary.CompareTo(c1.IsPrimary); + if (compare == 0) { + bool b1 = loc4.Foreigns.Find(fk => fk.Columns.Find(c3 => c3.Name == c1.Name) != null) != null; + bool b2 = loc4.Foreigns.Find(fk => fk.Columns.Find(c3 => c3.Name == c2.Name) != null) != null; + compare = b2.CompareTo(b1); + } + if (compare == 0) compare = c1.Name.CompareTo(c2.Name); + return compare; + }); + loc1.Add(loc4); + } + loc1.Sort((t1, t2) => { + var ret = t1.Schema.CompareTo(t2.Schema); + if (ret == 0) ret = t1.Name.CompareTo(t2.Name); + return ret; }); - loc1.Add(loc4); - } - loc1.Sort((t1, t2) => { - var ret = t1.Schema.CompareTo(t2.Schema); - if (ret == 0) ret = t1.Name.CompareTo(t2.Name); - return ret; - }); - foreach (var loc4 in loc1) { - var dicUniques = new Dictionary>(); - dicUniques.Add(string.Join(",", loc4.Primarys.Select(a => a.Name)), loc4.Primarys); - foreach (var loc5 in loc4.Uniques) { - var dickey = string.Join(",", loc5.Select(a => a.Name)); - if (dicUniques.ContainsKey(dickey)) continue; - dicUniques.Add(dickey, loc5); + foreach (var loc4 in loc1) { + var dicUniques = new Dictionary>(); + if (loc4.Primarys.Count > 0) dicUniques.Add(string.Join(",", loc4.Primarys.Select(a => a.Name)), loc4.Primarys); + foreach (var loc5 in loc4.Uniques) { + var dickey = string.Join(",", loc5.Select(a => a.Name)); + if (dicUniques.ContainsKey(dickey)) continue; + dicUniques.Add(dickey, loc5); + } + loc4.Uniques = dicUniques.Values.ToList(); } - loc4.Uniques = dicUniques.Values.ToList(); - } - loc2.Clear(); - loc3.Clear(); - return loc1; + loc2.Clear(); + loc3.Clear(); + tables.AddRange(loc1); + } + return tables; } } } \ No newline at end of file diff --git a/Templates/MySql/rich-entity-navigation-object/Models/for-table.cs.freesql b/Templates/MySql/rich-entity-navigation-object/Model/for-table.cs.freesql similarity index 85% rename from Templates/MySql/rich-entity-navigation-object/Models/for-table.cs.freesql rename to Templates/MySql/rich-entity-navigation-object/Model/for-table.cs.freesql index a33178b3..41b88c1f 100644 --- a/Templates/MySql/rich-entity-navigation-object/Models/for-table.cs.freesql +++ b/Templates/MySql/rich-entity-navigation-object/Model/for-table.cs.freesql @@ -57,8 +57,8 @@ namespace test.Model { {/if}{/for}{for fk in fks} public {#UString(fk.ReferencedTable.Name)} {#GetFkObjectName(fk)} { get; set; } {/for} - internal static IFreeSql mysql => Const.mysql; - public static ISelect<{#UString(table.Name)}> Select => mysql.Select<{#UString(table.Name)}>(); + internal static IFreeSql freesql => Const.mysql; + public static ISelect<{#UString(table.Name)}> Select => freesql.Select<{#UString(table.Name)}>(); {if (table.Uniques.Count > 0)} public static int ItemCacheTimeout = 180;{for uk001 in table.Uniques}{% @@ -79,7 +79,7 @@ namespace test.Model { parmsNodeTypeUpdateCacheRemove = parmsNodeTypeUpdateCacheRemove.Substring(0, parmsNodeTypeUpdateCacheRemove.Length - 9); %} public static {#UString(table.Name)} GetItem{#uk001[0].IsPrimary ? string.Empty : parmsBy}({#parms}) => Select.Where(a => {#parmsByWhereLambda}).Caching(ItemCacheTimeout, string.Concat("test:{#table.Name}{#uk001[0].IsPrimary ? string.Empty : parmsBy}:", {#parmsNodeTypeUpdateCacheRemove.Replace("item.", "")})).ToOne();{/for} -{/if}{if (table.Uniques.Count > 0)}{for uk001 in table.Uniques}{% +{for uk001 in table.Uniques}{% string parms = string.Empty; string parmsByWhereLambda = string.Empty; @@ -101,12 +101,12 @@ namespace test.Model { parmsNoneType = parmsNoneType.Substring(0, parmsNoneType.Length - 2); %} public static long Delete{#uk001[0].IsPrimary ? string.Empty : parmsBy}({#parms}) { - var affrows = mysql.Delete<{#UString(table.Name)}>().Where(a => {#parmsByWhereLambda}).ExecuteAffrows();{if table.Uniques.Count > 1} + var affrows = freesql.Delete<{#UString(table.Name)}>().Where(a => {#parmsByWhereLambda}).ExecuteAffrows();{if table.Uniques.Count > 1} if (ItemCacheTimeout > 0) RemoveCache(GetItem{#uk001[0].IsPrimary ? string.Empty : parmsBy}({#parmsNoneType}));{else} if (ItemCacheTimeout > 0) RemoveCache(new {#UString(table.Name)} { {#parmsNewItem} });{/if} return affrows; }{/for} -{/if}{for fkcoldel in fks}{% +{for fkcoldel in fks}{% string parms = string.Empty; string parmsBy = "By"; string parmsByWhereLambda = string.Empty; @@ -121,9 +121,9 @@ namespace test.Model { parmsByWhereLambda = parmsByWhereLambda.Substring(0, parmsByWhereLambda.Length - 4); %} public static long DeleteBy{#parmsBy}({#parms}) { - return mysql.Delete<{#UString(table.Name)}>().Where(a => {#parmsByWhereLambda}).ExecuteAffrows(); //删除缓存 + return freesql.Delete<{#UString(table.Name)}>().Where(a => {#parmsByWhereLambda}).ExecuteAffrows(); //删除缓存 } -{/for}{if (table.Uniques.Count > 0)}{% string redisRemoveCode = string.Empty; %}{for uk001 in table.Uniques}{% +{/for}{% string redisRemoveCode = string.Empty; %}{for uk001 in table.Uniques}{% string parmsBy = "By"; string parmsNodeTypeUpdateCacheRemove = string.Empty; @@ -143,10 +143,10 @@ namespace test.Model { var keysIdx = 0; foreach (var item in items) {{#redisRemoveCode} } - if (mysql.Ado.TransactionCurrentThread != null) mysql.Ado.TransactionPreRemoveCache(keys); - else mysql.Cache.Remove(keys); + if (freesql.Ado.TransactionCurrentThread != null) freesql.Ado.TransactionPreRemoveCache(keys); + else freesql.Cache.Remove(keys); } -{/if}{if (table.Columns.Count < 100)}{% +{if (table.Columns.Count < 100)}{% string CsParam3 = string.Empty; string CsParamNoType3 = string.Empty; string parms = string.Empty; @@ -186,55 +186,55 @@ namespace test.Model { if (CsParamNoType3.Length > 0) CsParamNoType3 = CsParamNoType3.Substring(0, CsParamNoType3.Length - 2); %}{if idens > 0} public static {#GetCsType(idensCol)} Insert({#UString(table.Name)} item) { - item.{#UString(idensCol.Name)} = ({#GetCsType(idensCol)})mysql.Insert<{#UString(table.Name)}>().AppendData(item).ExecuteIdentity(); + item.{#UString(idensCol.Name)} = ({#GetCsType(idensCol)})freesql.Insert<{#UString(table.Name)}>().AppendData(item).ExecuteIdentity(); if (ItemCacheTimeout > 0) RemoveCache(item); return item.{#UString(idensCol.Name)}; }{else} public static void Insert({#UString(table.Name)} item) { if (ItemCacheTimeout > 0) RemoveCache(item); - mysql.Insert<{#UString(table.Name)}>().AppendData(item).ExecuteAffrows(); + freesql.Insert<{#UString(table.Name)}>().AppendData(item).ExecuteAffrows(); } public static long Insert(IEnumerable<{#UString(table.Name)}> items) { if (ItemCacheTimeout > 0) RemoveCache(items); - return mysql.Insert<{#UString(table.Name)}>().AppendData(items).ExecuteAffrows(); + return freesql.Insert<{#UString(table.Name)}>().AppendData(items).ExecuteAffrows(); }{/if} {if CsParamNoType3.Split('=').Length <= 5}{if idens > 0} public static {#GetCsType(idensCol)} Insert({#CsParam3}) { var item = new {#UString(table.Name)} {{#CsParamNoType3}}; - item.{#UString(idensCol.Name)} = ({#GetCsType(idensCol)})mysql.Insert<{#UString(table.Name)}>().AppendData(new {#UString(table.Name)} {{#CsParamNoType3}}).ExecuteIdentity(); + item.{#UString(idensCol.Name)} = ({#GetCsType(idensCol)})freesql.Insert<{#UString(table.Name)}>().AppendData(new {#UString(table.Name)} {{#CsParamNoType3}}).ExecuteIdentity(); if (ItemCacheTimeout > 0) RemoveCache(item); return item.{#UString(idensCol.Name)}; }{else} public static {#UString(table.Name)} Insert({#CsParam3}) { var item = new {#UString(table.Name)} {{#CsParamNoType3}}; - mysql.Insert<{#UString(table.Name)}>().AppendData(item).ExecuteAffrows(); + freesql.Insert<{#UString(table.Name)}>().AppendData(item).ExecuteAffrows(); if (ItemCacheTimeout > 0) RemoveCache(item); return item; }{/if}{/if} public static long Update({#UString(table.Name)} item) { if (ItemCacheTimeout > 0) RemoveCache(item); - return mysql.Update<{#UString(table.Name)}>().SetSource(item).ExecuteAffrows(); + return freesql.Update<{#UString(table.Name)}>().SetSource(item).ExecuteAffrows(); } public static long Update(IEnumerable<{#UString(table.Name)}> items) { if (ItemCacheTimeout > 0) RemoveCache(items); - return mysql.Update<{#UString(table.Name)}>().SetSource(items).ExecuteAffrows(); + return freesql.Update<{#UString(table.Name)}>().SetSource(items).ExecuteAffrows(); } /// /// 指定字段更新 /// - public IUpdate<{#UString(table.Name)}> UpdateDiy => mysql.Update<{#UString(table.Name)}>().Where(a => {#parmsByWhereLambda}); + public IUpdate<{#UString(table.Name)}> UpdateDiy => freesql.Update<{#UString(table.Name)}>().Where(a => {#parmsByWhereLambda}); /// /// {if pks.Count > 0}保存或添加,如果主键有值则尝试 Update,如果影响的行为 0 则尝试 Insert{else}添加{/if} /// public void Save() {{if pks.Count > 0} if ({#string.Join(" && ", pks.Select(pkssa => "this." + UString(pkssa.Name) + " != default(" + GetCsType(pkssa) + ")"))}) { - var affrows = mysql.Update<{#UString(table.Name)}>().Where(a => {#parmsByWhereLambda}).ExecuteAffrows(); + var affrows = freesql.Update<{#UString(table.Name)}>().Where(a => {#parmsByWhereLambda}).ExecuteAffrows(); if (affrows > 0) return; }{/if} - {if idens > 0}this.{#UString(idensCol.Name)} = {#GetCsType(idensCol).Replace("?", "") == "long" ? "" : ("(" + GetCsType(idensCol) + ")")}mysql.Insert<{#UString(table.Name)}>().AppendData(this).ExecuteIdentity();{else} - mysql.Insert<{#UString(table.Name)}>().AppendData(this).ExecuteAffrows();{/if} + {if idens > 0}this.{#UString(idensCol.Name)} = {#GetCsType(idensCol).Replace("?", "") == "long" ? "" : ("(" + GetCsType(idensCol) + ")")}freesql.Insert<{#UString(table.Name)}>().AppendData(this).ExecuteIdentity();{else} + freesql.Insert<{#UString(table.Name)}>().AppendData(this).ExecuteAffrows();{/if} } -{/if} +{/if}{/if} } {include ../../include/enumtype.tpl} } \ No newline at end of file diff --git a/Templates/MySql/rich-entity-navigation-object/readme.md b/Templates/MySql/rich-entity-navigation-object/readme.md index e69de29b..c95c10a5 100644 --- a/Templates/MySql/rich-entity-navigation-object/readme.md +++ b/Templates/MySql/rich-entity-navigation-object/readme.md @@ -0,0 +1,94 @@ +# 生成器 + +生成器是基于 dbfirst 开发的辅助工具,适用老项目一键生成实体。生成器采用模板的方式,作者实现了三种生成模板: + +| 模板名称 | 类型映射 | 外键导航属性 | 缓存管理 | 失血 | 贫血 | 充血 | +| ------------- | - | - |- | - |- | - | +| simple-entity | √ | X | X | √ | X | X | +| simple-entity-navigation-object | √ | √ | X | √ | X | X | +| rich-entity-navigation-object | √ | √ | √ | X | √ | X | + +模板在项目目录:/Templates/MySql + +> 更多模板逐步开发中。。。 + +```csharp +//定义 mysql FreeSql +var mysql = new FreeSql.FreeSqlBuilder() + .UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10") + .Build(); + +//创建模板生成类现实 +var gen = new FreeSql.Generator.TemplateGenerator(); +gen.Build(mysql.DbFirst, + @"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\simple-entity", //模板目录(事先下载) + @"C:\Users\28810\Desktop\新建文件夹 (9)", //生成后保存的目录 + "cccddd" //数据库 +); +``` + +## 模板语法 + +```html + + +{#title} + + + + +{#表达式} +{##表达式} 当表达式可能发生runtime错误时使用,性能没有上面的高 + + +{include ../header.html} +
+

aaa

+

bbb {#i}

+

ccc {#i}

+
+ + +{module module_name1 parms1, 2, 3...} +{/module} +{module module_name2 parms1, 2, 3...} +{/module} + + +{import ../module.html as myname} +{#myname.module_name(parms1, 2, 3...)} + + +{extends ../inc/layout.html} +{block body}{/block} + + +{% +for (var a = 0; a < 100; a++) + print(a); +%} + + +{if i === 50} +{elseif i > 60} +{else} +{/if} + + +{for i 1,101} 可自定义名 {for index2 表达式1 in 表达式2} + +{for item,index in items} 可选参数称 index + 可自定义名 {for item2, index99 in 数组表达式} + +{for key,item,index on json} 可选参数 item, index, + 可自定义名 {for key2, item2, index99 in 对象表达式} +{/for} + + +{miss} +此块内容不被bmw.js解析 +{/miss} + + + +``` \ No newline at end of file diff --git a/Templates/MySql/simple-entity-navigation-object/Models/for-table.cs.freesql b/Templates/MySql/simple-entity-navigation-object/Model/for-table.cs.freesql similarity index 100% rename from Templates/MySql/simple-entity-navigation-object/Models/for-table.cs.freesql rename to Templates/MySql/simple-entity-navigation-object/Model/for-table.cs.freesql diff --git a/Templates/MySql/simple-entity-navigation-object/readme.md b/Templates/MySql/simple-entity-navigation-object/readme.md index e69de29b..c95c10a5 100644 --- a/Templates/MySql/simple-entity-navigation-object/readme.md +++ b/Templates/MySql/simple-entity-navigation-object/readme.md @@ -0,0 +1,94 @@ +# 生成器 + +生成器是基于 dbfirst 开发的辅助工具,适用老项目一键生成实体。生成器采用模板的方式,作者实现了三种生成模板: + +| 模板名称 | 类型映射 | 外键导航属性 | 缓存管理 | 失血 | 贫血 | 充血 | +| ------------- | - | - |- | - |- | - | +| simple-entity | √ | X | X | √ | X | X | +| simple-entity-navigation-object | √ | √ | X | √ | X | X | +| rich-entity-navigation-object | √ | √ | √ | X | √ | X | + +模板在项目目录:/Templates/MySql + +> 更多模板逐步开发中。。。 + +```csharp +//定义 mysql FreeSql +var mysql = new FreeSql.FreeSqlBuilder() + .UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10") + .Build(); + +//创建模板生成类现实 +var gen = new FreeSql.Generator.TemplateGenerator(); +gen.Build(mysql.DbFirst, + @"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\simple-entity", //模板目录(事先下载) + @"C:\Users\28810\Desktop\新建文件夹 (9)", //生成后保存的目录 + "cccddd" //数据库 +); +``` + +## 模板语法 + +```html + + +{#title} + + + + +{#表达式} +{##表达式} 当表达式可能发生runtime错误时使用,性能没有上面的高 + + +{include ../header.html} +
+

aaa

+

bbb {#i}

+

ccc {#i}

+
+ + +{module module_name1 parms1, 2, 3...} +{/module} +{module module_name2 parms1, 2, 3...} +{/module} + + +{import ../module.html as myname} +{#myname.module_name(parms1, 2, 3...)} + + +{extends ../inc/layout.html} +{block body}{/block} + + +{% +for (var a = 0; a < 100; a++) + print(a); +%} + + +{if i === 50} +{elseif i > 60} +{else} +{/if} + + +{for i 1,101} 可自定义名 {for index2 表达式1 in 表达式2} + +{for item,index in items} 可选参数称 index + 可自定义名 {for item2, index99 in 数组表达式} + +{for key,item,index on json} 可选参数 item, index, + 可自定义名 {for key2, item2, index99 in 对象表达式} +{/for} + + +{miss} +此块内容不被bmw.js解析 +{/miss} + + + +``` \ No newline at end of file diff --git a/Templates/MySql/simple-entity/Models/for-table.cs.freesql b/Templates/MySql/simple-entity/Model/for-table.cs.freesql similarity index 100% rename from Templates/MySql/simple-entity/Models/for-table.cs.freesql rename to Templates/MySql/simple-entity/Model/for-table.cs.freesql diff --git a/Templates/MySql/simple-entity/readme.md b/Templates/MySql/simple-entity/readme.md index e69de29b..c95c10a5 100644 --- a/Templates/MySql/simple-entity/readme.md +++ b/Templates/MySql/simple-entity/readme.md @@ -0,0 +1,94 @@ +# 生成器 + +生成器是基于 dbfirst 开发的辅助工具,适用老项目一键生成实体。生成器采用模板的方式,作者实现了三种生成模板: + +| 模板名称 | 类型映射 | 外键导航属性 | 缓存管理 | 失血 | 贫血 | 充血 | +| ------------- | - | - |- | - |- | - | +| simple-entity | √ | X | X | √ | X | X | +| simple-entity-navigation-object | √ | √ | X | √ | X | X | +| rich-entity-navigation-object | √ | √ | √ | X | √ | X | + +模板在项目目录:/Templates/MySql + +> 更多模板逐步开发中。。。 + +```csharp +//定义 mysql FreeSql +var mysql = new FreeSql.FreeSqlBuilder() + .UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10") + .Build(); + +//创建模板生成类现实 +var gen = new FreeSql.Generator.TemplateGenerator(); +gen.Build(mysql.DbFirst, + @"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\simple-entity", //模板目录(事先下载) + @"C:\Users\28810\Desktop\新建文件夹 (9)", //生成后保存的目录 + "cccddd" //数据库 +); +``` + +## 模板语法 + +```html + + +{#title} + + + + +{#表达式} +{##表达式} 当表达式可能发生runtime错误时使用,性能没有上面的高 + + +{include ../header.html} +
+

aaa

+

bbb {#i}

+

ccc {#i}

+
+ + +{module module_name1 parms1, 2, 3...} +{/module} +{module module_name2 parms1, 2, 3...} +{/module} + + +{import ../module.html as myname} +{#myname.module_name(parms1, 2, 3...)} + + +{extends ../inc/layout.html} +{block body}{/block} + + +{% +for (var a = 0; a < 100; a++) + print(a); +%} + + +{if i === 50} +{elseif i > 60} +{else} +{/if} + + +{for i 1,101} 可自定义名 {for index2 表达式1 in 表达式2} + +{for item,index in items} 可选参数称 index + 可自定义名 {for item2, index99 in 数组表达式} + +{for key,item,index on json} 可选参数 item, index, + 可自定义名 {for key2, item2, index99 in 对象表达式} +{/for} + + +{miss} +此块内容不被bmw.js解析 +{/miss} + + + +``` \ No newline at end of file diff --git a/Templates/SqlServer/rich-entity-navigation-object/Const.cs b/Templates/SqlServer/rich-entity-navigation-object/Const.cs new file mode 100644 index 00000000..783e7d9e --- /dev/null +++ b/Templates/SqlServer/rich-entity-navigation-object/Const.cs @@ -0,0 +1,5 @@ +public static class Const { + public static IFreeSql sqlserver = new FreeSql.FreeSqlBuilder() + .UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10") + .Build(); +} diff --git a/Templates/SqlServer/rich-entity-navigation-object/Model/for-table.cs.freesql b/Templates/SqlServer/rich-entity-navigation-object/Model/for-table.cs.freesql new file mode 100644 index 00000000..7a454552 --- /dev/null +++ b/Templates/SqlServer/rich-entity-navigation-object/Model/for-table.cs.freesql @@ -0,0 +1,240 @@ +{%if (table.Type == DbTableType.StoreProcedure) { + print("return;"); + return rTn; + } + %}using System; +using System.Collections; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Newtonsoft.Json; +using FreeSql; +using FreeSql.DataAnnotations; +{% +var dbf = dbfirst as FreeSql.IDbFirst; +var cols = (table.Columns as List); +var pks = (table.Primarys as List); +var fks = (table.Foreigns as List); + +Func UString = stra => stra.Substring(0, 1).ToUpper() + stra.Substring(1); +Func GetCsType = cola3 => { + return dbf.GetCsType(cola3); +}; +Func GetFkObjectName = fkx => { + var eqfks = fks.Where(fk22a => fk22a.ReferencedTable.Name == fkx.ReferencedTable.Name); + if (eqfks.Count() == 1) return "Obj_" + fkx.ReferencedTable.Name; + var fkretname = fkx.Columns[0].Name; + if (fkretname.EndsWith(fkx.ReferencedColumns[0].Name, StringComparison.CurrentCultureIgnoreCase)) fkretname = fkretname.Substring(0, fkretname.Length - fkx.ReferencedColumns[0].Name.Length).TrimEnd('_'); + if (fkretname.EndsWith(fkx.ReferencedTable.Name, StringComparison.CurrentCultureIgnoreCase)) fkretname = fkretname.Substring(0, fkretname.Length - fkx.ReferencedTable.Name.Length).TrimEnd('_'); + if (fkretname.StartsWith(fkx.ReferencedTable.Name, StringComparison.CurrentCultureIgnoreCase)) fkretname = fkretname.Substring(fkx.ReferencedTable.Name.Length).TrimStart('_'); + return "Obj_" + fkx.ReferencedTable.Name + (string.IsNullOrEmpty(fkretname) ? "" : ("_" + fkretname)); +}; + +%} +namespace test.Model { + + [JsonObject(MemberSerialization.OptIn), Table(Name = "{#!string.IsNullOrEmpty(table.Schema) ? table.Schema + "." : ""}{#table.Name}"{if cols.Where(cola003 => cola003.Name.ToLower() == "is_deleted" || cola003.Name.ToLower() == "isdeleted").Any()}, SelectFilter = "a.IsDeleted = 1"{/if})] + public partial class {#UString(table.Name)} {{for col,index in table.Columns}{% + var findfks = fks.Where(fkaa => fkaa.Columns.Where(fkaac1 => fkaac1.Name == col.Name).Any()); + %}{if findfks.Any() == false} + {if string.IsNullOrEmpty(col.Coment) == false}/// + /// {#col.Coment.Replace("\r\n", "\n").Replace("\n", "\r\n /// ")} + /// {/if} + [JsonProperty, Column(Name = "{#col.Name}", DbType = "{#col.DbTypeTextFull}"{if col.IsPrimary == true}, IsPrimary = true{/if}{if col.IsIdentity == true}, IsIdentity = true{/if}{if col.IsNullable == true}, IsNullable = true{/if})] + public {#GetCsType(col)} {#UString(col.Name)} { get; set; } + {else} + private {#GetCsType(col)} _{#UString(col.Name)}; + {if string.IsNullOrEmpty(col.Coment) == false}/// + /// {#col.Coment.Replace("\r\n", "\n").Replace("\n", "\r\n /// ")} + /// {/if} + [JsonProperty, Column(Name = "{#col.Name}", DbType = "{#col.DbTypeTextFull}"{if col.IsPrimary == true}, IsPrimary = true{/if}{if col.IsIdentity == true}, IsIdentity = true{/if}{if col.IsNullable == true}, IsNullable = true{/if})] + public {#GetCsType(col)} {#UString(col.Name)} { get => _{#UString(col.Name)}; set { + if (_{#UString(col.Name)} == value) return; + _{#UString(col.Name)} = value;{for fkcok2 in findfks} + {#GetFkObjectName(fkcok2)} = null;{/for} + } } + {/if}{/for}{for fk in fks} + public {#UString(fk.ReferencedTable.Name)} {#GetFkObjectName(fk)} { get; set; } + {/for} + internal static IFreeSql freesql => Const.sqlserver; + public static ISelect<{#UString(table.Name)}> Select => freesql.Select<{#UString(table.Name)}>(); +{if (table.Uniques.Count > 0)} + public static int ItemCacheTimeout = 180;{for uk001 in table.Uniques}{% + + string parms = string.Empty; + string parmsByWhereLambda = string.Empty; + string parmsBy = "By"; + string parmsNodeTypeUpdateCacheRemove = string.Empty; + foreach (var uk001col in uk001) { + string getcstype = GetCsType(uk001col); + parms += getcstype.Replace("?", "") + " " + UString(uk001col.Name) + ", "; + parmsByWhereLambda += "a." + UString(uk001col.Name) + " == " + UString(uk001col.Name) + " && "; + parmsBy += UString(uk001col.Name) + "And"; + parmsNodeTypeUpdateCacheRemove += "item." + UString(uk001col.Name) + ", \"_,_\", "; + } + parms = parms.Substring(0, parms.Length - 2); + parmsByWhereLambda = parmsByWhereLambda.Substring(0, parmsByWhereLambda.Length - 4); + parmsBy = parmsBy.Substring(0, parmsBy.Length - 3); + parmsNodeTypeUpdateCacheRemove = parmsNodeTypeUpdateCacheRemove.Substring(0, parmsNodeTypeUpdateCacheRemove.Length - 9); + %} + public static {#UString(table.Name)} GetItem{#uk001[0].IsPrimary ? string.Empty : parmsBy}({#parms}) => Select.Where(a => {#parmsByWhereLambda}).Caching(ItemCacheTimeout, string.Concat("test:{#table.Name}{#uk001[0].IsPrimary ? string.Empty : parmsBy}:", {#parmsNodeTypeUpdateCacheRemove.Replace("item.", "")})).ToOne();{/for} +{for uk001 in table.Uniques}{% + + string parms = string.Empty; + string parmsByWhereLambda = string.Empty; + string parmsNewItem = string.Empty; + string parmsBy = "By"; + string parmsNoneType = string.Empty; + foreach (var uk001col in uk001) { + string getcstype = GetCsType(uk001col); + parms += getcstype.Replace("?", "") + " " + UString(uk001col.Name) + ", "; + parmsByWhereLambda += "a." + UString(uk001col.Name) + " == " + UString(uk001col.Name) + " && "; + parmsNewItem += UString(uk001col.Name) + " = " + UString(uk001col.Name) + ", "; + parmsBy += UString(uk001col.Name) + "And"; + parmsNoneType += UString(uk001col.Name) + ", "; + } + parms = parms.Substring(0, parms.Length - 2); + parmsByWhereLambda = parmsByWhereLambda.Substring(0, parmsByWhereLambda.Length - 4); + parmsNewItem = parmsNewItem.Substring(0, parmsNewItem.Length - 2); + parmsBy = parmsBy.Substring(0, parmsBy.Length - 3); + parmsNoneType = parmsNoneType.Substring(0, parmsNoneType.Length - 2); + %} + public static long Delete{#uk001[0].IsPrimary ? string.Empty : parmsBy}({#parms}) { + var affrows = freesql.Delete<{#UString(table.Name)}>().Where(a => {#parmsByWhereLambda}).ExecuteAffrows();{if table.Uniques.Count > 1} + if (ItemCacheTimeout > 0) RemoveCache(GetItem{#uk001[0].IsPrimary ? string.Empty : parmsBy}({#parmsNoneType}));{else} + if (ItemCacheTimeout > 0) RemoveCache(new {#UString(table.Name)} { {#parmsNewItem} });{/if} + return affrows; + }{/for} +{for fkcoldel in fks}{% + string parms = string.Empty; + string parmsBy = "By"; + string parmsByWhereLambda = string.Empty; + foreach( var fkcoldelcol in fkcoldel.Columns) { + string getcstype = GetCsType(fkcoldelcol); + parms += getcstype.Replace("?", "") + " " + UString(fkcoldelcol.Name) + ", "; + parmsBy += UString(fkcoldelcol.Name) + "And"; + parmsByWhereLambda += "a." + UString(fkcoldelcol.Name) + " == " + UString(fkcoldelcol.Name) + " && "; + } + parms = parms.Substring(0, parms.Length - 2); + parmsBy = parmsBy.Substring(0, parmsBy.Length - 3); + parmsByWhereLambda = parmsByWhereLambda.Substring(0, parmsByWhereLambda.Length - 4); + %} + public static long DeleteBy{#parmsBy}({#parms}) { + return freesql.Delete<{#UString(table.Name)}>().Where(a => {#parmsByWhereLambda}).ExecuteAffrows(); //删除缓存 + } +{/for}{% string redisRemoveCode = string.Empty; %}{for uk001 in table.Uniques}{% + + string parmsBy = "By"; + string parmsNodeTypeUpdateCacheRemove = string.Empty; + foreach (var uk001col in uk001) { + parmsBy += UString(uk001col.Name) + "And"; + parmsNodeTypeUpdateCacheRemove += "item." + UString(uk001col.Name) + ", \"_,_\", "; + } + parmsBy = parmsBy.Substring(0, parmsBy.Length - 3); + parmsNodeTypeUpdateCacheRemove = parmsNodeTypeUpdateCacheRemove.Substring(0, parmsNodeTypeUpdateCacheRemove.Length - 9); + redisRemoveCode += $@" + keys[keysIdx++] = string.Concat(""test:{table.Name}{(uk001[0].IsPrimary ? string.Empty : parmsBy)}:"", {parmsNodeTypeUpdateCacheRemove});"; + %}{/for} + internal static void RemoveCache({#UString(table.Name)} item) => RemoveCache(item == null ? null : new [] { item }); + internal static void RemoveCache(IEnumerable<{#UString(table.Name)}> items) { + if (ItemCacheTimeout <= 0 || items == null || items.Any() == false) return; + var keys = new string[items.Count() * {#table.Uniques.Count}]; + var keysIdx = 0; + foreach (var item in items) {{#redisRemoveCode} + } + if (freesql.Ado.TransactionCurrentThread != null) freesql.Ado.TransactionPreRemoveCache(keys); + else freesql.Cache.Remove(keys); + } +{if (table.Columns.Count < 100)}{% + string CsParam3 = string.Empty; + string CsParamNoType3 = string.Empty; + string parms = string.Empty; + string parmsByWhereLambda = string.Empty; + string parmsNewItem = string.Empty; + string parmsBy = "By"; + string parmsNoneType = string.Empty; + var idens = 0; + var idensCol = table.Columns[0]; + foreach (var uk001col in table.Columns) { + string getcstype = GetCsType(uk001col); + parms += getcstype.Replace("?", "") + " " + UString(uk001col.Name) + ", "; + if (uk001col.IsPrimary) + parmsByWhereLambda += "a." + UString(uk001col.Name) + " == " + UString(uk001col.Name) + " && "; + parmsNewItem += UString(uk001col.Name) + " = " + UString(uk001col.Name) + ", "; + parmsBy += UString(uk001col.Name) + "And"; + parmsNoneType += UString(uk001col.Name) + ", "; + if (uk001col.IsIdentity) { + idens++; + idensCol = uk001col; + } else { + if (getcstype.StartsWith("DateTime") && (uk001col.Name.ToLower() == "create_time" || uk001col.Name.ToLower() == "update_time" || uk001col.Name.ToLower() == "createtime" || uk001col.Name.ToLower() == "updatetime") || + getcstype == "bool?" && (uk001col.Name.ToLower() == "is_deleted" || uk001col.Name.ToLower() == "isdeleted")) { + + } else { + CsParam3 += getcstype + " " + UString(uk001col.Name) + ", "; + CsParamNoType3 += string.Format("\r\n {0} = {0}, ", UString(uk001col.Name)); + } + } + } + parms = parms.Substring(0, parms.Length - 2); + if (parmsByWhereLambda.Length > 0) parmsByWhereLambda = parmsByWhereLambda.Substring(0, parmsByWhereLambda.Length - 4); + parmsNewItem = parmsNewItem.Substring(0, parmsNewItem.Length - 2); + parmsBy = parmsBy.Substring(0, parmsBy.Length - 3); + parmsNoneType = parmsNoneType.Substring(0, parmsNoneType.Length - 2); + if (CsParam3.Length > 0) CsParam3 = CsParam3.Substring(0, CsParam3.Length - 2); + if (CsParamNoType3.Length > 0) CsParamNoType3 = CsParamNoType3.Substring(0, CsParamNoType3.Length - 2); + %}{if idens > 0} + public static {#GetCsType(idensCol)} Insert({#UString(table.Name)} item) { + item.{#UString(idensCol.Name)} = ({#GetCsType(idensCol)})freesql.Insert<{#UString(table.Name)}>().AppendData(item).ExecuteIdentity(); + if (ItemCacheTimeout > 0) RemoveCache(item); + return item.{#UString(idensCol.Name)}; + }{else} + public static void Insert({#UString(table.Name)} item) { + if (ItemCacheTimeout > 0) RemoveCache(item); + freesql.Insert<{#UString(table.Name)}>().AppendData(item).ExecuteAffrows(); + } + public static long Insert(IEnumerable<{#UString(table.Name)}> items) { + if (ItemCacheTimeout > 0) RemoveCache(items); + return freesql.Insert<{#UString(table.Name)}>().AppendData(items).ExecuteAffrows(); + }{/if} + {if CsParamNoType3.Split('=').Length <= 5}{if idens > 0} + public static {#GetCsType(idensCol)} Insert({#CsParam3}) { + var item = new {#UString(table.Name)} {{#CsParamNoType3}}; + item.{#UString(idensCol.Name)} = ({#GetCsType(idensCol)})freesql.Insert<{#UString(table.Name)}>().AppendData(new {#UString(table.Name)} {{#CsParamNoType3}}).ExecuteIdentity(); + if (ItemCacheTimeout > 0) RemoveCache(item); + return item.{#UString(idensCol.Name)}; + }{else} + public static {#UString(table.Name)} Insert({#CsParam3}) { + var item = new {#UString(table.Name)} {{#CsParamNoType3}}; + freesql.Insert<{#UString(table.Name)}>().AppendData(item).ExecuteAffrows(); + if (ItemCacheTimeout > 0) RemoveCache(item); + return item; + }{/if}{/if} + public static long Update({#UString(table.Name)} item) { + if (ItemCacheTimeout > 0) RemoveCache(item); + return freesql.Update<{#UString(table.Name)}>().SetSource(item).ExecuteAffrows(); + } + public static long Update(IEnumerable<{#UString(table.Name)}> items) { + if (ItemCacheTimeout > 0) RemoveCache(items); + return freesql.Update<{#UString(table.Name)}>().SetSource(items).ExecuteAffrows(); + } + /// + /// 指定字段更新 + /// + public IUpdate<{#UString(table.Name)}> UpdateDiy => freesql.Update<{#UString(table.Name)}>().Where(a => {#parmsByWhereLambda}); + /// + /// {if pks.Count > 0}保存或添加,如果主键有值则尝试 Update,如果影响的行为 0 则尝试 Insert{else}添加{/if} + /// + public void Save() {{if pks.Count > 0} + if ({#string.Join(" && ", pks.Select(pkssa => "this." + UString(pkssa.Name) + " != default(" + GetCsType(pkssa) + ")"))}) { + var affrows = freesql.Update<{#UString(table.Name)}>().Where(a => {#parmsByWhereLambda}).ExecuteAffrows(); + if (affrows > 0) return; + }{/if} + {if idens > 0}this.{#UString(idensCol.Name)} = {#GetCsType(idensCol).Replace("?", "") == "long" ? "" : ("(" + GetCsType(idensCol) + ")")}freesql.Insert<{#UString(table.Name)}>().AppendData(this).ExecuteIdentity();{else} + freesql.Insert<{#UString(table.Name)}>().AppendData(this).ExecuteAffrows();{/if} + } +{/if}{/if} + } +} \ No newline at end of file diff --git a/Templates/SqlServer/rich-entity-navigation-object/readme.md b/Templates/SqlServer/rich-entity-navigation-object/readme.md new file mode 100644 index 00000000..c95c10a5 --- /dev/null +++ b/Templates/SqlServer/rich-entity-navigation-object/readme.md @@ -0,0 +1,94 @@ +# 生成器 + +生成器是基于 dbfirst 开发的辅助工具,适用老项目一键生成实体。生成器采用模板的方式,作者实现了三种生成模板: + +| 模板名称 | 类型映射 | 外键导航属性 | 缓存管理 | 失血 | 贫血 | 充血 | +| ------------- | - | - |- | - |- | - | +| simple-entity | √ | X | X | √ | X | X | +| simple-entity-navigation-object | √ | √ | X | √ | X | X | +| rich-entity-navigation-object | √ | √ | √ | X | √ | X | + +模板在项目目录:/Templates/MySql + +> 更多模板逐步开发中。。。 + +```csharp +//定义 mysql FreeSql +var mysql = new FreeSql.FreeSqlBuilder() + .UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10") + .Build(); + +//创建模板生成类现实 +var gen = new FreeSql.Generator.TemplateGenerator(); +gen.Build(mysql.DbFirst, + @"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\simple-entity", //模板目录(事先下载) + @"C:\Users\28810\Desktop\新建文件夹 (9)", //生成后保存的目录 + "cccddd" //数据库 +); +``` + +## 模板语法 + +```html + + +{#title} + + + + +{#表达式} +{##表达式} 当表达式可能发生runtime错误时使用,性能没有上面的高 + + +{include ../header.html} +
+

aaa

+

bbb {#i}

+

ccc {#i}

+
+ + +{module module_name1 parms1, 2, 3...} +{/module} +{module module_name2 parms1, 2, 3...} +{/module} + + +{import ../module.html as myname} +{#myname.module_name(parms1, 2, 3...)} + + +{extends ../inc/layout.html} +{block body}{/block} + + +{% +for (var a = 0; a < 100; a++) + print(a); +%} + + +{if i === 50} +{elseif i > 60} +{else} +{/if} + + +{for i 1,101} 可自定义名 {for index2 表达式1 in 表达式2} + +{for item,index in items} 可选参数称 index + 可自定义名 {for item2, index99 in 数组表达式} + +{for key,item,index on json} 可选参数 item, index, + 可自定义名 {for key2, item2, index99 in 对象表达式} +{/for} + + +{miss} +此块内容不被bmw.js解析 +{/miss} + + + +``` \ No newline at end of file diff --git a/Templates/SqlServer/simple-entity-navigation-object/Model/for-table.cs.freesql b/Templates/SqlServer/simple-entity-navigation-object/Model/for-table.cs.freesql new file mode 100644 index 00000000..3d606937 --- /dev/null +++ b/Templates/SqlServer/simple-entity-navigation-object/Model/for-table.cs.freesql @@ -0,0 +1,59 @@ +{%if (table.Type == DbTableType.StoreProcedure) { + print("return;"); + return rTn; + } + %}using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Newtonsoft.Json; +using FreeSql.DataAnnotations; +{% +var dbf = dbfirst as FreeSql.IDbFirst; +var cols = (table.Columns as List); +var pks = (table.Primarys as List); +var fks = (table.Foreigns as List); + +Func UString = stra => stra.Substring(0, 1).ToUpper() + stra.Substring(1); +Func GetCsType = cola3 => { + return dbf.GetCsType(cola3); +}; +Func GetFkObjectName = fkx => { + var eqfks = fks.Where(fk22a => fk22a.ReferencedTable.Name == fkx.ReferencedTable.Name); + if (eqfks.Count() == 1) return "Obj_" + fkx.ReferencedTable.Name; + var fkretname = fkx.Columns[0].Name; + if (fkretname.EndsWith(fkx.ReferencedColumns[0].Name, StringComparison.CurrentCultureIgnoreCase)) fkretname = fkretname.Substring(0, fkretname.Length - fkx.ReferencedColumns[0].Name.Length).TrimEnd('_'); + if (fkretname.EndsWith(fkx.ReferencedTable.Name, StringComparison.CurrentCultureIgnoreCase)) fkretname = fkretname.Substring(0, fkretname.Length - fkx.ReferencedTable.Name.Length).TrimEnd('_'); + if (fkretname.StartsWith(fkx.ReferencedTable.Name, StringComparison.CurrentCultureIgnoreCase)) fkretname = fkretname.Substring(fkx.ReferencedTable.Name.Length).TrimStart('_'); + return "Obj_" + fkx.ReferencedTable.Name + (string.IsNullOrEmpty(fkretname) ? "" : ("_" + fkretname)); +}; +%} +namespace test.Model { + + [JsonObject(MemberSerialization.OptIn), Table(Name = "{#!string.IsNullOrEmpty(table.Schema) ? table.Schema + "." : ""}{#table.Name}"{if cols.Where(cola003 => cola003.Name.ToLower() == "is_deleted" || cola003.Name.ToLower() == "isdeleted").Any()}, SelectFilter = "a.IsDeleted = 1"{/if})] + public partial class {#UString(table.Name)} {{for col,index in table.Columns}{% + var findfks = fks.Where(fkaa => fkaa.Columns.Where(fkaac1 => fkaac1.Name == col.Name).Any()); + %}{if findfks.Any() == false} + {if string.IsNullOrEmpty(col.Coment) == false}/// + /// {#col.Coment.Replace("\r\n", "\n").Replace("\n", "\r\n /// ")} + /// {/if} + [JsonProperty, Column(Name = "{#col.Name}", DbType = "{#col.DbTypeTextFull}"{if col.IsPrimary == true}, IsPrimary = true{/if}{if col.IsIdentity == true}, IsIdentity = true{/if}{if col.IsNullable == true}, IsNullable = true{/if})] + public {#GetCsType(col)} {#UString(col.Name)} { get; set; } + {else} + private {#GetCsType(col)} _{#UString(col.Name)}; + {if string.IsNullOrEmpty(col.Coment) == false}/// + /// {#col.Coment.Replace("\r\n", "\n").Replace("\n", "\r\n /// ")} + /// {/if} + [JsonProperty, Column(Name = "{#col.Name}", DbType = "{#col.DbTypeTextFull}"{if col.IsPrimary == true}, IsPrimary = true{/if}{if col.IsIdentity == true}, IsIdentity = true{/if}{if col.IsNullable == true}, IsNullable = true{/if})] + public {#GetCsType(col)} {#UString(col.Name)} { get => _{#UString(col.Name)}; set { + if (_{#UString(col.Name)} == value) return; + _{#UString(col.Name)} = value;{for fkcok2 in findfks} + {#GetFkObjectName(fkcok2)} = null;{/for} + } } + {/if}{/for}{for fk in fks} + public {#UString(fk.ReferencedTable.Name)} {#GetFkObjectName(fk)} { get; set; } + {/for} + } +} \ No newline at end of file diff --git a/Templates/SqlServer/simple-entity-navigation-object/readme.md b/Templates/SqlServer/simple-entity-navigation-object/readme.md new file mode 100644 index 00000000..c95c10a5 --- /dev/null +++ b/Templates/SqlServer/simple-entity-navigation-object/readme.md @@ -0,0 +1,94 @@ +# 生成器 + +生成器是基于 dbfirst 开发的辅助工具,适用老项目一键生成实体。生成器采用模板的方式,作者实现了三种生成模板: + +| 模板名称 | 类型映射 | 外键导航属性 | 缓存管理 | 失血 | 贫血 | 充血 | +| ------------- | - | - |- | - |- | - | +| simple-entity | √ | X | X | √ | X | X | +| simple-entity-navigation-object | √ | √ | X | √ | X | X | +| rich-entity-navigation-object | √ | √ | √ | X | √ | X | + +模板在项目目录:/Templates/MySql + +> 更多模板逐步开发中。。。 + +```csharp +//定义 mysql FreeSql +var mysql = new FreeSql.FreeSqlBuilder() + .UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10") + .Build(); + +//创建模板生成类现实 +var gen = new FreeSql.Generator.TemplateGenerator(); +gen.Build(mysql.DbFirst, + @"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\simple-entity", //模板目录(事先下载) + @"C:\Users\28810\Desktop\新建文件夹 (9)", //生成后保存的目录 + "cccddd" //数据库 +); +``` + +## 模板语法 + +```html + + +{#title} + + + + +{#表达式} +{##表达式} 当表达式可能发生runtime错误时使用,性能没有上面的高 + + +{include ../header.html} +
+

aaa

+

bbb {#i}

+

ccc {#i}

+
+ + +{module module_name1 parms1, 2, 3...} +{/module} +{module module_name2 parms1, 2, 3...} +{/module} + + +{import ../module.html as myname} +{#myname.module_name(parms1, 2, 3...)} + + +{extends ../inc/layout.html} +{block body}{/block} + + +{% +for (var a = 0; a < 100; a++) + print(a); +%} + + +{if i === 50} +{elseif i > 60} +{else} +{/if} + + +{for i 1,101} 可自定义名 {for index2 表达式1 in 表达式2} + +{for item,index in items} 可选参数称 index + 可自定义名 {for item2, index99 in 数组表达式} + +{for key,item,index on json} 可选参数 item, index, + 可自定义名 {for key2, item2, index99 in 对象表达式} +{/for} + + +{miss} +此块内容不被bmw.js解析 +{/miss} + + + +``` \ No newline at end of file diff --git a/Templates/SqlServer/simple-entity/Model/for-table.cs.freesql b/Templates/SqlServer/simple-entity/Model/for-table.cs.freesql new file mode 100644 index 00000000..86f7cb7f --- /dev/null +++ b/Templates/SqlServer/simple-entity/Model/for-table.cs.freesql @@ -0,0 +1,33 @@ +{%if (table.Type == DbTableType.StoreProcedure) { + print("return;"); + return rTn; + } + %}using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Newtonsoft.Json; +using FreeSql.DataAnnotations; +{% +var dbf = dbfirst as FreeSql.IDbFirst; +var cols = (table.Columns as List); + +Func UString = stra => stra.Substring(0, 1).ToUpper() + stra.Substring(1); +Func GetCsType = cola3 => { + return dbf.GetCsType(cola3); +}; +%} +namespace test.Model { + + [JsonObject(MemberSerialization.OptIn), Table(Name = "{#!string.IsNullOrEmpty(table.Schema) ? table.Schema + "." : ""}{#table.Name}"{if cols.Where(cola003 => cola003.Name.ToLower() == "is_deleted" || cola003.Name.ToLower() == "isdeleted").Any()}, SelectFilter = "a.IsDeleted = 1"{/if})] + public partial class {#UString(table.Name)} {{for col,index in table.Columns} + {if string.IsNullOrEmpty(col.Coment) == false}/// + /// {#col.Coment.Replace("\r\n", "\n").Replace("\n", "\r\n /// ")} + /// {/if} + [JsonProperty, Column(Name = "{#col.Name}", DbType = "{#col.DbTypeTextFull}"{if col.IsPrimary == true}, IsPrimary = true{/if}{if col.IsIdentity == true}, IsIdentity = true{/if}{if col.IsNullable == true}, IsNullable = true{/if})] + public {#GetCsType(col)} {#UString(col.Name)} { get; set; } + {/for} + } +} \ No newline at end of file diff --git a/Templates/SqlServer/simple-entity/readme.md b/Templates/SqlServer/simple-entity/readme.md new file mode 100644 index 00000000..c95c10a5 --- /dev/null +++ b/Templates/SqlServer/simple-entity/readme.md @@ -0,0 +1,94 @@ +# 生成器 + +生成器是基于 dbfirst 开发的辅助工具,适用老项目一键生成实体。生成器采用模板的方式,作者实现了三种生成模板: + +| 模板名称 | 类型映射 | 外键导航属性 | 缓存管理 | 失血 | 贫血 | 充血 | +| ------------- | - | - |- | - |- | - | +| simple-entity | √ | X | X | √ | X | X | +| simple-entity-navigation-object | √ | √ | X | √ | X | X | +| rich-entity-navigation-object | √ | √ | √ | X | √ | X | + +模板在项目目录:/Templates/MySql + +> 更多模板逐步开发中。。。 + +```csharp +//定义 mysql FreeSql +var mysql = new FreeSql.FreeSqlBuilder() + .UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10") + .Build(); + +//创建模板生成类现实 +var gen = new FreeSql.Generator.TemplateGenerator(); +gen.Build(mysql.DbFirst, + @"C:\Users\28810\Desktop\github\FreeSql\Templates\MySql\simple-entity", //模板目录(事先下载) + @"C:\Users\28810\Desktop\新建文件夹 (9)", //生成后保存的目录 + "cccddd" //数据库 +); +``` + +## 模板语法 + +```html + + +{#title} + + + + +{#表达式} +{##表达式} 当表达式可能发生runtime错误时使用,性能没有上面的高 + + +{include ../header.html} +
+

aaa

+

bbb {#i}

+

ccc {#i}

+
+ + +{module module_name1 parms1, 2, 3...} +{/module} +{module module_name2 parms1, 2, 3...} +{/module} + + +{import ../module.html as myname} +{#myname.module_name(parms1, 2, 3...)} + + +{extends ../inc/layout.html} +{block body}{/block} + + +{% +for (var a = 0; a < 100; a++) + print(a); +%} + + +{if i === 50} +{elseif i > 60} +{else} +{/if} + + +{for i 1,101} 可自定义名 {for index2 表达式1 in 表达式2} + +{for item,index in items} 可选参数称 index + 可自定义名 {for item2, index99 in 数组表达式} + +{for key,item,index on json} 可选参数 item, index, + 可自定义名 {for key2, item2, index99 in 对象表达式} +{/for} + + +{miss} +此块内容不被bmw.js解析 +{/miss} + + + +``` \ No newline at end of file From 4e45bb184e2a8f2f606ee67743715e2b121dca4b Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Wed, 19 Dec 2018 17:06:38 +0800 Subject: [PATCH 4/6] =?UTF-8?q?SqlServer=20=E5=8D=95=E5=85=83=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=20Curd=20=E8=B5=B0=E9=80=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs | 10 +- .../SqlServer/Curd/SqlServerDeleteTest.cs | 73 +++ .../SqlServer/Curd/SqlServerInsertTest.cs | 85 +++ .../SqlServer/Curd/SqlServerSelectTest.cs | 501 ++++++++++++++++++ .../SqlServer/Curd/SqlServerUpdateTest.cs | 107 ++++ .../SqlServerAdo/SqlServerAdoTest.cs | 55 ++ FreeSql.Tests/g.cs | 2 +- FreeSql/Interface/IAdo.cs | 20 +- FreeSql/Internal/CommonExpression.cs | 25 +- .../Internal/CommonProvider/InsertProvider.cs | 2 +- .../Internal/CommonProvider/UpdateProvider.cs | 4 +- FreeSql/MySql/Curd/MySqlDelete.cs | 3 +- FreeSql/MySql/Curd/MySqlInsert.cs | 2 +- FreeSql/MySql/Curd/MySqlUpdate.cs | 20 +- FreeSql/PostgreSQL/Curd/PostgreSQLDelete.cs | 3 +- FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs | 2 +- FreeSql/PostgreSQL/Curd/PostgreSQLUpdate.cs | 24 +- FreeSql/SqlServer/Curd/SqlServerDelete.cs | 3 +- FreeSql/SqlServer/Curd/SqlServerInsert.cs | 4 +- FreeSql/SqlServer/Curd/SqlServerUpdate.cs | 18 +- FreeSql/SqlServer/SqlServerCodeFirst.cs | 12 +- 21 files changed, 933 insertions(+), 42 deletions(-) create mode 100644 FreeSql.Tests/SqlServer/Curd/SqlServerDeleteTest.cs create mode 100644 FreeSql.Tests/SqlServer/Curd/SqlServerInsertTest.cs create mode 100644 FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs create mode 100644 FreeSql.Tests/SqlServer/Curd/SqlServerUpdateTest.cs create mode 100644 FreeSql.Tests/SqlServer/SqlServerAdo/SqlServerAdoTest.cs diff --git a/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs b/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs index 5e2f3e84..bbc0e659 100644 --- a/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs +++ b/FreeSql.Tests/MySql/Curd/MySqlSelectTest.cs @@ -343,9 +343,9 @@ namespace FreeSql.Tests.MySql { query2.ToList(); //������϶����㲻�� - query = select.Where("a.clicks > 100 && a.id = ?id", new { id = 10 }); + query = select.Where("a.clicks > 100 and a.id = ?id", new { id = 10 }); sql = query.ToSql().Replace("\r\n", ""); - Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.clicks > 100 && a.id = ?id)", sql); + Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.clicks > 100 and a.id = ?id)", sql); query.ToList(); } [Fact] @@ -390,9 +390,9 @@ namespace FreeSql.Tests.MySql { query2.ToList(); //������϶����㲻�� - query = select.WhereIf(true, "a.clicks > 100 && a.id = ?id", new { id = 10 }); + query = select.WhereIf(true, "a.clicks > 100 and a.id = ?id", new { id = 10 }); sql = query.ToSql().Replace("\r\n", ""); - Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.clicks > 100 && a.id = ?id)", sql); + Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a WHERE (a.clicks > 100 and a.id = ?id)", sql); query.ToList(); // ==========================================WhereIf(false) @@ -437,7 +437,7 @@ namespace FreeSql.Tests.MySql { query2.ToList(); //������϶����㲻�� - query = select.WhereIf(false, "a.clicks > 100 && a.id = ?id", new { id = 10 }); + query = select.WhereIf(false, "a.clicks > 100 and a.id = ?id", new { id = 10 }); sql = query.ToSql().Replace("\r\n", ""); Assert.Equal("SELECT a.`Id` as1, a.`Clicks` as2, a.`TestTypeInfoGuid` as3, a.`Title` as4, a.`CreateTime` as5 FROM `tb_topic` a", sql); query.ToList(); diff --git a/FreeSql.Tests/SqlServer/Curd/SqlServerDeleteTest.cs b/FreeSql.Tests/SqlServer/Curd/SqlServerDeleteTest.cs new file mode 100644 index 00000000..86b79b56 --- /dev/null +++ b/FreeSql.Tests/SqlServer/Curd/SqlServerDeleteTest.cs @@ -0,0 +1,73 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.SqlServer { + public class SqlServerDeleteTest { + + IDelete delete => g.sqlserver.Delete(); //�������� + + [Table(Name = "tb_topic")] + class Topic { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int Clicks { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + + [Fact] + public void Dywhere() { + Assert.Null(g.sqlserver.Delete().ToSql()); + var sql = g.sqlserver.Delete(new[] { 1, 2 }).ToSql(); + Assert.Equal("DELETE FROM [tb_topic] WHERE ([Id] = 1 OR [Id] = 2)", sql); + + sql = g.sqlserver.Delete(new Topic { Id = 1, Title = "test" }).ToSql(); + Assert.Equal("DELETE FROM [tb_topic] WHERE ([Id] = 1)", sql); + + sql = g.sqlserver.Delete(new[] { new Topic { Id = 1, Title = "test" }, new Topic { Id = 2, Title = "test" } }).ToSql(); + Assert.Equal("DELETE FROM [tb_topic] WHERE ([Id] = 1 OR [Id] = 2)", sql); + + sql = g.sqlserver.Delete(new { id = 1 }).ToSql(); + Assert.Equal("DELETE FROM [tb_topic] WHERE ([Id] = 1)", sql); + } + + [Fact] + public void Where() { + var sql = delete.Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("DELETE FROM [tb_topic] WHERE ([Id] = 1)", sql); + + sql = delete.Where("id = ?id", new { id = 1 }).ToSql().Replace("\r\n", ""); + Assert.Equal("DELETE FROM [tb_topic] WHERE (id = ?id)", sql); + + var item = new Topic { Id = 1, Title = "newtitle" }; + sql = delete.Where(item).ToSql().Replace("\r\n", ""); + Assert.Equal("DELETE FROM [tb_topic] WHERE ([Id] = 1)", sql); + + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); + + sql = delete.Where(items).ToSql().Replace("\r\n", ""); + Assert.Equal("DELETE FROM [tb_topic] WHERE ([Id] IN (1,2,3,4,5,6,7,8,9,10))", sql); + } + [Fact] + public void WhereExists() { + + } + [Fact] + public void ExecuteAffrows() { + + var id = g.sqlserver.Insert(new Topic { Title = "xxxx", CreateTime = DateTime.Now }).ExecuteIdentity(); + Assert.Equal(1, delete.Where(a => a.Id == id).ExecuteAffrows()); + } + [Fact] + public void ExecuteDeleted() { + + var item = g.sqlserver.Insert(new Topic { Title = "xxxx", CreateTime = DateTime.Now }).ExecuteInserted(); + Assert.Equal(item[0].Id, delete.Where(a => a.Id == item[0].Id).ExecuteDeleted()[0].Id); + } + } +} diff --git a/FreeSql.Tests/SqlServer/Curd/SqlServerInsertTest.cs b/FreeSql.Tests/SqlServer/Curd/SqlServerInsertTest.cs new file mode 100644 index 00000000..b60fe033 --- /dev/null +++ b/FreeSql.Tests/SqlServer/Curd/SqlServerInsertTest.cs @@ -0,0 +1,85 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.SqlServer { + public class SqlServerInsertTest { + + IInsert insert => g.sqlserver.Insert(); //�������� + + [Table(Name = "tb_topic")] + class Topic { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int Clicks { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + + [Fact] + public void AppendData() { + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now }); + + var sql = insert.AppendData(items.First()).ToSql(); + Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title], [CreateTime]) VALUES(@Clicks0, @Title0, @CreateTime0)", sql); + + sql = insert.AppendData(items).ToSql(); + Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title], [CreateTime]) VALUES(@Clicks0, @Title0, @CreateTime0), (@Clicks1, @Title1, @CreateTime1), (@Clicks2, @Title2, @CreateTime2), (@Clicks3, @Title3, @CreateTime3), (@Clicks4, @Title4, @CreateTime4), (@Clicks5, @Title5, @CreateTime5), (@Clicks6, @Title6, @CreateTime6), (@Clicks7, @Title7, @CreateTime7), (@Clicks8, @Title8, @CreateTime8), (@Clicks9, @Title9, @CreateTime9)", sql); + + sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql(); + Assert.Equal("INSERT INTO [tb_topic]([Title]) VALUES(@Title0), (@Title1), (@Title2), (@Title3), (@Title4), (@Title5), (@Title6), (@Title7), (@Title8), (@Title9)", sql); + + sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql(); + Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title]) VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql); + } + + [Fact] + public void InsertColumns() { + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now }); + + var sql = insert.AppendData(items).InsertColumns(a => a.Title).ToSql(); + Assert.Equal("INSERT INTO [tb_topic]([Title]) VALUES(@Title0), (@Title1), (@Title2), (@Title3), (@Title4), (@Title5), (@Title6), (@Title7), (@Title8), (@Title9)", sql); + + sql = insert.AppendData(items).InsertColumns(a =>new { a.Title, a.Clicks }).ToSql(); + Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title]) VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql); + } + [Fact] + public void IgnoreColumns() { + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now }); + + var sql = insert.AppendData(items).IgnoreColumns(a => a.CreateTime).ToSql(); + Assert.Equal("INSERT INTO [tb_topic]([Clicks], [Title]) VALUES(@Clicks0, @Title0), (@Clicks1, @Title1), (@Clicks2, @Title2), (@Clicks3, @Title3), (@Clicks4, @Title4), (@Clicks5, @Title5), (@Clicks6, @Title6), (@Clicks7, @Title7), (@Clicks8, @Title8), (@Clicks9, @Title9)", sql); + + sql = insert.AppendData(items).IgnoreColumns(a => new { a.Title, a.CreateTime }).ToSql(); + Assert.Equal("INSERT INTO [tb_topic]([Clicks]) VALUES(@Clicks0), (@Clicks1), (@Clicks2), (@Clicks3), (@Clicks4), (@Clicks5), (@Clicks6), (@Clicks7), (@Clicks8), (@Clicks9)", sql); + } + [Fact] + public void ExecuteAffrows() { + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now }); + + Assert.Equal(1, insert.AppendData(items.First()).ExecuteAffrows()); + Assert.Equal(10, insert.AppendData(items).ExecuteAffrows()); + } + [Fact] + public void ExecuteIdentity() { + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now }); + + Assert.NotEqual(0, insert.AppendData(items.First()).ExecuteIdentity()); + } + [Fact] + public void ExecuteInserted() { + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100, CreateTime = DateTime.Now }); + + var items2 = insert.AppendData(items).ExecuteInserted(); + } + } +} diff --git a/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs b/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs new file mode 100644 index 00000000..ce7d9a2b --- /dev/null +++ b/FreeSql.Tests/SqlServer/Curd/SqlServerSelectTest.cs @@ -0,0 +1,501 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace FreeSql.Tests.SqlServer { + public class SqlServerSelectTest { + + ISelect select => g.sqlserver.Select(); + + [Table(Name = "tb_topic22")] + 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 ToList() { + } + [Fact] + public void ToOne() { + } + [Fact] + public void ToSql() { + } + [Fact] + public void Any() { + var count = select.Where(a => 1 == 1).Count(); + Assert.False(select.Where(a => 1 == 2).Any()); + Assert.Equal(count > 0, select.Where(a => 1 == 1).Any()); + } + [Fact] + public void Count() { + var count = select.Where(a => 1 == 1).Count(); + select.Where(a => 1 == 1).Count(out var count2); + Assert.Equal(count, count2); + Assert.Equal(0, select.Where(a => 1 == 2).Count()); + } + [Fact] + public void Master() { + Assert.StartsWith(" SELECT", select.Master().Where(a => 1 == 1).ToSql()); + } + [Fact] + public void Caching() { + var result1 = select.Where(a => 1 == 1).Caching(20, "testcaching").ToList(); + var testcaching1 = g.sqlserver.Cache.Get("testcaching"); + Assert.NotNull(testcaching1); + var result2 = select.Where(a => 1 == 1).Caching(20, "testcaching").ToList(); + var testcaching2 = g.sqlserver.Cache.Get("testcaching"); + Assert.NotNull(testcaching2); + Assert.Equal(result1.Count, result1.Count); + } + [Fact] + public void From() { + //������� + var query2 = select.From((s, b, c) => s + .LeftJoin(a => a.TestTypeInfoGuid == b.Guid) + .LeftJoin(a => b.ParentId == c.Id) + ); + var sql = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a LEFT JOIN [TestTypeInfo] b ON a.[TestTypeInfoGuid] = b.[Guid] LEFT JOIN [TestTypeParentInfo] c ON b.[ParentId] = c.[Id]", sql); + query2.ToList(); + } + [Fact] + public void LeftJoin() { + //����е�������a.Type��a.Type.Parent ���ǵ������� + var query = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid); + var sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a LEFT JOIN [TestTypeInfo] a__Type ON a__Type.[Guid] = a.[TestTypeInfoGuid]", sql); + query.ToList(); + + query = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid && a.Type.Name == "xxx"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a LEFT JOIN [TestTypeInfo] a__Type ON a__Type.[Guid] = a.[TestTypeInfoGuid] AND a__Type.[Name] = 'xxx'", sql); + query.ToList(); + + query = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid && a.Type.Name == "xxx").Where(a => a.Type.Parent.Id == 10); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a LEFT JOIN [TestTypeParentInfo] a__Type__Parent ON 1 = 1 LEFT JOIN [TestTypeInfo] a__Type ON a__Type.[Guid] = a.[TestTypeInfoGuid] AND a__Type.[Name] = 'xxx' WHERE (a__Type__Parent.[Id] = 10)", sql); + query.ToList(); + + //���û�е������� + query = select.LeftJoin((a, b) => b.Guid == a.TestTypeInfoGuid); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a LEFT JOIN [TestTypeInfo] b ON b.[Guid] = a.[TestTypeInfoGuid]", sql); + query.ToList(); + + query = select.LeftJoin((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "xxx"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a LEFT JOIN [TestTypeInfo] b ON b.[Guid] = a.[TestTypeInfoGuid] AND b.[Name] = 'xxx'", sql); + query.ToList(); + + query = select.LeftJoin((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "xxx").Where(a => a.Type.Parent.Id == 10); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a LEFT JOIN [TestTypeParentInfo] b__Parent ON 1 = 1 LEFT JOIN [TestTypeInfo] b ON b.[Guid] = a.[TestTypeInfoGuid] AND b.[Name] = 'xxx' WHERE (b__Parent.[Id] = 10)", sql); + query.ToList(); + + //������� + query = select + .LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid) + .LeftJoin(a => a.Type.Parent.Id == a.Type.ParentId); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a LEFT JOIN [TestTypeInfo] a__Type ON a__Type.[Guid] = a.[TestTypeInfoGuid] LEFT JOIN [TestTypeParentInfo] a__Type__Parent ON a__Type__Parent.[Id] = a__Type.[ParentId]", sql); + query.ToList(); + + query = select + .LeftJoin((a, b) => b.Guid == a.TestTypeInfoGuid) + .LeftJoin((a, c) => c.Id == a.Type.ParentId); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a LEFT JOIN [TestTypeInfo] b ON b.[Guid] = a.[TestTypeInfoGuid] LEFT JOIN [TestTypeParentInfo] c ON c.[Id] = b.[ParentId]", sql); + query.ToList(); + + //���û�е�������b��c������ϵ + var query2 = select.From((s, b, c) => s + .LeftJoin(a => a.TestTypeInfoGuid == b.Guid) + .LeftJoin(a => b.ParentId == c.Id)); + sql = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a LEFT JOIN [TestTypeInfo] b ON a.[TestTypeInfoGuid] = b.[Guid] LEFT JOIN [TestTypeParentInfo] c ON b.[ParentId] = c.[Id]", sql); + query2.ToList(); + + //������϶����㲻�� + query = select.LeftJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a LEFT JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid", sql); + query.ToList(); + + query = select.LeftJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = @bname", new { bname = "xxx" }); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a LEFT JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = @bname", sql); + query.ToList(); + } + [Fact] + public void InnerJoin() { + //����е�������a.Type��a.Type.Parent ���ǵ������� + var query = select.InnerJoin(a => a.Type.Guid == a.TestTypeInfoGuid); + var sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a INNER JOIN [TestTypeInfo] a__Type ON a__Type.[Guid] = a.[TestTypeInfoGuid]", sql); + query.ToList(); + + query = select.InnerJoin(a => a.Type.Guid == a.TestTypeInfoGuid && a.Type.Name == "xxx"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a INNER JOIN [TestTypeInfo] a__Type ON a__Type.[Guid] = a.[TestTypeInfoGuid] AND a__Type.[Name] = 'xxx'", sql); + query.ToList(); + + query = select.InnerJoin(a => a.Type.Guid == a.TestTypeInfoGuid && a.Type.Name == "xxx").Where(a => a.Type.Parent.Id == 10); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a LEFT JOIN [TestTypeParentInfo] a__Type__Parent ON 1 = 1 INNER JOIN [TestTypeInfo] a__Type ON a__Type.[Guid] = a.[TestTypeInfoGuid] AND a__Type.[Name] = 'xxx' WHERE (a__Type__Parent.[Id] = 10)", sql); + query.ToList(); + + //���û�е������� + query = select.InnerJoin((a, b) => b.Guid == a.TestTypeInfoGuid); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a INNER JOIN [TestTypeInfo] b ON b.[Guid] = a.[TestTypeInfoGuid]", sql); + query.ToList(); + + query = select.InnerJoin((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "xxx"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a INNER JOIN [TestTypeInfo] b ON b.[Guid] = a.[TestTypeInfoGuid] AND b.[Name] = 'xxx'", sql); + query.ToList(); + + query = select.InnerJoin((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "xxx").Where(a => a.Type.Parent.Id == 10); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a LEFT JOIN [TestTypeParentInfo] b__Parent ON 1 = 1 INNER JOIN [TestTypeInfo] b ON b.[Guid] = a.[TestTypeInfoGuid] AND b.[Name] = 'xxx' WHERE (b__Parent.[Id] = 10)", sql); + query.ToList(); + + //������� + query = select + .InnerJoin(a => a.Type.Guid == a.TestTypeInfoGuid) + .InnerJoin(a => a.Type.Parent.Id == a.Type.ParentId); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a INNER JOIN [TestTypeInfo] a__Type ON a__Type.[Guid] = a.[TestTypeInfoGuid] INNER JOIN [TestTypeParentInfo] a__Type__Parent ON a__Type__Parent.[Id] = a__Type.[ParentId]", sql); + query.ToList(); + + query = select + .InnerJoin((a, b) => b.Guid == a.TestTypeInfoGuid) + .InnerJoin((a, c) => c.Id == a.Type.ParentId); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a INNER JOIN [TestTypeInfo] b ON b.[Guid] = a.[TestTypeInfoGuid] INNER JOIN [TestTypeParentInfo] c ON c.[Id] = b.[ParentId]", sql); + query.ToList(); + + //���û�е�������b��c������ϵ + var query2 = select.From((s, b, c) => s + .InnerJoin(a => a.TestTypeInfoGuid == b.Guid) + .InnerJoin(a => b.ParentId == c.Id)); + sql = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a INNER JOIN [TestTypeInfo] b ON a.[TestTypeInfoGuid] = b.[Guid] INNER JOIN [TestTypeParentInfo] c ON b.[ParentId] = c.[Id]", sql); + query2.ToList(); + + //������϶����㲻�� + query = select.InnerJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a INNER JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid", sql); + query.ToList(); + + query = select.InnerJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = @bname", new { bname = "xxx" }); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a INNER JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = @bname", sql); + query.ToList(); + + } + [Fact] + public void RightJoin() { + //����е�������a.Type��a.Type.Parent ���ǵ������� + var query = select.RightJoin(a => a.Type.Guid == a.TestTypeInfoGuid); + var sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a RIGHT JOIN [TestTypeInfo] a__Type ON a__Type.[Guid] = a.[TestTypeInfoGuid]", sql); + query.ToList(); + + query = select.RightJoin(a => a.Type.Guid == a.TestTypeInfoGuid && a.Type.Name == "xxx"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a RIGHT JOIN [TestTypeInfo] a__Type ON a__Type.[Guid] = a.[TestTypeInfoGuid] AND a__Type.[Name] = 'xxx'", sql); + query.ToList(); + + query = select.RightJoin(a => a.Type.Guid == a.TestTypeInfoGuid && a.Type.Name == "xxx").Where(a => a.Type.Parent.Id == 10); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a LEFT JOIN [TestTypeParentInfo] a__Type__Parent ON 1 = 1 RIGHT JOIN [TestTypeInfo] a__Type ON a__Type.[Guid] = a.[TestTypeInfoGuid] AND a__Type.[Name] = 'xxx' WHERE (a__Type__Parent.[Id] = 10)", sql); + query.ToList(); + + //���û�е������� + query = select.RightJoin((a, b) => b.Guid == a.TestTypeInfoGuid); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a RIGHT JOIN [TestTypeInfo] b ON b.[Guid] = a.[TestTypeInfoGuid]", sql); + query.ToList(); + + query = select.RightJoin((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "xxx"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a RIGHT JOIN [TestTypeInfo] b ON b.[Guid] = a.[TestTypeInfoGuid] AND b.[Name] = 'xxx'", sql); + query.ToList(); + + query = select.RightJoin((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "xxx").Where(a => a.Type.Parent.Id == 10); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a LEFT JOIN [TestTypeParentInfo] b__Parent ON 1 = 1 RIGHT JOIN [TestTypeInfo] b ON b.[Guid] = a.[TestTypeInfoGuid] AND b.[Name] = 'xxx' WHERE (b__Parent.[Id] = 10)", sql); + query.ToList(); + + //������� + query = select + .RightJoin(a => a.Type.Guid == a.TestTypeInfoGuid) + .RightJoin(a => a.Type.Parent.Id == a.Type.ParentId); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a RIGHT JOIN [TestTypeInfo] a__Type ON a__Type.[Guid] = a.[TestTypeInfoGuid] RIGHT JOIN [TestTypeParentInfo] a__Type__Parent ON a__Type__Parent.[Id] = a__Type.[ParentId]", sql); + query.ToList(); + + query = select + .RightJoin((a, b) => b.Guid == a.TestTypeInfoGuid) + .RightJoin((a, c) => c.Id == a.Type.ParentId); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a RIGHT JOIN [TestTypeInfo] b ON b.[Guid] = a.[TestTypeInfoGuid] RIGHT JOIN [TestTypeParentInfo] c ON c.[Id] = b.[ParentId]", sql); + query.ToList(); + + //���û�е�������b��c������ϵ + var query2 = select.From((s, b, c) => s + .RightJoin(a => a.TestTypeInfoGuid == b.Guid) + .RightJoin(a => b.ParentId == c.Id)); + sql = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a RIGHT JOIN [TestTypeInfo] b ON a.[TestTypeInfoGuid] = b.[Guid] RIGHT JOIN [TestTypeParentInfo] c ON b.[ParentId] = c.[Id]", sql); + query2.ToList(); + + //������϶����㲻�� + query = select.RightJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a RIGHT JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid", sql); + query.ToList(); + + query = select.RightJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = @bname", new { bname = "xxx" }); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a RIGHT JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = @bname", sql); + query.ToList(); + + } + [Fact] + public void Where() { + //����е�������a.Type��a.Type.Parent ���ǵ������� + var query = select.Where(a => a.Id == 10); + var sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a WHERE (a.[Id] = 10)", sql); + query.ToList(); + + query = select.Where(a => a.Id == 10 && a.Id > 10 || a.Clicks > 100); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a WHERE (a.[Id] = 10 AND a.[Id] > 10 OR a.[Clicks] > 100)", sql); + query.ToList(); + + query = select.Where(a => a.Id == 10).Where(a => a.Clicks > 100); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a WHERE (a.[Id] = 10) AND (a.[Clicks] > 100)", sql); + query.ToList(); + + query = select.Where(a => a.Type.Name == "typeTitle"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a, [TestTypeInfo] a__Type WHERE (a__Type.[Name] = 'typeTitle')", sql); + query.ToList(); + + query = select.Where(a => a.Type.Name == "typeTitle" && a.Type.Guid == a.TestTypeInfoGuid); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a, [TestTypeInfo] a__Type WHERE (a__Type.[Name] = 'typeTitle' AND a__Type.[Guid] = a.[TestTypeInfoGuid])", sql); + query.ToList(); + + query = select.Where(a => a.Type.Parent.Name == "tparent"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a, [TestTypeInfo] a__Type, [TestTypeParentInfo] a__Type__Parent WHERE (a__Type__Parent.[Name] = 'tparent')", sql); + query.ToList(); + + //���û�е������ԣ��򵥶������ + query = select.Where((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "typeTitle"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a, [TestTypeInfo] b WHERE (b.[Guid] = a.[TestTypeInfoGuid] AND b.[Name] = 'typeTitle')", sql); + query.ToList(); + + query = select.Where((a, b) => b.Name == "typeTitle" && b.Guid == a.TestTypeInfoGuid); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a, [TestTypeInfo] b WHERE (b.[Name] = 'typeTitle' AND b.[Guid] = a.[TestTypeInfoGuid])", sql); + query.ToList(); + + query = select.Where((a, b, c) => c.Name == "tparent"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a, [TestTypeParentInfo] c WHERE (c.[Name] = 'tparent')", sql); + query.ToList(); + + //����һ�� From ��Ķ������ + var query2 = select.From((s, b, c) => s + .Where(a => a.Id == 10 && c.Name == "xxx") + .Where(a => b.ParentId == 20)); + sql = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a, [TestTypeParentInfo] c, [TestTypeInfo] b WHERE (a.[Id] = 10 AND c.[Name] = 'xxx') AND (b.[ParentId] = 20)", sql); + query2.ToList(); + + //������϶����㲻�� + query = select.Where("a.clicks > 100 and a.id = @id", new { id = 10 }); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a WHERE (a.clicks > 100 and a.id = @id)", sql); + query.ToList(); + } + [Fact] + public void WhereIf() { + //����е�������a.Type��a.Type.Parent ���ǵ������� + var query = select.WhereIf(true, a => a.Id == 10); + var sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a WHERE (a.[Id] = 10)", sql); + query.ToList(); + + query = select.WhereIf(true, a => a.Id == 10 && a.Id > 10 || a.Clicks > 100); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a WHERE (a.[Id] = 10 AND a.[Id] > 10 OR a.[Clicks] > 100)", sql); + query.ToList(); + + query = select.WhereIf(true, a => a.Id == 10).WhereIf(true, a => a.Clicks > 100); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a WHERE (a.[Id] = 10) AND (a.[Clicks] > 100)", sql); + query.ToList(); + + query = select.WhereIf(true, a => a.Type.Name == "typeTitle"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a, [TestTypeInfo] a__Type WHERE (a__Type.[Name] = 'typeTitle')", sql); + query.ToList(); + + query = select.WhereIf(true, a => a.Type.Name == "typeTitle" && a.Type.Guid == a.TestTypeInfoGuid); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a, [TestTypeInfo] a__Type WHERE (a__Type.[Name] = 'typeTitle' AND a__Type.[Guid] = a.[TestTypeInfoGuid])", sql); + query.ToList(); + + query = select.WhereIf(true, a => a.Type.Parent.Name == "tparent"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("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_topic22] a, [TestTypeInfo] a__Type, [TestTypeParentInfo] a__Type__Parent WHERE (a__Type__Parent.[Name] = 'tparent')", sql); + query.ToList(); + + //����һ�� From ��Ķ������ + var query2 = select.From((s, b, c) => s + .WhereIf(true, a => a.Id == 10 && c.Name == "xxx") + .WhereIf(true, a => b.ParentId == 20)); + sql = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, b.[Guid] as4, b.[ParentId] as5, b.[Name] as6, a.[Title] as7, a.[CreateTime] as8 FROM [tb_topic22] a, [TestTypeParentInfo] c, [TestTypeInfo] b WHERE (a.[Id] = 10 AND c.[Name] = 'xxx') AND (b.[ParentId] = 20)", sql); + query2.ToList(); + + //������϶����㲻�� + query = select.WhereIf(true, "a.clicks > 100 and a.id = @id", new { id = 10 }); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a WHERE (a.clicks > 100 and a.id = @id)", sql); + query.ToList(); + + // ==========================================WhereIf(false) + + //����е�������a.Type��a.Type.Parent ���ǵ������� + query = select.WhereIf(false, a => a.Id == 10); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a", sql); + query.ToList(); + + query = select.WhereIf(false, a => a.Id == 10 && a.Id > 10 || a.Clicks > 100); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a", sql); + query.ToList(); + + query = select.WhereIf(false, a => a.Id == 10).WhereIf(false, a => a.Clicks > 100); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a", sql); + query.ToList(); + + query = select.WhereIf(false, a => a.Type.Name == "typeTitle"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a", sql); + query.ToList(); + + query = select.WhereIf(false, a => a.Type.Name == "typeTitle" && a.Type.Guid == a.TestTypeInfoGuid); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a", sql); + query.ToList(); + + query = select.WhereIf(false, a => a.Type.Parent.Name == "tparent"); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a", sql); + query.ToList(); + + //����һ�� From ��Ķ������ + query2 = select.From((s, b, c) => s + .WhereIf(false, a => a.Id == 10 && c.Name == "xxx") + .WhereIf(false, a => b.ParentId == 20)); + sql = query2.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a", sql); + query2.ToList(); + + //������϶����㲻�� + query = select.WhereIf(false, "a.clicks > 100 and a.id = @id", new { id = 10 }); + sql = query.ToSql().Replace("\r\n", ""); + Assert.Equal("SELECT a.[Id] as1, a.[Clicks] as2, a.[TestTypeInfoGuid] as3, a.[Title] as4, a.[CreateTime] as5 FROM [tb_topic22] a", sql); + query.ToList(); + } + [Fact] + public void WhereLike() { + //ģ����ѯ��WhereLike(a => a.Title, "%sql") + var query = select.Where(a => a.Title.StartsWith("ss")).Where(a => a.Type.Name.Contains("sss")); + var sql = query.ToSql().Replace("\r\n", ""); + + query = select.Where(a => a.Title.EndsWith("ss")); + sql = query.ToSql().Replace("\r\n", ""); + + query = select.Where(a => a.Title.Contains("ss")); + sql = query.ToSql().Replace("\r\n", ""); + + query = select.WhereLike(a => a.Title, "%ss"); + sql = query.ToSql().Replace("\r\n", ""); + + query = select.WhereLike(a => a.Title, "%ss").WhereLike(a => a.Title, "%aa"); + sql = query.ToSql().Replace("\r\n", ""); + + //ģ����ѯ��ѡ������ OR��WhereLike(a => new[] { a.Title, a.Content }, "%sql%") + query = select.WhereLike(a => new[] { a.Title, a.Type.Name, a.Type.Parent.Name }, "%aa"); + sql = query.ToSql().Replace("\r\n", ""); + } + [Fact] + public void GroupBy() { + } + [Fact] + public void Having() { + } + [Fact] + public void OrderBy() { + } + [Fact] + public void Skip_Offset() { + } + [Fact] + public void Take_Limit() { + } + [Fact] + public void Page() { + } + [Fact] + public void Sum() { + } + [Fact] + public void Min() { + } + [Fact] + public void Max() { + } + [Fact] + public void Avg() { + } + [Fact] + public void As() { + } + } +} diff --git a/FreeSql.Tests/SqlServer/Curd/SqlServerUpdateTest.cs b/FreeSql.Tests/SqlServer/Curd/SqlServerUpdateTest.cs new file mode 100644 index 00000000..3775b110 --- /dev/null +++ b/FreeSql.Tests/SqlServer/Curd/SqlServerUpdateTest.cs @@ -0,0 +1,107 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using Xunit; + +namespace FreeSql.Tests.SqlServer { + public class SqlServerUpdateTest { + IUpdate update => g.sqlserver.Update(); + + [Table(Name = "tb_topic")] + class Topic { + [Column(IsIdentity = true, IsPrimary = true)] + public int Id { get; set; } + public int? Clicks { get; set; } + public TestTypeInfo Type { get; set; } + public string Title { get; set; } + public DateTime CreateTime { get; set; } + } + + [Fact] + public void Dywhere() { + Assert.Null(g.sqlserver.Update().ToSql()); + Assert.Equal("UPDATE [tb_topic] SET title='test' \r\nWHERE ([Id] = 1 OR [Id] = 2)", g.sqlserver.Update(new[] { 1, 2 }).SetRaw("title='test'").ToSql()); + Assert.Equal("UPDATE [tb_topic] SET title='test1' \r\nWHERE ([Id] = 1)", g.sqlserver.Update(new Topic { Id = 1, Title = "test" }).SetRaw("title='test1'").ToSql()); + Assert.Equal("UPDATE [tb_topic] SET title='test1' \r\nWHERE ([Id] = 1 OR [Id] = 2)", g.sqlserver.Update(new[] { new Topic { Id = 1, Title = "test" }, new Topic { Id = 2, Title = "test" } }).SetRaw("title='test1'").ToSql()); + Assert.Equal("UPDATE [tb_topic] SET title='test1' \r\nWHERE ([Id] = 1)", g.sqlserver.Update(new { id = 1 }).SetRaw("title='test1'").ToSql()); + } + + [Fact] + public void SetSource() { + var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET [Clicks] = @p_0, [Title] = @p_1, [CreateTime] = @p_2 WHERE ([Id] = 1)", sql); + + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); + + sql = update.SetSource(items).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET [Clicks] = CASE [Id] WHEN 1 THEN @p_0 WHEN 2 THEN @p_1 WHEN 3 THEN @p_2 WHEN 4 THEN @p_3 WHEN 5 THEN @p_4 WHEN 6 THEN @p_5 WHEN 7 THEN @p_6 WHEN 8 THEN @p_7 WHEN 9 THEN @p_8 WHEN 10 THEN @p_9 END, [Title] = CASE [Id] WHEN 1 THEN @p_10 WHEN 2 THEN @p_11 WHEN 3 THEN @p_12 WHEN 4 THEN @p_13 WHEN 5 THEN @p_14 WHEN 6 THEN @p_15 WHEN 7 THEN @p_16 WHEN 8 THEN @p_17 WHEN 9 THEN @p_18 WHEN 10 THEN @p_19 END, [CreateTime] = CASE [Id] WHEN 1 THEN @p_20 WHEN 2 THEN @p_21 WHEN 3 THEN @p_22 WHEN 4 THEN @p_23 WHEN 5 THEN @p_24 WHEN 6 THEN @p_25 WHEN 7 THEN @p_26 WHEN 8 THEN @p_27 WHEN 9 THEN @p_28 WHEN 10 THEN @p_29 END WHERE ([Id] IN (1,2,3,4,5,6,7,8,9,10))", sql); + + sql = update.SetSource(items).IgnoreColumns(a => new { a.Clicks, a.CreateTime }).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET [Title] = CASE [Id] WHEN 1 THEN @p_0 WHEN 2 THEN @p_1 WHEN 3 THEN @p_2 WHEN 4 THEN @p_3 WHEN 5 THEN @p_4 WHEN 6 THEN @p_5 WHEN 7 THEN @p_6 WHEN 8 THEN @p_7 WHEN 9 THEN @p_8 WHEN 10 THEN @p_9 END WHERE ([Id] IN (1,2,3,4,5,6,7,8,9,10))", sql); + + sql = update.SetSource(items).Set(a => a.CreateTime, new DateTime(2020,1,1)).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET [CreateTime] = @p_0 WHERE ([Id] IN (1,2,3,4,5,6,7,8,9,10))", sql); + } + [Fact] + public void IgnoreColumns() { + var sql = update.SetSource(new Topic { Id = 1, Title = "newtitle" }).IgnoreColumns(a => new { a.Clicks, a.CreateTime }).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET [Title] = @p_0 WHERE ([Id] = 1)", sql); + } + [Fact] + public void Set() { + var sql = update.Where(a => a.Id == 1).Set(a => a.Title, "newtitle").ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET [Title] = @p_0 WHERE ([Id] = 1)", sql); + + sql = update.Where(a => a.Id == 1).Set(a => a.Title, "newtitle").Set(a => a.CreateTime, new DateTime(2020, 1, 1)).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET [Title] = @p_0, [CreateTime] = @p_1 WHERE ([Id] = 1)", sql); + + sql = update.Set(a => a.Clicks * 10 / 1).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET [Clicks] = isnull([Clicks], 0) * 10 / 1 WHERE ([Id] = 1)", sql); + + sql = update.Set(a => a.Id - 10).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET [Id] = [Id] - 10 WHERE ([Id] = 1)", sql); + + int incrv = 10; + sql = update.Set(a => a.Clicks * incrv / 1).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET [Clicks] = isnull([Clicks], 0) * 10 / 1 WHERE ([Id] = 1)", sql); + + sql = update.Set(a => a.Id - incrv).Where(a => a.Id == 1).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET [Id] = [Id] - 10 WHERE ([Id] = 1)", sql); + } + [Fact] + public void SetRaw() { + var sql = update.Where(a => a.Id == 1).SetRaw("clicks = clicks + @incrClick", new { incrClick = 1 }).ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET clicks = clicks + @incrClick WHERE ([Id] = 1)", sql); + } + [Fact] + public void Where() { + var sql = update.Where(a => a.Id == 1).SetRaw("title='newtitle'").ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET title='newtitle' WHERE ([Id] = 1)", sql); + + sql = update.Where("id = @id", new { id = 1 }).SetRaw("title='newtitle'").ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET title='newtitle' WHERE (id = @id)", sql); + + var item = new Topic { Id = 1, Title = "newtitle" }; + sql = update.Where(item).SetRaw("title='newtitle'").ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET title='newtitle' WHERE ([Id] = 1)", sql); + + var items = new List(); + for (var a = 0; a < 10; a++) items.Add(new Topic { Id = a + 1, Title = $"newtitle{a}", Clicks = a * 100 }); + sql = update.Where(items).SetRaw("title='newtitle'").ToSql().Replace("\r\n", ""); + Assert.Equal("UPDATE [tb_topic] SET title='newtitle' WHERE ([Id] IN (1,2,3,4,5,6,7,8,9,10))", sql); + } + [Fact] + public void WhereExists() { + + } + [Fact] + public void ExecuteAffrows() { + + } + [Fact] + public void ExecuteUpdated() { + + } + } +} diff --git a/FreeSql.Tests/SqlServer/SqlServerAdo/SqlServerAdoTest.cs b/FreeSql.Tests/SqlServer/SqlServerAdo/SqlServerAdoTest.cs new file mode 100644 index 00000000..4970d9be --- /dev/null +++ b/FreeSql.Tests/SqlServer/SqlServerAdo/SqlServerAdoTest.cs @@ -0,0 +1,55 @@ +using FreeSql.DataAnnotations; +using System; +using Xunit; + +namespace FreeSql.Tests.SqlServer { + public class SqlServerAdoTest { + [Fact] + public void Pool() { + var t1 = g.sqlserver.Ado.MasterPool.StatisticsFullily; + } + + [Fact] + public void SlavePools() { + var t2 = g.sqlserver.Ado.SlavePools.Count; + } + + [Fact] + public void IsTracePerformance() { + Assert.True(g.sqlserver.Ado.IsTracePerformance); + } + + [Fact] + public void ExecuteReader() { + + } + [Fact] + public void ExecuteArray() { + + } + [Fact] + public void ExecuteNonQuery() { + + } + [Fact] + public void ExecuteScalar() { + + } + + [Fact] + public void Query() { + var t3 = g.sqlserver.Ado.Query("select * from song"); + + var t4 = g.sqlserver.Ado.Query<(int, string, string, DateTime)>("select * from song"); + + var t5 = g.sqlserver.Ado.Query("select * from song"); + } + + class xxx { + public int Id { get; set; } + public string Title { get; set; } + public string Url { get; set; } + public DateTime Create_time { get; set; } + } + } +} diff --git a/FreeSql.Tests/g.cs b/FreeSql.Tests/g.cs index 1f7f39b0..471df841 100644 --- a/FreeSql.Tests/g.cs +++ b/FreeSql.Tests/g.cs @@ -10,6 +10,6 @@ public class g { .Build(); public static IFreeSql sqlserver = new FreeSql.FreeSqlBuilder() - .UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=shop;Pooling=true;Max Pool Size=10") + .UseConnectionString(FreeSql.DataType.SqlServer, "Data Source=.;Integrated Security=True;Initial Catalog=cms;Pooling=true;Max Pool Size=10") .Build(); } diff --git a/FreeSql/Interface/IAdo.cs b/FreeSql/Interface/IAdo.cs index facc2e02..cee3ec4a 100644 --- a/FreeSql/Interface/IAdo.cs +++ b/FreeSql/Interface/IAdo.cs @@ -80,6 +80,15 @@ namespace FreeSql { /// object ExecuteScalar(CommandType cmdType, string cmdText, params DbParameter[] cmdParms); + /// + /// 执行SQL返回对象集合,Query<User>("select * from user where age > @age", new SqlParameter { ParameterName = "age", Value = 25 }) + /// + /// + /// + /// + /// + /// + List Query(CommandType cmdType, string cmdText, params DbParameter[] cmdParms); /// /// 执行SQL返回对象集合,Query<User>("select * from user where age > @age", new { age = 25 }) /// @@ -126,7 +135,16 @@ namespace FreeSql { Task ExecuteScalarAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms); /// - /// 执行SQL返回对象集合,Query<User>("select * from user where age > @age", new { age = 25 }) + /// 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new SqlParameter { ParameterName = "age", Value = 25 }) + /// + /// + /// + /// + /// + /// + Task> QueryAsync(CommandType cmdType, string cmdText, params DbParameter[] cmdParms); + /// + /// 执行SQL返回对象集合,QueryAsync<User>("select * from user where age > @age", new { age = 25 }) /// /// /// diff --git a/FreeSql/Internal/CommonExpression.cs b/FreeSql/Internal/CommonExpression.cs index 8c149cf3..b8c27ef9 100644 --- a/FreeSql/Internal/CommonExpression.cs +++ b/FreeSql/Internal/CommonExpression.cs @@ -113,15 +113,36 @@ namespace FreeSql.Internal { { ExpressionType.Equal, "=" }, }; internal string ExpressionWhereLambdaNoneForeignObject(List _tables, List _selectColumnMap, Expression exp) { - return ExpressionLambdaToSql(exp, _tables, _selectColumnMap, SelectTableInfoType.From, true); + var sql = ExpressionLambdaToSql(exp, _tables, _selectColumnMap, SelectTableInfoType.From, true); + switch(sql) { + case "1": + case "'t'": return "1=1"; + case "0": + case "'f'": return "1=2"; + default:return sql; + } } internal string ExpressionWhereLambda(List _tables, Expression exp) { - return ExpressionLambdaToSql(exp, _tables, null, SelectTableInfoType.From, true); + var sql = ExpressionLambdaToSql(exp, _tables, null, SelectTableInfoType.From, true); + switch (sql) { + case "1": + case "'t'": return "1=1"; + case "0": + case "'f'": return "1=2"; + default: return sql; + } } internal void ExpressionJoinLambda(List _tables, SelectTableInfoType tbtype, Expression exp) { var tbidx = _tables.Count; var filter = ExpressionLambdaToSql(exp, _tables, null, tbtype, true); + switch (filter) { + case "1": + case "'t'": filter = "1=1"; break; + case "0": + case "'f'": filter = "1=2"; break; + default: break; + } if (_tables.Count > tbidx) { _tables[tbidx].Type = tbtype; _tables[tbidx].On = filter; diff --git a/FreeSql/Internal/CommonProvider/InsertProvider.cs b/FreeSql/Internal/CommonProvider/InsertProvider.cs index 10bfd4d0..0cab0b54 100644 --- a/FreeSql/Internal/CommonProvider/InsertProvider.cs +++ b/FreeSql/Internal/CommonProvider/InsertProvider.cs @@ -76,7 +76,7 @@ namespace FreeSql.Internal.CommonProvider { foreach (var col in _table.Columns.Values) if (col.Attribute.IsIdentity == false && _ignore.ContainsKey(col.Attribute.Name) == false) { if (colidx2 > 0) sb.Append(", "); - sb.Append("?").Append(col.CsName).Append(didx); + sb.Append(_commonUtils.QuoteParamterName(col.CsName)).Append(didx); _params[didx * colidx + colidx2] = _commonUtils.AppendParamter(null, $"{col.CsName}{didx}", _table.Properties.TryGetValue(col.CsName, out var tryp) ? tryp.GetValue(d) : DBNull.Value); ++colidx2; } diff --git a/FreeSql/Internal/CommonProvider/UpdateProvider.cs b/FreeSql/Internal/CommonProvider/UpdateProvider.cs index 29a21cc2..7d6e8768 100644 --- a/FreeSql/Internal/CommonProvider/UpdateProvider.cs +++ b/FreeSql/Internal/CommonProvider/UpdateProvider.cs @@ -54,7 +54,7 @@ namespace FreeSql.Internal.CommonProvider { public IUpdate Set(Expression> column, TMember value) { var col = _commonExpression.ExpressionSelectColumn_MemberAccess(null, null, SelectTableInfoType.From, column?.Body, true); if (string.IsNullOrEmpty(col)) return this; - _set.Append(", ").Append(col).Append(" = ?p_").Append(_params.Count); + _set.Append(", ").Append(col).Append(" = ").Append(_commonUtils.QuoteParamterName("p_")).Append(_params.Count); _commonUtils.AppendParamter(_params, null, value); //foreach (var t in _source) Utils.FillPropertyValue(t, tryf.CsName, value); return this; @@ -135,7 +135,7 @@ namespace FreeSql.Internal.CommonProvider { // ++pkidx; //} //if (_table.Primarys.Length > 1) caseWhen.Append(")"); - var cw = caseWhen.Append(" ").ToString(); + var cw = caseWhen.ToString(); _paramsSource.Clear(); var colidx = 0; diff --git a/FreeSql/MySql/Curd/MySqlDelete.cs b/FreeSql/MySql/Curd/MySqlDelete.cs index 37ff0a0a..194ce951 100644 --- a/FreeSql/MySql/Curd/MySqlDelete.cs +++ b/FreeSql/MySql/Curd/MySqlDelete.cs @@ -1,5 +1,6 @@ using FreeSql.Internal; using System.Collections.Generic; +using System.Data; using System.Text; namespace FreeSql.MySql.Curd { @@ -19,7 +20,7 @@ namespace FreeSql.MySql.Curd { sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); ++colidx; } - return _orm.Ado.Query(sb.ToString()); + return _orm.Ado.Query(CommandType.Text, sb.ToString(), _params.ToArray()); } } } diff --git a/FreeSql/MySql/Curd/MySqlInsert.cs b/FreeSql/MySql/Curd/MySqlInsert.cs index 01176154..1dc2a935 100644 --- a/FreeSql/MySql/Curd/MySqlInsert.cs +++ b/FreeSql/MySql/Curd/MySqlInsert.cs @@ -22,7 +22,7 @@ namespace FreeSql.MySql.Curd { sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); ++colidx; } - return _orm.Ado.Query(sb.ToString()); + return _orm.Ado.Query(CommandType.Text, sb.ToString(), _params); } } } diff --git a/FreeSql/MySql/Curd/MySqlUpdate.cs b/FreeSql/MySql/Curd/MySqlUpdate.cs index 0da7600e..e3f11422 100644 --- a/FreeSql/MySql/Curd/MySqlUpdate.cs +++ b/FreeSql/MySql/Curd/MySqlUpdate.cs @@ -1,6 +1,8 @@ using FreeSql.Internal; using FreeSql.Internal.Model; using System.Collections.Generic; +using System.Data; +using System.Linq; using System.Text; namespace FreeSql.MySql.Curd { @@ -21,29 +23,37 @@ namespace FreeSql.MySql.Curd { sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); ++colidx; } - return _orm.Ado.Query(sb.ToString()); + return _orm.Ado.Query(CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray()); } protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys) { - if (_table.Primarys.Length > 1) caseWhen.Append("CONCAT("); + if (_table.Primarys.Length == 1) { + caseWhen.Append(_commonUtils.QuoteSqlName(_table.Primarys.First().Attribute.Name)); + return; + } + caseWhen.Append("CONCAT("); var pkidx = 0; foreach (var pk in _table.Primarys) { if (pkidx > 0) caseWhen.Append(", "); caseWhen.Append(_commonUtils.QuoteSqlName(pk.Attribute.Name)); ++pkidx; } - if (_table.Primarys.Length > 1) caseWhen.Append(")"); + caseWhen.Append(")"); } protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d) { - if (_table.Primarys.Length > 1) sb.Append("CONCAT("); + if (_table.Primarys.Length == 1) { + sb.Append(_commonUtils.FormatSql("{0}", _table.Properties.TryGetValue(_table.Primarys.First().CsName, out var tryp2) ? tryp2.GetValue(d) : null)); + return; + } + sb.Append("CONCAT("); var pkidx = 0; foreach (var pk in _table.Primarys) { if (pkidx > 0) sb.Append(", "); sb.Append(_commonUtils.FormatSql("{0}", _table.Properties.TryGetValue(pk.CsName, out var tryp2) ? tryp2.GetValue(d) : null)); ++pkidx; } - if (_table.Primarys.Length > 1) sb.Append(")"); + sb.Append(")"); } } } diff --git a/FreeSql/PostgreSQL/Curd/PostgreSQLDelete.cs b/FreeSql/PostgreSQL/Curd/PostgreSQLDelete.cs index 4473fab8..a36edef9 100644 --- a/FreeSql/PostgreSQL/Curd/PostgreSQLDelete.cs +++ b/FreeSql/PostgreSQL/Curd/PostgreSQLDelete.cs @@ -1,5 +1,6 @@ using FreeSql.Internal; using System.Collections.Generic; +using System.Data; using System.Text; namespace FreeSql.PostgreSQL.Curd { @@ -19,7 +20,7 @@ namespace FreeSql.PostgreSQL.Curd { sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); ++colidx; } - return _orm.Ado.Query(sb.ToString()); + return _orm.Ado.Query(CommandType.Text, sb.ToString(), _params.ToArray()); } } } diff --git a/FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs b/FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs index 470fa434..45bad8d3 100644 --- a/FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs +++ b/FreeSql/PostgreSQL/Curd/PostgreSQLInsert.cs @@ -24,7 +24,7 @@ namespace FreeSql.PostgreSQL.Curd { sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); ++colidx; } - return _orm.Ado.Query(sb.ToString()); + return _orm.Ado.Query(CommandType.Text, sb.ToString(), _params); } } } diff --git a/FreeSql/PostgreSQL/Curd/PostgreSQLUpdate.cs b/FreeSql/PostgreSQL/Curd/PostgreSQLUpdate.cs index c1eb1d4a..ec2278fa 100644 --- a/FreeSql/PostgreSQL/Curd/PostgreSQLUpdate.cs +++ b/FreeSql/PostgreSQL/Curd/PostgreSQLUpdate.cs @@ -1,6 +1,8 @@ using FreeSql.Internal; using FreeSql.Internal.Model; using System.Collections.Generic; +using System.Data; +using System.Linq; using System.Text; namespace FreeSql.PostgreSQL.Curd { @@ -21,29 +23,37 @@ namespace FreeSql.PostgreSQL.Curd { sb.Append(_commonUtils.QuoteSqlName(col.Attribute.Name)).Append(" as ").Append(_commonUtils.QuoteSqlName(col.CsName)); ++colidx; } - return _orm.Ado.Query(sb.ToString()); + return _orm.Ado.Query(CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray()); } protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys) { - if (_table.Primarys.Length > 1) caseWhen.Append("("); + if (_table.Primarys.Length == 1) { + caseWhen.Append(_commonUtils.QuoteSqlName(_table.Primarys.First().Attribute.Name)); + return; + } + caseWhen.Append("("); var pkidx = 0; foreach (var pk in _table.Primarys) { - if (pkidx > 0) caseWhen.Append(", "); + if (pkidx > 0) caseWhen.Append(" || "); caseWhen.Append(_commonUtils.QuoteSqlName(pk.Attribute.Name)).Append("::varchar"); ++pkidx; } - if (_table.Primarys.Length > 1) caseWhen.Append(")"); + caseWhen.Append(")"); } protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d) { - if (_table.Primarys.Length > 1) sb.Append("("); + if (_table.Primarys.Length == 1) { + sb.Append(_commonUtils.FormatSql("{0}", _table.Properties.TryGetValue(_table.Primarys.First().CsName, out var tryp2) ? tryp2.GetValue(d) : null)); + return; + } + sb.Append("("); var pkidx = 0; foreach (var pk in _table.Primarys) { - if (pkidx > 0) sb.Append(", "); + if (pkidx > 0) sb.Append(" || "); sb.Append(_commonUtils.FormatSql("{0}", _table.Properties.TryGetValue(pk.CsName, out var tryp2) ? tryp2.GetValue(d) : null)).Append("::varchar"); ++pkidx; } - if (_table.Primarys.Length > 1) sb.Append(")"); + sb.Append(")"); } } } diff --git a/FreeSql/SqlServer/Curd/SqlServerDelete.cs b/FreeSql/SqlServer/Curd/SqlServerDelete.cs index ace43780..1502b154 100644 --- a/FreeSql/SqlServer/Curd/SqlServerDelete.cs +++ b/FreeSql/SqlServer/Curd/SqlServerDelete.cs @@ -1,6 +1,7 @@ using FreeSql.Internal; using System; using System.Collections.Generic; +using System.Data; using System.Text; namespace FreeSql.SqlServer.Curd { @@ -28,7 +29,7 @@ namespace FreeSql.SqlServer.Curd { sb.Insert(0, sql.Substring(0, validx)); sb.Append(sql.Substring(validx)); - return _orm.Ado.Query(sb.ToString()); + return _orm.Ado.Query(CommandType.Text, sb.ToString(), _params.ToArray()); } } } diff --git a/FreeSql/SqlServer/Curd/SqlServerInsert.cs b/FreeSql/SqlServer/Curd/SqlServerInsert.cs index c02fde4d..24bc6819 100644 --- a/FreeSql/SqlServer/Curd/SqlServerInsert.cs +++ b/FreeSql/SqlServer/Curd/SqlServerInsert.cs @@ -28,10 +28,10 @@ namespace FreeSql.SqlServer.Curd { var validx = sql.IndexOf(") VALUES"); if (validx == -1) throw new ArgumentException("找不到 VALUES"); - sb.Insert(0, sql.Substring(0, validx)).Insert(0, ")"); + sb.Insert(0, sql.Substring(0, validx + 1)); sb.Append(sql.Substring(validx + 1)); - return _orm.Ado.Query(sb.ToString()); + return _orm.Ado.Query(CommandType.Text, sb.ToString(), _params); } } } diff --git a/FreeSql/SqlServer/Curd/SqlServerUpdate.cs b/FreeSql/SqlServer/Curd/SqlServerUpdate.cs index 4d51a7ca..6139c8fc 100644 --- a/FreeSql/SqlServer/Curd/SqlServerUpdate.cs +++ b/FreeSql/SqlServer/Curd/SqlServerUpdate.cs @@ -2,6 +2,8 @@ using FreeSql.Internal.Model; using System; using System.Collections.Generic; +using System.Data; +using System.Linq; using System.Text; namespace FreeSql.SqlServer.Curd { @@ -30,29 +32,35 @@ namespace FreeSql.SqlServer.Curd { sb.Insert(0, sql.Substring(0, validx)); sb.Append(sql.Substring(validx)); - return _orm.Ado.Query(sb.ToString()); + return _orm.Ado.Query(CommandType.Text, sb.ToString(), _params.Concat(_paramsSource).ToArray()); } protected override void ToSqlCase(StringBuilder caseWhen, ColumnInfo[] primarys) { - if (_table.Primarys.Length > 1) caseWhen.Append("("); + if (_table.Primarys.Length == 1) { + caseWhen.Append(_commonUtils.QuoteSqlName(_table.Primarys.First().Attribute.Name)); + return; + } + caseWhen.Append("("); var pkidx = 0; foreach (var pk in _table.Primarys) { if (pkidx > 0) caseWhen.Append(", "); caseWhen.Append("cast(").Append(_commonUtils.QuoteSqlName(pk.Attribute.Name)).Append(" as varchar)"); ++pkidx; } - if (_table.Primarys.Length > 1) caseWhen.Append(")"); + caseWhen.Append(")"); } protected override void ToSqlWhen(StringBuilder sb, ColumnInfo[] primarys, object d) { - if (_table.Primarys.Length > 1) sb.Append("("); + if (_table.Primarys.Length == 1) { + sb.Append(_commonUtils.FormatSql("{0}", _table.Properties.TryGetValue(_table.Primarys.First().CsName, out var tryp2) ? tryp2.GetValue(d) : null)); + return; + } var pkidx = 0; foreach (var pk in _table.Primarys) { if (pkidx > 0) sb.Append(", "); sb.Append("cast(").Append(_commonUtils.FormatSql("{0}", _table.Properties.TryGetValue(pk.CsName, out var tryp2) ? tryp2.GetValue(d) : null)).Append(" as varchar)"); ++pkidx; } - if (_table.Primarys.Length > 1) sb.Append(")"); } } } diff --git a/FreeSql/SqlServer/SqlServerCodeFirst.cs b/FreeSql/SqlServer/SqlServerCodeFirst.cs index 8d648818..3777c7d2 100644 --- a/FreeSql/SqlServer/SqlServerCodeFirst.cs +++ b/FreeSql/SqlServer/SqlServerCodeFirst.cs @@ -85,7 +85,7 @@ namespace FreeSql.SqlServer { if (tboldname != null && _orm.Ado.ExecuteScalar(CommandType.Text, string.Format("select 1 from dbo.sysobjects where id = object_id(N'[{0}].[{1}]') and OBJECTPROPERTY(id, N'IsUserTable') = 1", tboldname)) != null) { //旧表存在 //修改表名 - sb.Append(_commonUtils.FormatSql("EXEC sp_rename {0}, {1} \r\nGO \r\n", _commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}"), _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"))); + sb.Append(_commonUtils.FormatSql("EXEC sp_rename {0}, {1};\r\n", _commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}"), _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"))); isRenameTable = true; } else { @@ -98,7 +98,7 @@ namespace FreeSql.SqlServer { if (tbcol.Attribute.IsPrimary) sb.Append(" primary key"); sb.Append(","); } - sb.Remove(sb.Length - 1, 1).Append("\r\n) \r\nGO \r\n"); + sb.Remove(sb.Length - 1, 1).Append("\r\n);\r\n"); continue; } } @@ -137,7 +137,7 @@ where a.object_id in (object_id(N'[{0}].[{1}]'))", isRenameTable ? tboldname : t trycol.Attribute.IsIdentity != is_identity) { sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(column)).Append(" ").Append(trycol.Attribute.DbType.ToUpper()); if (trycol.Attribute.IsIdentity && trycol.Attribute.DbType.IndexOf("identity", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" identity(1,1)"); - sb.Append(" \r\nGO \r\n"); + sb.Append(";\r\n"); } addcols.Remove(column); } else @@ -145,15 +145,15 @@ where a.object_id in (object_id(N'[{0}].[{1}]'))", isRenameTable ? tboldname : t } foreach (var addcol in addcols.Values) { if (string.IsNullOrEmpty(addcol.Attribute.OldName) == false && surplus.ContainsKey(addcol.Attribute.OldName)) { //修改列名 - sb.Append(_commonUtils.FormatSql("EXEC sp_rename {0}, {1}, 'COLUMN' \r\nGO \r\n", $"{tbname[0]}.{tbname[1]}.{addcol.Attribute.OldName}", addcol.Attribute.Name)); + sb.Append(_commonUtils.FormatSql("EXEC sp_rename {0}, {1}, 'COLUMN';\r\n", $"{tbname[0]}.{tbname[1]}.{addcol.Attribute.OldName}", addcol.Attribute.Name)); sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ALTER COLUMN ").Append(_commonUtils.QuoteSqlName(addcol.Attribute.Name)).Append(" ").Append(addcol.Attribute.DbType.ToUpper()); if (addcol.Attribute.IsIdentity && addcol.Attribute.DbType.IndexOf("identity", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" identity(1,1)"); - sb.Append(" \r\nGO \r\n"); + sb.Append(";\r\n"); } else { //添加列 sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD ").Append(_commonUtils.QuoteSqlName(addcol.Attribute.Name)).Append(" ").Append(addcol.Attribute.DbType.ToUpper()); if (addcol.Attribute.IsIdentity && addcol.Attribute.DbType.IndexOf("identity", StringComparison.CurrentCultureIgnoreCase) == -1) sb.Append(" identity(1,1)"); - sb.Append(" \r\nGO \r\n"); + sb.Append(";\r\n"); } } } From 6f8a047149cb630af2c09066859965718b36b187 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Wed, 19 Dec 2018 19:34:52 +0800 Subject: [PATCH 5/6] =?UTF-8?q?pgsql=20CodeFirst=20=E9=80=82=E9=85=8D?= =?UTF-8?q?=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- FreeSql/DatabaseModel/DbEnumInfo.cs | 18 ++++ FreeSql/DatabaseModel/DbTypeInfo.cs | 18 ++++ FreeSql/Interface/iDbFirst.cs | 7 ++ FreeSql/Internal/Utils.cs | 23 +++-- FreeSql/MySql/MySqlDbFirst.cs | 4 + FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs | 120 ++++++++++++++-------- FreeSql/PostgreSQL/PostgreSQLDbFirst.cs | 20 ++++ FreeSql/SqlServer/SqlServerDbFirst.cs | 4 + 8 files changed, 164 insertions(+), 50 deletions(-) create mode 100644 FreeSql/DatabaseModel/DbEnumInfo.cs create mode 100644 FreeSql/DatabaseModel/DbTypeInfo.cs diff --git a/FreeSql/DatabaseModel/DbEnumInfo.cs b/FreeSql/DatabaseModel/DbEnumInfo.cs new file mode 100644 index 00000000..bd237cf8 --- /dev/null +++ b/FreeSql/DatabaseModel/DbEnumInfo.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace FreeSql.DatabaseModel { + public class DbEnumInfo { + + /// + /// 枚举类型标识 + /// + public string Name { get; set; } + + /// + /// 枚举项 + /// + public Dictionary Labels { get; set; } + } +} diff --git a/FreeSql/DatabaseModel/DbTypeInfo.cs b/FreeSql/DatabaseModel/DbTypeInfo.cs new file mode 100644 index 00000000..2440283d --- /dev/null +++ b/FreeSql/DatabaseModel/DbTypeInfo.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace FreeSql.DatabaseModel { + public class DbTypeInfo { + + /// + /// 类型标识 + /// + public string Name { get; set; } + + /// + /// 枚举项 + /// + public List<(string label, string value)> Labels { get; set; } + } +} diff --git a/FreeSql/Interface/iDbFirst.cs b/FreeSql/Interface/iDbFirst.cs index 96604795..ac8f0fbd 100644 --- a/FreeSql/Interface/iDbFirst.cs +++ b/FreeSql/Interface/iDbFirst.cs @@ -66,5 +66,12 @@ namespace FreeSql { /// /// string GetCsParse(DbColumnInfo column); + + /// + /// 获取数据库枚举类型,适用 PostgreSQL + /// + /// + /// + List GetEnumsByDatabase(params string[] database); } } diff --git a/FreeSql/Internal/Utils.cs b/FreeSql/Internal/Utils.cs index 76c46087..e8fb0fa7 100644 --- a/FreeSql/Internal/Utils.cs +++ b/FreeSql/Internal/Utils.cs @@ -27,17 +27,20 @@ namespace FreeSql.Internal { trytb.SelectFilter = tbattr?.SelectFilter; foreach (var p in trytb.Properties.Values) { var tp = common.CodeFirst.GetDbInfo(p.PropertyType); - if (tp == null) continue; - var colattr = p.GetCustomAttributes(typeof(ColumnAttribute), false).LastOrDefault() as ColumnAttribute ?? new ColumnAttribute { - Name = p.Name, - DbType = tp.Value.dbtypeFull, - IsIdentity = false, - IsNullable = tp.Value.isnullable ?? false, - IsPrimary = false, - }; + //if (tp == null) continue; + var colattr = p.GetCustomAttributes(typeof(ColumnAttribute), false).LastOrDefault() as ColumnAttribute; + if (tp == null && colattr == null) continue; + if (colattr == null) + colattr = new ColumnAttribute { + Name = p.Name, + DbType = tp.Value.dbtypeFull, + IsIdentity = false, + IsNullable = tp.Value.isnullable ?? false, + IsPrimary = false, + }; if (string.IsNullOrEmpty(colattr.Name)) colattr.Name = p.Name; - if (string.IsNullOrEmpty(colattr.DbType)) colattr.DbType = tp.Value.dbtypeFull; - if (colattr.DbType.IndexOf("NOT NULL") == -1 && tp.Value.isnullable == false) colattr.DbType += " NOT NULL"; + if (string.IsNullOrEmpty(colattr.DbType)) colattr.DbType = tp?.dbtypeFull ?? "varchar(255)"; + if (colattr.DbType.IndexOf("NOT NULL") == -1 && tp?.isnullable == false) colattr.DbType += " NOT NULL"; var col = new ColumnInfo { Table = trytb, diff --git a/FreeSql/MySql/MySqlDbFirst.cs b/FreeSql/MySql/MySqlDbFirst.cs index 455e27ae..5221bed1 100644 --- a/FreeSql/MySql/MySqlDbFirst.cs +++ b/FreeSql/MySql/MySqlDbFirst.cs @@ -373,5 +373,9 @@ where a.constraint_schema in ({1}) and a.table_name in ({0}) and not isnull(posi loc3.Clear(); return loc1; } + + public List GetEnumsByDatabase(params string[] database) { + return new List(); + } } } \ No newline at end of file diff --git a/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs b/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs index 668979e6..2d4991ce 100644 --- a/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs +++ b/FreeSql/PostgreSQL/PostgreSQLCodeFirst.cs @@ -1,11 +1,16 @@ using FreeSql.DatabaseModel; using FreeSql.Internal; using FreeSql.Internal.Model; +using Newtonsoft.Json.Linq; +using Npgsql.LegacyPostgis; using NpgsqlTypes; using System; +using System.Collections; using System.Collections.Generic; using System.Data; using System.Linq; +using System.Net; +using System.Net.NetworkInformation; using System.Text; namespace FreeSql.PostgreSQL { @@ -22,58 +27,90 @@ namespace FreeSql.PostgreSQL { public bool IsAutoSyncStructure { get; set; } = true; - static readonly Dictionary _dicCsToDb = new Dictionary() { + static object _dicCsToDbLock = new object(); + static Dictionary _dicCsToDb = new Dictionary() { - { "System.Int16", (NpgsqlDbType.Smallint, "int2","int2 NOT NULL", false, false) },{ "System.Nullable`1[System.Int16]", (NpgsqlDbType.Smallint, "int2", "int2", false, true) }, - { "System.Int32", (NpgsqlDbType.Integer, "int4","int4 NOT NULL", false, false) },{ "System.Nullable`1[System.Int32]", (NpgsqlDbType.Integer, "int4", "int4", false, true) }, - { "System.Int64", (NpgsqlDbType.Bigint, "int8","int8 NOT NULL", false, false) },{ "System.Nullable`1[System.Int64]", (NpgsqlDbType.Bigint, "int8", "int8", false, true) }, + { typeof(sbyte).FullName, (NpgsqlDbType.Smallint, "int2","int2 NOT NULL", false, false) },{ typeof(sbyte?).FullName, (NpgsqlDbType.Smallint, "int2", "int2", false, true) }, + { typeof(short).FullName, (NpgsqlDbType.Smallint, "int2","int2 NOT NULL", false, false) },{ typeof(short?).FullName, (NpgsqlDbType.Smallint, "int2", "int2", false, true) }, + { typeof(int).FullName, (NpgsqlDbType.Integer, "int4","int4 NOT NULL", false, false) },{ typeof(int?).FullName, (NpgsqlDbType.Integer, "int4", "int4", false, true) }, + { typeof(long).FullName, (NpgsqlDbType.Bigint, "int8","int8 NOT NULL", false, false) },{ typeof(long?).FullName, (NpgsqlDbType.Bigint, "int8", "int8", false, true) }, - { "System.Single", (NpgsqlDbType.Real, "float4","float4 NOT NULL", false, false) },{ "System.Nullable`1[System.Single]", (NpgsqlDbType.Real, "float4", "float4", false, true) }, - { "System.Double", (NpgsqlDbType.Double, "float8","float8 NOT NULL", false, false) },{ "System.Nullable`1[System.Double]", (NpgsqlDbType.Double, "float8", "float8", false, true) }, - { "System.Decimal", (NpgsqlDbType.Numeric, "numeric", "numeric(10,2) NOT NULL", false, false) },{ "System.Nullable`1[System.Decimal]", (NpgsqlDbType.Numeric, "numeric", "numeric(10,2)", false, true) }, + { typeof(byte).FullName, (NpgsqlDbType.Smallint, "int2","int2 NOT NULL", false, false) },{ typeof(byte?).FullName, (NpgsqlDbType.Smallint, "int2", "int2", false, true) }, + { typeof(ushort).FullName, (NpgsqlDbType.Smallint, "int2","int2 NOT NULL", false, false) },{ typeof(ushort?).FullName, (NpgsqlDbType.Smallint, "int2", "int2", false, true) }, + { typeof(uint).FullName, (NpgsqlDbType.Integer, "int4","int4 NOT NULL", false, false) },{ typeof(uint?).FullName, (NpgsqlDbType.Integer, "int4", "int4", false, true) }, + { typeof(ulong).FullName, (NpgsqlDbType.Bigint, "int8","int8 NOT NULL", false, false) },{ typeof(ulong?).FullName, (NpgsqlDbType.Bigint, "int8", "int8", false, true) }, - { "System.String", (NpgsqlDbType.Varchar, "varchar", "varchar(255)", false, null) }, + { typeof(float).FullName, (NpgsqlDbType.Real, "float4","float4 NOT NULL", false, false) },{ typeof(float?).FullName, (NpgsqlDbType.Real, "float4", "float4", false, true) }, + { typeof(double).FullName, (NpgsqlDbType.Double, "float8","float8 NOT NULL", false, false) },{ typeof(double?).FullName, (NpgsqlDbType.Double, "float8", "float8", false, true) }, + { typeof(decimal).FullName, (NpgsqlDbType.Numeric, "numeric", "numeric(10,2) NOT NULL", false, false) },{ typeof(decimal?).FullName, (NpgsqlDbType.Numeric, "numeric", "numeric(10,2)", false, true) }, - { "System.TimeSpan", (NpgsqlDbType.Time, "time","time NOT NULL", false, false) },{ "System.Nullable`1[System.TimeSpan]", (NpgsqlDbType.Time, "time", "time",false, true) }, - { "System.DateTime", (NpgsqlDbType.Timestamp, "timestamp", "timestamp NOT NULL", false, false) },{ "System.Nullable`1[System.DateTime]", (NpgsqlDbType.Timestamp, "timestamp", "timestamp", false, true) }, + { typeof(string).FullName, (NpgsqlDbType.Varchar, "varchar", "varchar(255)", false, null) }, - { "System.Boolean", (NpgsqlDbType.Boolean, "bool","bool NOT NULL", null, false) },{ "System.Nullable`1[System.Boolean]", (NpgsqlDbType.Bit, "bool","bool", null, true) }, - { "System.Byte[]", (NpgsqlDbType.Bytea, "bytea", "bytea", false, null) }, - { "System.BitArray", (NpgsqlDbType.Varbit, "varbit", "varbit(255)", false, null) }, + { typeof(TimeSpan).FullName, (NpgsqlDbType.Time, "time","time NOT NULL", false, false) },{ typeof(TimeSpan?).FullName, (NpgsqlDbType.Time, "time", "time",false, true) }, + { typeof(DateTime).FullName, (NpgsqlDbType.Timestamp, "timestamp", "timestamp NOT NULL", false, false) },{ typeof(DateTime?).FullName, (NpgsqlDbType.Timestamp, "timestamp", "timestamp", false, true) }, - { "NpgsqlTypes.NpgsqlPoint", (NpgsqlDbType.Point, "point", "point", false, false) },{ "System.Nullable`1[NpgsqlTypes.NpgsqlPoint]", (NpgsqlDbType.Point, "point", "point", false, true) }, - { "NpgsqlTypes.NpgsqlLine", (NpgsqlDbType.Line, "line", "line", false, false) },{ "System.Nullable`1[NpgsqlTypes.NpgsqlLine]", (NpgsqlDbType.Line, "line", "line", false, true) }, - { "NpgsqlTypes.NpgsqlLSeg", (NpgsqlDbType.LSeg, "lseg", "lseg", false, false) },{ "System.Nullable`1[NpgsqlTypes.NpgsqlLSeg]", (NpgsqlDbType.LSeg, "lseg", "lseg", false, true) }, - { "NpgsqlTypes.NpgsqlBox", (NpgsqlDbType.Box, "box", "box", false, false) },{ "System.Nullable`1[NpgsqlTypes.NpgsqlBox]", (NpgsqlDbType.Box, "box", "box", false, true) }, - { "NpgsqlTypes.NpgsqlPath", (NpgsqlDbType.Path, "path", "path", false, false) },{ "System.Nullable`1[NpgsqlTypes.NpgsqlPath]", (NpgsqlDbType.Path, "path", "path", false, true) }, - { "NpgsqlTypes.NpgsqlPolygon", (NpgsqlDbType.Polygon, "polygon", "polygon", false, false) },{ "System.Nullable`1[NpgsqlTypes.NpgsqlPolygon]", (NpgsqlDbType.Polygon, "polygon", "polygon", false, true) }, - { "NpgsqlTypes.NpgsqlCircle", (NpgsqlDbType.Circle, "circle", "circle", false, false) },{ "System.Nullable`1[NpgsqlTypes.NpgsqlCircle]", (NpgsqlDbType.Circle, "circle", "circle", false, true) }, + { typeof(bool).FullName, (NpgsqlDbType.Boolean, "bool","bool NOT NULL", null, false) },{ typeof(bool?).FullName, (NpgsqlDbType.Bit, "bool","bool", null, true) }, + { typeof(Byte[]).FullName, (NpgsqlDbType.Bytea, "bytea", "bytea", false, null) }, + { typeof(BitArray).FullName, (NpgsqlDbType.Varbit, "varbit", "varbit(64)", false, null) }, - { "System.ValueTuple`2[[System.Net.IPAddress, System.Int32]]", (NpgsqlDbType.Cidr, "cidr", "cidr", false, false) },{ "System.Nullable`1[System.ValueTuple`2[[System.Net.IPAddress, System.Int32]]]", (NpgsqlDbType.Cidr, "cidr", "cidr", false, true) }, - { "System.Net.IPAddress", (NpgsqlDbType.Inet, "inet", "inet", false, null) }, - { "System.Net.NetworkInformation.PhysicalAddress", (NpgsqlDbType.MacAddr, "macaddr", "macaddr", false, null) }, + { typeof(NpgsqlPoint).FullName, (NpgsqlDbType.Point, "point", "point NOT NULL", false, false) },{ typeof(NpgsqlPoint?).FullName, (NpgsqlDbType.Point, "point", "point", false, true) }, + { typeof(NpgsqlLine).FullName, (NpgsqlDbType.Line, "line", "line NOT NULL", false, false) },{ typeof(NpgsqlLine?).FullName, (NpgsqlDbType.Line, "line", "line", false, true) }, + { typeof(NpgsqlLSeg).FullName, (NpgsqlDbType.LSeg, "lseg", "lseg NOT NULL", false, false) },{ typeof(NpgsqlLSeg?).FullName, (NpgsqlDbType.LSeg, "lseg", "lseg", false, true) }, + { typeof(NpgsqlBox).FullName, (NpgsqlDbType.Box, "box", "box NOT NULL", false, false) },{ typeof(NpgsqlBox?).FullName, (NpgsqlDbType.Box, "box", "box", false, true) }, + { typeof(NpgsqlPath).FullName, (NpgsqlDbType.Path, "path", "path NOT NULL", false, false) },{ typeof(NpgsqlPath?).FullName, (NpgsqlDbType.Path, "path", "path", false, true) }, + { typeof(NpgsqlPolygon).FullName, (NpgsqlDbType.Polygon, "polygon", "polygon NOT NULL", false, false) },{ typeof(NpgsqlPolygon?).FullName, (NpgsqlDbType.Polygon, "polygon", "polygon", false, true) }, + { typeof(NpgsqlCircle).FullName, (NpgsqlDbType.Circle, "circle", "circle NOT NULL", false, false) },{ typeof(NpgsqlCircle?).FullName, (NpgsqlDbType.Circle, "circle", "circle", false, true) }, - { "Newtonsoft.Json.Linq.JToken", (NpgsqlDbType.Jsonb, "jsonb", "jsonb", false, null) }, - { "Newtonsoft.Json.Linq.JObject", (NpgsqlDbType.Jsonb, "jsonb", "jsonb", false, null) }, - { "Newtonsoft.Json.Linq.JArray", (NpgsqlDbType.Jsonb, "jsonb", "jsonb", false, null) }, - { "System.Guid", (NpgsqlDbType.Uuid, "uuid", "uuid", false, false) },{ "System.Nullable`1[System.Guid]", (NpgsqlDbType.Uuid, "uuid", "uuid", false, true) }, + { typeof((IPAddress Address, int Subnet)).FullName, (NpgsqlDbType.Cidr, "cidr", "cidr NOT NULL", false, false) },{ typeof((IPAddress Address, int Subnet)?).FullName, (NpgsqlDbType.Cidr, "cidr", "cidr", false, true) }, + { typeof(IPAddress).FullName, (NpgsqlDbType.Inet, "inet", "inet", false, null) }, + { typeof(PhysicalAddress).FullName, (NpgsqlDbType.MacAddr, "macaddr", "macaddr", false, null) }, - { "NpgsqlTypes.NpgsqlRange", (NpgsqlDbType.Range | NpgsqlDbType.Integer, "int4range", "int4range", false, false) },{ "System.Nullable`1[NpgsqlTypes.NpgsqlRange]", (NpgsqlDbType.Range | NpgsqlDbType.Integer, "int4range", "int4range", false, true) }, - { "NpgsqlTypes.NpgsqlRange", (NpgsqlDbType.Range | NpgsqlDbType.Bigint, "int8range", "int8range", false, false) },{ "System.Nullable`1[NpgsqlTypes.NpgsqlRange]", (NpgsqlDbType.Range | NpgsqlDbType.Bigint, "int8range", "int8range", false, true) }, - { "NpgsqlTypes.NpgsqlRange", (NpgsqlDbType.Range | NpgsqlDbType.Numeric, "numrange", "numrange", false, false) },{ "System.Nullable`1[NpgsqlTypes.NpgsqlRange]", (NpgsqlDbType.Range | NpgsqlDbType.Numeric, "numrange", "numrange", false, true) }, - { "NpgsqlTypes.NpgsqlRange", (NpgsqlDbType.Range | NpgsqlDbType.Timestamp, "tsrange", "tsrange", false, false) },{ "System.Nullable`1[NpgsqlTypes.NpgsqlRange]", (NpgsqlDbType.Range | NpgsqlDbType.Timestamp, "tsrange", "tsrange", false, true) }, + { typeof(JToken).FullName, (NpgsqlDbType.Jsonb, "jsonb", "jsonb", false, null) }, + { typeof(JObject).FullName, (NpgsqlDbType.Jsonb, "jsonb", "jsonb", false, null) }, + { typeof(JArray).FullName, (NpgsqlDbType.Jsonb, "jsonb", "jsonb", false, null) }, + { typeof(Guid).FullName, (NpgsqlDbType.Uuid, "uuid", "uuid NOT NULL", false, false) },{ typeof(Guid?).FullName, (NpgsqlDbType.Uuid, "uuid", "uuid", false, true) }, - { "Dictionary", (NpgsqlDbType.Hstore, "hstore", "hstore", false, null) }, - { "Npgsql.LegacyPostgis.PostgisGeometry", (NpgsqlDbType.Geometry, "geometry", "geometry", false, null) }, + { typeof(NpgsqlRange).FullName, (NpgsqlDbType.Range | NpgsqlDbType.Integer, "int4range", "int4range NOT NULL", false, false) },{ typeof(NpgsqlRange?).FullName, (NpgsqlDbType.Range | NpgsqlDbType.Integer, "int4range", "int4range", false, true) }, + { typeof(NpgsqlRange).FullName, (NpgsqlDbType.Range | NpgsqlDbType.Bigint, "int8range", "int8range NOT NULL", false, false) },{ typeof(NpgsqlRange?).FullName, (NpgsqlDbType.Range | NpgsqlDbType.Bigint, "int8range", "int8range", false, true) }, + { typeof(NpgsqlRange).FullName, (NpgsqlDbType.Range | NpgsqlDbType.Numeric, "numrange", "numrange NOT NULL", false, false) },{ typeof(NpgsqlRange?).FullName, (NpgsqlDbType.Range | NpgsqlDbType.Numeric, "numrange", "numrange", false, true) }, + { typeof(NpgsqlRange).FullName, (NpgsqlDbType.Range | NpgsqlDbType.Timestamp, "tsrange", "tsrange NOT NULL", false, false) },{ typeof(NpgsqlRange?).FullName, (NpgsqlDbType.Range | NpgsqlDbType.Timestamp, "tsrange", "tsrange", false, true) }, + + { typeof(Dictionary).FullName, (NpgsqlDbType.Hstore, "hstore", "hstore", false, null) }, + { typeof(PostgisPoint).FullName, (NpgsqlDbType.Geometry, "geometry", "geometry", false, null) }, + { typeof(PostgisLineString).FullName, (NpgsqlDbType.Geometry, "geometry", "geometry", false, null) }, + { typeof(PostgisPolygon).FullName, (NpgsqlDbType.Geometry, "geometry", "geometry", false, null) }, + { typeof(PostgisMultiPoint).FullName, (NpgsqlDbType.Geometry, "geometry", "geometry", false, null) }, + { typeof(PostgisMultiLineString).FullName, (NpgsqlDbType.Geometry, "geometry", "geometry", false, null) }, + { typeof(PostgisMultiPolygon).FullName, (NpgsqlDbType.Geometry, "geometry", "geometry", false, null) }, + { typeof(PostgisGeometry).FullName, (NpgsqlDbType.Geometry, "geometry", "geometry", false, null) }, + { typeof(PostgisGeometryCollection).FullName, (NpgsqlDbType.Geometry, "geometry", "geometry", false, null) }, }; public (int type, string dbtype, string dbtypeFull, bool? isnullable)? GetDbInfo(Type type) { + var elementType = type.IsArray ? type.GetElementType() : type; + var info = GetDbInfoNoneArray(elementType); + if (info == null) return null; + if (type.IsArray == false) return ((int)info.Value.type, info.Value.dbtype, info.Value.dbtypeFull, info.Value.isnullable); + var dbype = $"{info.Value.dbtype}[]"; + return ((int)(info.Value.type | NpgsqlDbType.Array), dbype, info.Value.dbtypeFull.Replace(info.Value.dbtype, dbype), info.Value.isnullable); + } + (NpgsqlDbType type, string dbtype, string dbtypeFull, bool? isnullable)? GetDbInfoNoneArray(Type type) { + if (_dicCsToDb.TryGetValue(type.FullName, out var trydc)) return new (NpgsqlDbType, string, string, bool?)?((trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable)); var enumType = type.IsEnum ? type : null; if (enumType == null && type.FullName.StartsWith("System.Nullable`1[") && type.GenericTypeArguments.Length == 1 && type.GenericTypeArguments.First().IsEnum) enumType = type.GenericTypeArguments.First(); if (enumType != null) { - return ((int)NpgsqlDbType.Integer, "int4", $"int4{(type.IsEnum ? " NOT NULL" : "")}", type.IsEnum ? false : true); + 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); + if (_dicCsToDb.ContainsKey(type.FullName) == false) { + lock (_dicCsToDbLock) { + if (_dicCsToDb.ContainsKey(type.FullName) == false) + _dicCsToDb.Add(type.FullName, newItem); + } + } + return (newItem.Item1, newItem.Item2, newItem.Item3, newItem.Item5); } - return _dicCsToDb.TryGetValue(type.FullName, out var trydc) ? new (int, string, string, bool?)?(((int)trydc.type, trydc.dbtype, trydc.dbtypeFull, trydc.isnullable)) : null; + return null; } public string GetComparisonDDLStatements() => this.GetComparisonDDLStatements(typeof(TEntity)); @@ -88,9 +125,9 @@ namespace FreeSql.PostgreSQL { var isRenameTable = false; var tbname = tb.DbName.Split(new[] { '.' }, 2); if (tbname.Length == 1) tbname = new[] { "public", tbname[0] }; - if (_orm.Ado.ExecuteScalar(CommandType.Text, "select 1 from pg_tables a inner join pg_namespace b on b.nspname = a.schemaname where b.nspname || '.' || a.tablename = {0}.{1}".FormatMySql(tbname)) == null) { //表不存在 + if (_orm.Ado.ExecuteScalar(CommandType.Text, "select 1 from pg_tables a inner join pg_namespace b on b.nspname = a.schemaname where b.nspname || '.' || a.tablename = {0}.{1}".FormatPostgreSQL(tbname)) == null) { //表不存在 - if (tboldname != null && _orm.Ado.ExecuteScalar(CommandType.Text, "select 1 from pg_tables a inner join pg_namespace b on b.nspname = a.schemaname where b.nspname || '.' || a.tablename = {0}.{1}".FormatMySql(tboldname)) != null) { //旧表存在 + if (tboldname != null && _orm.Ado.ExecuteScalar(CommandType.Text, "select 1 from pg_tables a inner join pg_namespace b on b.nspname = a.schemaname where b.nspname || '.' || a.tablename = {0}.{1}".FormatPostgreSQL(tboldname)) != null) { //旧表存在 //修改表名 sb.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}")).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(";\r\n"); isRenameTable = true; @@ -126,8 +163,9 @@ a.attname, t.typname, case when a.atttypmod > 0 and a.atttypmod < 32767 then a.atttypmod - 4 else a.attlen end len, case when t.typelem = 0 then t.typname else t2.typname end, -case when a.attnotnull then 0 else 1 end as is_nullable, -e.adsrc as is_identity +case when a.attnotnull then '0' else '1' end as is_nullable, +case when e.adsrc = 1 then '1' else '0' end as is_identity, +a.attndims from pg_class c inner join pg_attribute a on a.attnum > 0 and a.attrelid = c.oid inner join pg_type t on t.oid = a.atttypid @@ -136,7 +174,7 @@ left join pg_description d on d.objoid = a.attrelid and d.objsubid = a.attnum left join pg_attrdef e on e.adrelid = a.attrelid and e.adnum = a.attnum inner join pg_namespace ns on ns.oid = c.relnamespace inner join pg_namespace ns2 on ns2.oid = t.typnamespace -where ns.nspname = {0} and c.relname = {1}".FormatMySql(isRenameTable ? tboldname : tbname); +where ns.nspname = {0} and c.relname = {1}".FormatPostgreSQL(isRenameTable ? tboldname : tbname); var ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); foreach (var row in ds) { string column = string.Concat(row[0]); @@ -144,6 +182,8 @@ where ns.nspname = {0} and c.relname = {1}".FormatMySql(isRenameTable ? tboldnam long max_length = long.Parse(string.Concat(row[2])); bool is_nullable = string.Concat(row[4]) == "1"; bool is_identity = string.Concat(row[5]).StartsWith(@"nextval('") && string.Concat(row[6]).EndsWith(@"_seq'::regclass)"); + var attndims = long.Parse(string.Concat(row[6])); + if (attndims > 0) sqlType += "[]"; if (addcols.TryGetValue(column, out var trycol)) { if (trycol.Attribute.DbType.ToLower().StartsWith(sqlType.ToLower()) == false || diff --git a/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs b/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs index 4325abf3..d48cedb5 100644 --- a/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs +++ b/FreeSql/PostgreSQL/PostgreSQLDbFirst.cs @@ -372,5 +372,25 @@ where a.constraint_schema in ({1}) and a.table_name in ({0}) and not isnull(posi loc3.Clear(); return loc1; } + + public List GetEnumsByDatabase(params string[] database) { + if (database == null || database.Length == 0) return new List(); + var drs = _orm.Ado.Query<(string name, string label)>(CommandType.Text, @"select +ns.nspname || '.' || a.typname, +b.enumlabel +from pg_type a +inner join pg_enum b on b.enumtypid = a.oid +inner join pg_namespace ns on ns.oid = a.typnamespace +where a.typtype = 'e' and ns.nspname in (SELECT ""schema_name"" FROM information_schema.schemata where catalog_name in {0})".FormatPostgreSQL(database)); + var ret = new Dictionary>(); + foreach (var dr in drs) { + if (ret.TryGetValue(dr.name, out var labels) == false) ret.Add(dr.name, labels = new Dictionary()); + var key = dr.label; + if (Regex.IsMatch(key, @"^[\u0391-\uFFE5a-zA-Z_\$][\u0391-\uFFE5a-zA-Z_\$\d]*$") == false) + key = $"Unkown{ret[dr.name].Count + 1}"; + if (labels.ContainsKey(key) == false) labels.Add(key, dr.label); + } + return ret.Select(a => new DbEnumInfo { Name = a.Key, Labels = a.Value }).ToList(); + } } } \ No newline at end of file diff --git a/FreeSql/SqlServer/SqlServerDbFirst.cs b/FreeSql/SqlServer/SqlServerDbFirst.cs index 02036f2f..9b51886e 100644 --- a/FreeSql/SqlServer/SqlServerDbFirst.cs +++ b/FreeSql/SqlServer/SqlServerDbFirst.cs @@ -410,5 +410,9 @@ use {olddatabase}; } return tables; } + + public List GetEnumsByDatabase(params string[] database) { + return new List(); + } } } \ No newline at end of file From 572aa1d8ee559116ae397c623ad7e862a21ccfb5 Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Thu, 20 Dec 2018 20:00:33 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F=E5=87=BD?= =?UTF-8?q?=E6=95=B0=EF=BC=8C=E5=A2=9E=E5=8A=A0DateTime/TimeSpan=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E4=B8=94=E5=BC=80=E5=A7=8B=E6=B5=8B=E8=AF=95=E4=B8=8E?= =?UTF-8?q?=E6=95=B4=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)")}"; } }