From 78fded3f8e4f9169097d994dc8dfd3f04598395f Mon Sep 17 00:00:00 2001 From: 28810 <28810@YEXIANGQIN> Date: Thu, 3 Oct 2019 04:31:04 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E5=A2=9E=E5=8A=A0=20IndexAttribute=20?= =?UTF-8?q?=E7=89=B9=E6=80=A7=EF=BC=8C=E8=87=AA=E5=8A=A8=E8=BF=81=E7=A7=BB?= =?UTF-8?q?=E7=B4=A2=E5=BC=95=EF=BC=8C=E4=BB=A5=E5=8F=8A=E5=AF=B9=E5=BA=94?= =?UTF-8?q?=E7=9A=84=20FluentApi=20=E6=96=B9=E6=B3=95=EF=BC=9B=20-=20?= =?UTF-8?q?=E7=A7=BB=E9=99=A4=20ColumnAttribute.Unique=20=E5=B1=9E?= =?UTF-8?q?=E6=80=A7=E8=AE=BE=E7=BD=AE=EF=BC=8C=E6=94=B9=E4=B8=BA=20IndexA?= =?UTF-8?q?ttribute=20=E7=89=B9=E6=80=A7=E8=AE=BE=E7=BD=AE=E5=94=AF?= =?UTF-8?q?=E4=B8=80=E9=94=AE=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MySqlConnector/MySqlCodeFirstTest.cs | 7 +- .../MySql/MySqlCodeFirstTest.cs | 7 +- .../Oracle/OracleCodeFirstTest.cs | 7 +- .../PostgreSQL/PostgreSQLCodeFirstTest.cs | 7 +- .../SqlServer/SqlServerCodeFirstTest.cs | 7 +- .../DataAnnotations/MySqlFluentTest.cs | 1 + .../FreeSql.Tests/MySql/MySqlCodeFirstTest.cs | 7 +- .../Oracle/OracleCodeFirstTest.cs | 7 +- .../FreeSql.Tests/Other/SystemUser.cs | 3 +- .../Other/SystemUserAuthentication.cs | 3 +- .../PostgreSQL/PostgreSQLCodeFirstTest.cs | 7 +- .../SqlServer/SqlServerCodeFirstTest.cs | 7 +- .../Sqlite/SqliteCodeFirstTest.cs | 7 +- FreeSql/DataAnnotations/ColumnAttribute.cs | 30 +---- FreeSql/DataAnnotations/ColumnFluent.cs | 10 -- FreeSql/DataAnnotations/TableAttribute.cs | 33 +++++ FreeSql/DataAnnotations/TableFluent.cs | 28 ++++ FreeSql/DatabaseModel/DBTableInfo.cs | 8 +- FreeSql/DatabaseModel/DbIndexInfo.cs | 21 +++ FreeSql/FreeSql.xml | 53 ++++++-- FreeSql/FreeSqlBuilder.cs | 4 +- FreeSql/Interface/ICodeFirst.cs | 4 +- FreeSql/Internal/CommonUtils.cs | 26 +++- FreeSql/Internal/Model/IndexInfo.cs | 21 +++ FreeSql/Internal/Model/TableInfo.cs | 5 +- FreeSql/Internal/UtilsExpressionTree.cs | 125 +++++++++++------- .../FreeSql.Provider.MySql/MySqlCodeFirst.cs | 74 +++++++---- .../FreeSql.Provider.MySql/MySqlDbFirst.cs | 54 ++++---- .../MySql/OdbcMySqlCodeFirst.cs | 74 +++++++---- .../MySql/OdbcMySqlDbFirst.cs | 54 ++++---- .../Oracle/OdbcOracleCodeFirst.cs | 111 +++++++++++----- .../Oracle/OdbcOracleDbFirst.cs | 72 +++++----- .../PostgreSQL/OdbcPostgreSQLCodeFirst.cs | 72 ++++++---- .../PostgreSQL/OdbcPostgreSQLDbFirst.cs | 44 +++--- .../SqlServer/OdbcSqlServerCodeFirst.cs | 78 +++++++---- .../SqlServer/OdbcSqlServerDbFirst.cs | 47 ++++--- .../OracleCodeFirst.cs | 109 ++++++++++----- .../FreeSql.Provider.Oracle/OracleDbFirst.cs | 72 +++++----- .../PostgreSQLCodeFirst.cs | 72 ++++++---- .../PostgreSQLDbFirst.cs | 44 +++--- .../SqlServerCodeFirst.cs | 78 +++++++---- .../SqlServerDbFirst.cs | 47 ++++--- .../SqliteCodeFirst.cs | 70 ++++++---- 43 files changed, 1010 insertions(+), 607 deletions(-) create mode 100644 FreeSql/DatabaseModel/DbIndexInfo.cs create mode 100644 FreeSql/Internal/Model/IndexInfo.cs diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/MySqlConnector/MySqlCodeFirstTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/MySqlConnector/MySqlCodeFirstTest.cs index 48e209f0..7a8e141d 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/MySqlConnector/MySqlCodeFirstTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.MySqlConnector/MySqlConnector/MySqlCodeFirstTest.cs @@ -46,17 +46,16 @@ namespace FreeSql.Tests.MySqlConnector g.mysql.CodeFirst.SyncStructure(); } [Table(Name = "AddUniquesInfo", OldName = "AddUniquesInfo2")] + [Index("uk_phone", "phone", true)] + [Index("uk_group_index", "group,index", true)] + [Index("uk_group_index22", "group, index22", true)] class AddUniquesInfo { public Guid id { get; set; } - [Column(Unique = "uk_phone")] public string phone { get; set; } - [Column(Unique = "uk_group_index, uk_group_index22")] public string group { get; set; } - [Column(Unique = "uk_group_index")] public int index { get; set; } - [Column(Unique = "uk_group_index22")] public string index22 { get; set; } } diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/MySql/MySqlCodeFirstTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/MySql/MySqlCodeFirstTest.cs index b857909c..e28cb85f 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/MySql/MySqlCodeFirstTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/MySql/MySqlCodeFirstTest.cs @@ -46,17 +46,16 @@ namespace FreeSql.Tests.Odbc.MySql g.mysql.CodeFirst.SyncStructure(); } [Table(Name = "AddUniquesInfo", OldName = "AddUniquesInfo2")] + [Index("uk_phone", "phone", true)] + [Index("uk_group_index", "group,index", true)] + [Index("uk_group_index22", "group, index22", true)] class AddUniquesInfo { public Guid id { get; set; } - [Column(Unique = "uk_phone")] public string phone { get; set; } - [Column(Unique = "uk_group_index, uk_group_index22")] public string group { get; set; } - [Column(Unique = "uk_group_index")] public int index { get; set; } - [Column(Unique = "uk_group_index22")] public string index22 { get; set; } } diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/Oracle/OracleCodeFirstTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/Oracle/OracleCodeFirstTest.cs index f34d6754..a5686eeb 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/Oracle/OracleCodeFirstTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/Oracle/OracleCodeFirstTest.cs @@ -46,17 +46,16 @@ namespace FreeSql.Tests.Odbc.Oracle g.oracle.CodeFirst.SyncStructure(); } [Table(Name = "AddUniquesInfo", OldName = "AddUniquesInfo2")] + [Index("uk_phone", "phone", true)] + [Index("uk_group_index", "group,index", true)] + [Index("uk_group_index22", "group, index22", true)] class AddUniquesInfo { public Guid id { get; set; } - [Column(Unique = "uk_phone")] public string phone { get; set; } - [Column(Unique = "uk_group_index, uk_group_index22")] public string group { get; set; } - [Column(Unique = "uk_group_index")] public int index { get; set; } - [Column(Unique = "uk_group_index22")] public string index22 { get; set; } } [Fact] diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/PostgreSQL/PostgreSQLCodeFirstTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/PostgreSQL/PostgreSQLCodeFirstTest.cs index 6d0aa7ae..81773eba 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/PostgreSQL/PostgreSQLCodeFirstTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/PostgreSQL/PostgreSQLCodeFirstTest.cs @@ -50,17 +50,16 @@ namespace FreeSql.Tests.Odbc.PostgreSQL g.pgsql.CodeFirst.SyncStructure(); } [Table(Name = "AddUniquesInfo", OldName = "AddUniquesInfo2")] + [Index("uk_phone", "phone", true)] + [Index("uk_group_index", "group,index", true)] + [Index("uk_group_index22", "group, index22", true)] class AddUniquesInfo { public Guid id { get; set; } - [Column(Unique = "uk_phone")] public string phone { get; set; } - [Column(Unique = "uk_group_index, uk_group_index22")] public string group { get; set; } - [Column(Unique = "uk_group_index")] public int index { get; set; } - [Column(Unique = "uk_group_index22")] public string index22 { get; set; } } diff --git a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/SqlServer/SqlServerCodeFirstTest.cs b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/SqlServer/SqlServerCodeFirstTest.cs index 8ebc109e..68ca3891 100644 --- a/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/SqlServer/SqlServerCodeFirstTest.cs +++ b/FreeSql.Tests/FreeSql.Tests.Provider.Odbc/SqlServer/SqlServerCodeFirstTest.cs @@ -48,17 +48,16 @@ namespace FreeSql.Tests.Odbc.SqlServer g.sqlserver.CodeFirst.SyncStructure(); } [Table(Name = "AddUniquesInfo", OldName = "AddUniquesInfo2")] + [Index("uk_phone", "phone", true)] + [Index("uk_group_index", "group,index", true)] + [Index("uk_group_index22", "group, index22", true)] class AddUniquesInfo { public Guid id { get; set; } - [Column(Unique = "uk_phone")] public string phone { get; set; } - [Column(Unique = "uk_group_index, uk_group_index22")] public string group { get; set; } - [Column(Unique = "uk_group_index")] public int index { get; set; } - [Column(Unique = "uk_group_index22")] public string index22 { get; set; } } diff --git a/FreeSql.Tests/FreeSql.Tests/DataAnnotations/MySqlFluentTest.cs b/FreeSql.Tests/FreeSql.Tests/DataAnnotations/MySqlFluentTest.cs index 5f736963..596a5dc1 100644 --- a/FreeSql.Tests/FreeSql.Tests/DataAnnotations/MySqlFluentTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/DataAnnotations/MySqlFluentTest.cs @@ -163,6 +163,7 @@ namespace FreeSql.Tests.DataAnnotations Assert.NotEqual(item.testfield2, find.testfield2); Assert.Equal(1000, find.testfield1); } + [Index("idx_xxx", "testfield1 ASC, testfield2 DESC")] class TestCanInsert { public Guid id { get; set; } diff --git a/FreeSql.Tests/FreeSql.Tests/MySql/MySqlCodeFirstTest.cs b/FreeSql.Tests/FreeSql.Tests/MySql/MySqlCodeFirstTest.cs index a3017d2d..3fe86a01 100644 --- a/FreeSql.Tests/FreeSql.Tests/MySql/MySqlCodeFirstTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/MySql/MySqlCodeFirstTest.cs @@ -46,17 +46,16 @@ namespace FreeSql.Tests.MySql g.mysql.CodeFirst.SyncStructure(); } [Table(Name = "AddUniquesInfo", OldName = "AddUniquesInfo2")] + [Index("uk_phone", "phone", true)] + [Index("uk_group_index", "group,index", true)] + [Index("uk_group_index22", "group, index22", false)] class AddUniquesInfo { public Guid id { get; set; } - [Column(Unique = "uk_phone")] public string phone { get; set; } - [Column(Unique = "uk_group_index, uk_group_index22")] public string group { get; set; } - [Column(Unique = "uk_group_index")] public int index { get; set; } - [Column(Unique = "uk_group_index22")] public string index22 { get; set; } } diff --git a/FreeSql.Tests/FreeSql.Tests/Oracle/OracleCodeFirstTest.cs b/FreeSql.Tests/FreeSql.Tests/Oracle/OracleCodeFirstTest.cs index a7ccc99a..4cfd7adc 100644 --- a/FreeSql.Tests/FreeSql.Tests/Oracle/OracleCodeFirstTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/Oracle/OracleCodeFirstTest.cs @@ -46,17 +46,16 @@ namespace FreeSql.Tests.Oracle g.oracle.CodeFirst.SyncStructure(); } [Table(Name = "AddUniquesInfo", OldName = "AddUniquesInfo2")] + [Index("uk_phone", "phone", true)] + [Index("uk_group_index", "group,index", true)] + [Index("uk_group_index22", "group, index22 desc", true)] class AddUniquesInfo { public Guid id { get; set; } - [Column(Unique = "uk_phone")] public string phone { get; set; } - [Column(Unique = "uk_group_index, uk_group_index22")] public string group { get; set; } - [Column(Unique = "uk_group_index")] public int index { get; set; } - [Column(Unique = "uk_group_index22")] public string index22 { get; set; } } [Fact] diff --git a/FreeSql.Tests/FreeSql.Tests/Other/SystemUser.cs b/FreeSql.Tests/FreeSql.Tests/Other/SystemUser.cs index 1b7a0a8a..9091a97d 100644 --- a/FreeSql.Tests/FreeSql.Tests/Other/SystemUser.cs +++ b/FreeSql.Tests/FreeSql.Tests/Other/SystemUser.cs @@ -9,12 +9,13 @@ namespace Zeus /// 用户表 /// [Table(Name = "system_user")] + [Index("UK_DisplayName", "DisplayName", true)] public partial class SystemUser : EntityBase { /// /// 显示名称 /// - [Column(DbType = "varchar(20)", IsNullable = false, Unique = "UK_DisplayName")] + [Column(DbType = "varchar(20)", IsNullable = false)] public string DisplayName { get; set; } /// /// 真实名称 diff --git a/FreeSql.Tests/FreeSql.Tests/Other/SystemUserAuthentication.cs b/FreeSql.Tests/FreeSql.Tests/Other/SystemUserAuthentication.cs index 5da122f7..594c3865 100644 --- a/FreeSql.Tests/FreeSql.Tests/Other/SystemUserAuthentication.cs +++ b/FreeSql.Tests/FreeSql.Tests/Other/SystemUserAuthentication.cs @@ -10,6 +10,7 @@ namespace Zeus /// 用户认证表 /// [Table(Name = "system_user_authentication")] + [Index("UK_Identifier", "Identifier", true)] public partial class SystemUserAuthentication : EntityBase { /// @@ -30,7 +31,7 @@ namespace Zeus /// /// 登录标识 /// - [Column(DbType = "varchar(50)", IsNullable = false, Unique = "UK_Identifier")] + [Column(DbType = "varchar(50)", IsNullable = false)] public string Identifier { get; set; } /// /// 登录凭证 diff --git a/FreeSql.Tests/FreeSql.Tests/PostgreSQL/PostgreSQLCodeFirstTest.cs b/FreeSql.Tests/FreeSql.Tests/PostgreSQL/PostgreSQLCodeFirstTest.cs index 8b330b37..d91dc319 100644 --- a/FreeSql.Tests/FreeSql.Tests/PostgreSQL/PostgreSQLCodeFirstTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/PostgreSQL/PostgreSQLCodeFirstTest.cs @@ -53,17 +53,16 @@ namespace FreeSql.Tests.PostgreSQL g.pgsql.CodeFirst.SyncStructure(); } [Table(Name = "AddUniquesInfo", OldName = "AddUniquesInfo2")] + [Index("uk_phone", "phone", true)] + [Index("uk_group_index", "group,index", true)] + [Index("uk_group_index22", "group, index22", false)] class AddUniquesInfo { public Guid id { get; set; } - [Column(Unique = "uk_phone")] public string phone { get; set; } - [Column(Unique = "uk_group_index, uk_group_index22")] public string group { get; set; } - [Column(Unique = "uk_group_index")] public int index { get; set; } - [Column(Unique = "uk_group_index22")] public string index22 { get; set; } } diff --git a/FreeSql.Tests/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs b/FreeSql.Tests/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs index f4ec916e..6772988d 100644 --- a/FreeSql.Tests/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/SqlServer/SqlServerCodeFirstTest.cs @@ -57,17 +57,16 @@ namespace FreeSql.Tests.SqlServer _sqlserverFixture.SqlServer.CodeFirst.SyncStructure(); } [Table(Name = "AddUniquesInfo", OldName = "AddUniquesInfo2")] + [Index("uk_phone", "phone", true)] + [Index("uk_group_index", "group,index", true)] + [Index("uk_group_index22", "group, index22", false)] class AddUniquesInfo { public Guid id { get; set; } - [Column(Unique = "uk_phone")] public string phone { get; set; } - [Column(Unique = "uk_group_index, uk_group_index22")] public string group { get; set; } - [Column(Unique = "uk_group_index")] public int index { get; set; } - [Column(Unique = "uk_group_index22")] public string index22 { get; set; } } diff --git a/FreeSql.Tests/FreeSql.Tests/Sqlite/SqliteCodeFirstTest.cs b/FreeSql.Tests/FreeSql.Tests/Sqlite/SqliteCodeFirstTest.cs index ef0597df..48281579 100644 --- a/FreeSql.Tests/FreeSql.Tests/Sqlite/SqliteCodeFirstTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/Sqlite/SqliteCodeFirstTest.cs @@ -46,17 +46,16 @@ namespace FreeSql.Tests.Sqlite g.sqlite.CodeFirst.SyncStructure(); } [Table(Name = "AddUniquesInfo2", OldName = "AddUniquesInfo")] + [Index("uk_phone", "phone", true)] + [Index("uk_group_index", "group,index", true)] + [Index("uk_group_index22", "group desc, index22", true)] class AddUniquesInfo { public Guid id { get; set; } - [Column(Unique = "uk_phone")] public string phone { get; set; } - [Column(Unique = "uk_group_index, uk_group_index22")] public string group { get; set; } - [Column(Unique = "uk_group_index")] public int index { get; set; } - [Column(Unique = "uk_group_index22")] public string index22 { get; set; } } diff --git a/FreeSql/DataAnnotations/ColumnAttribute.cs b/FreeSql/DataAnnotations/ColumnAttribute.cs index 96955872..0c9944e1 100644 --- a/FreeSql/DataAnnotations/ColumnAttribute.cs +++ b/FreeSql/DataAnnotations/ColumnAttribute.cs @@ -3,6 +3,7 @@ using System.Linq; namespace FreeSql.DataAnnotations { + [AttributeUsage(AttributeTargets.Property)] public class ColumnAttribute : Attribute { @@ -42,35 +43,6 @@ namespace FreeSql.DataAnnotations /// public bool IsVersion { get => _IsVersion ?? false; set => _IsVersion = value; } - internal string[] _Uniques; - /// - /// 唯一键,在多个属性指定相同的标识,代表联合键;可使用逗号分割多个 UniqueKey 名。 - /// - public string Unique - { - get => _Uniques == null ? null : string.Join(", ", _Uniques); - set - { - if (string.IsNullOrEmpty(value)) - { - _Uniques = null; - return; - } - var val = value?.Trim(' ', '\t', ','); - if (string.IsNullOrEmpty(val)) - { - _Uniques = null; - return; - } - var arr = val.Split(',').Select(a => a.Trim(' ', '\t').Trim()).Where(a => !string.IsNullOrEmpty(a)).ToArray(); - if (arr.Any() == false) - { - _Uniques = null; - return; - } - _Uniques = arr; - } - } /// /// 数据库默认值 /// diff --git a/FreeSql/DataAnnotations/ColumnFluent.cs b/FreeSql/DataAnnotations/ColumnFluent.cs index 0f80bb02..3cebe19c 100644 --- a/FreeSql/DataAnnotations/ColumnFluent.cs +++ b/FreeSql/DataAnnotations/ColumnFluent.cs @@ -77,16 +77,6 @@ namespace FreeSql.DataAnnotations return this; } /// - /// 唯一键,在多个属性指定相同的标识,代表联合键;可使用逗号分割多个 UniqueKey 名。 - /// - /// 标识 - /// - public ColumnFluent Unique(string value) - { - _column.Unique = value; - return this; - } - /// /// 类型映射,比如:可将 enum 属性映射成 typeof(string) /// /// diff --git a/FreeSql/DataAnnotations/TableAttribute.cs b/FreeSql/DataAnnotations/TableAttribute.cs index ef5a4dda..18fb2e54 100644 --- a/FreeSql/DataAnnotations/TableAttribute.cs +++ b/FreeSql/DataAnnotations/TableAttribute.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Concurrent; +using System.Linq.Expressions; namespace FreeSql.DataAnnotations { + [AttributeUsage(AttributeTargets.Class)] public class TableAttribute : Attribute { @@ -27,5 +29,36 @@ namespace FreeSql.DataAnnotations internal ConcurrentDictionary _columns { get; } = new ConcurrentDictionary(StringComparer.CurrentCultureIgnoreCase); internal ConcurrentDictionary _navigates { get; } = new ConcurrentDictionary(StringComparer.CurrentCultureIgnoreCase); + internal ConcurrentDictionary _indexs { get; } = new ConcurrentDictionary(StringComparer.CurrentCultureIgnoreCase); + } + + [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] + public class IndexAttribute : Attribute + { + public IndexAttribute(string name, string fields) + { + this.Name = name; + this.Fields = fields; + } + public IndexAttribute(string name, string fields, bool isUnique) + { + this.Name = name; + this.Fields = fields; + this.IsUnique = isUnique; + } + /// + /// 索引名 + /// + public string Name { get; set; } + /// + /// 索引字段,为属性名以逗号分隔,如:Create_time ASC, Title ASC + /// + public string Fields { get; set; } + + internal bool? _IsUnique; + /// + /// 是否唯一 + /// + public bool IsUnique { get => _IsUnique ?? false; set => _IsUnique = value; } } } diff --git a/FreeSql/DataAnnotations/TableFluent.cs b/FreeSql/DataAnnotations/TableFluent.cs index 9027d529..d29e94fa 100644 --- a/FreeSql/DataAnnotations/TableFluent.cs +++ b/FreeSql/DataAnnotations/TableFluent.cs @@ -59,6 +59,20 @@ namespace FreeSql.DataAnnotations var col = _table._columns.GetOrAdd(proto, name => new ColumnAttribute { Name = proto }); return new ColumnFluent(col); } + + /// + /// 设置实体的索引 + /// + /// 索引名 + /// 索引字段,为属性名以逗号分隔,如:Create_time ASC, Title ASC + /// 是否唯一 + /// + public TableFluent Index(string name, string fields, bool isUnique = false) + { + var idx = new IndexAttribute(name, fields, isUnique); + _table._indexs.AddOrUpdate(name, idx, (_, __) => idx); + return this; + } } public class TableFluent @@ -128,5 +142,19 @@ namespace FreeSql.DataAnnotations _table._navigates.AddOrUpdate(member.Name, nav, (name, old) => nav); return this; } + + /// + /// 设置实体的索引 + /// + /// 索引名 + /// 索引字段,为属性名以逗号分隔,如:Create_time ASC, Title ASC + /// 是否唯一 + /// + public TableFluent Index(string name, string fields, bool isUnique = false) + { + var idx = new IndexAttribute(name, fields, isUnique); + _table._indexs.AddOrUpdate(name, idx, (_, __) => idx); + return this; + } } } diff --git a/FreeSql/DatabaseModel/DBTableInfo.cs b/FreeSql/DatabaseModel/DBTableInfo.cs index 10dc42e0..f294b406 100644 --- a/FreeSql/DatabaseModel/DBTableInfo.cs +++ b/FreeSql/DatabaseModel/DBTableInfo.cs @@ -40,18 +40,18 @@ namespace FreeSql.DatabaseModel /// /// 唯一键/组合 /// - public Dictionary> UniquesDict { get; set; } = new Dictionary>(); + public Dictionary UniquesDict { get; set; } = new Dictionary(); /// /// 索引/组合 /// - public Dictionary> IndexesDict { get; set; } = new Dictionary>(); + public Dictionary IndexesDict { get; set; } = new Dictionary(); /// /// 外键 /// public Dictionary ForeignsDict { get; set; } = new Dictionary(); - public List> Uniques => UniquesDict.Values.ToList(); - public List> Indexes => IndexesDict.Values.ToList(); + public List Uniques => UniquesDict.Values.ToList(); + public List Indexes => IndexesDict.Values.ToList(); public List Foreigns => ForeignsDict.Values.ToList(); } diff --git a/FreeSql/DatabaseModel/DbIndexInfo.cs b/FreeSql/DatabaseModel/DbIndexInfo.cs new file mode 100644 index 00000000..f8de2c6a --- /dev/null +++ b/FreeSql/DatabaseModel/DbIndexInfo.cs @@ -0,0 +1,21 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq.Expressions; + +namespace FreeSql.DatabaseModel +{ + public class DbIndexInfo + { + public string Name { get; set; } + public List Columns { get; } = new List(); + public bool IsUnique { get; set; } + } + + public class DbIndexColumnInfo + { + public DbColumnInfo Column { get; set; } + public bool IsDesc { get; set; } + } +} \ No newline at end of file diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 3d2a21c9..7a86ceb0 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -45,11 +45,6 @@ 设置行锁(乐观锁)版本号,每次更新累加版本号,若更新整个实体时会附带当前的版本号判断(修改失败时抛出异常) - - - 唯一键,在多个属性指定相同的标识,代表联合键;可使用逗号分割多个 UniqueKey 名。 - - 数据库默认值 @@ -123,13 +118,6 @@ 乐观锁 - - - 唯一键,在多个属性指定相同的标识,代表联合键;可使用逗号分割多个 UniqueKey 名。 - - 标识 - - 类型映射,比如:可将 enum 属性映射成 typeof(string) @@ -199,6 +187,21 @@ 禁用 CodeFirst 同步结构迁移 + + + 索引名 + + + + + 索引字段,为属性名以逗号分隔,如:Create_time ASC, Title ASC + + + + + 是否唯一 + + 数据库表名 @@ -219,6 +222,15 @@ 禁用 CodeFirst 同步结构迁移 + + + 设置实体的索引 + + 索引名 + 索引字段,为属性名以逗号分隔,如:Create_time ASC, Title ASC + 是否唯一 + + 数据库表名 @@ -249,6 +261,15 @@ 多对多关系的中间实体类型 + + + 设置实体的索引 + + 索引名 + 索引字段,为属性名以逗号分隔,如:Create_time ASC, Title ASC + 是否唯一 + + 所属表 @@ -551,7 +572,9 @@ - 使用数据库的主键和自增,适用 DbFirst 模式,无须在实体类型上设置 [Column(IsPrimary)] 或者 ConfigEntity。此功能目前可用于 mysql/sqlserver/postgresql。 + 将数据库的主键、自增、索引设置导入,适用 DbFirst 模式,无须在实体类型上设置 [Column(IsPrimary)] 或者 ConfigEntity。此功能目前可用于 mysql/sqlserver/postgresql/oracle。 + 本功能会影响 IFreeSql 首次访问的速度。 + 若使用 CodeFirst 创建索引后,又直接在数据库上建了索引,若无本功能下一次 CodeFirst 迁移时数据库上创建的索引将被删除 @@ -2288,7 +2311,9 @@ - 使用数据库的主键和自增,适用 DbFirst 模式,无须在实体类型上设置 [Column(IsPrimary)] 或者 ConfigEntity。此功能目前可用于 mysql/sqlserver/postgresql。 + 将数据库的主键、自增、索引设置导入,适用 DbFirst 模式,无须在实体类型上设置 [Column(IsPrimary)] 或者 ConfigEntity。此功能目前可用于 mysql/sqlserver/postgresql/oracle。 + 本功能会影响 IFreeSql 首次访问的速度。 + 若使用 CodeFirst 创建索引后,又直接在数据库上建了索引,若无本功能下一次 CodeFirst 迁移时数据库上创建的索引将被删除 diff --git a/FreeSql/FreeSqlBuilder.cs b/FreeSql/FreeSqlBuilder.cs index 12b4102f..154ae22b 100644 --- a/FreeSql/FreeSqlBuilder.cs +++ b/FreeSql/FreeSqlBuilder.cs @@ -78,7 +78,9 @@ namespace FreeSql return this; } /// - /// 使用数据库的主键和自增,适用 DbFirst 模式,无须在实体类型上设置 [Column(IsPrimary)] 或者 ConfigEntity。此功能目前可用于 mysql/sqlserver/postgresql。 + /// 将数据库的主键、自增、索引设置导入,适用 DbFirst 模式,无须在实体类型上设置 [Column(IsPrimary)] 或者 ConfigEntity。此功能目前可用于 mysql/sqlserver/postgresql/oracle。 + /// 本功能会影响 IFreeSql 首次访问的速度。 + /// 若使用 CodeFirst 创建索引后,又直接在数据库上建了索引,若无本功能下一次 CodeFirst 迁移时数据库上创建的索引将被删除 /// /// /// diff --git a/FreeSql/Interface/ICodeFirst.cs b/FreeSql/Interface/ICodeFirst.cs index de49488a..18b7b67e 100644 --- a/FreeSql/Interface/ICodeFirst.cs +++ b/FreeSql/Interface/ICodeFirst.cs @@ -21,7 +21,9 @@ namespace FreeSql /// bool IsSyncStructureToUpper { get; set; } /// - /// 使用数据库的主键和自增,适用 DbFirst 模式,无须在实体类型上设置 [Column(IsPrimary)] 或者 ConfigEntity。此功能目前可用于 mysql/sqlserver/postgresql。 + /// 将数据库的主键、自增、索引设置导入,适用 DbFirst 模式,无须在实体类型上设置 [Column(IsPrimary)] 或者 ConfigEntity。此功能目前可用于 mysql/sqlserver/postgresql/oracle。 + /// 本功能会影响 IFreeSql 首次访问的速度。 + /// 若使用 CodeFirst 创建索引后,又直接在数据库上建了索引,若无本功能下一次 CodeFirst 迁移时数据库上创建的索引将被删除 /// bool IsConfigEntityFromDbFirst { get; set; } /// diff --git a/FreeSql/Internal/CommonUtils.cs b/FreeSql/Internal/CommonUtils.cs index e976465d..7c9ed240 100644 --- a/FreeSql/Internal/CommonUtils.cs +++ b/FreeSql/Internal/CommonUtils.cs @@ -125,7 +125,6 @@ namespace FreeSql.Internal if (trycol._IsNullable != null) attr._IsNullable = trycol.IsNullable; if (trycol._IsIgnore != null) attr._IsIgnore = trycol.IsIgnore; if (trycol._IsVersion != null) attr._IsVersion = trycol.IsVersion; - if (trycol._Uniques != null) attr._Uniques = trycol._Uniques; if (trycol.MapType != null) attr.MapType = trycol.MapType; if (trycol._Position != null) attr._Position = trycol.Position; if (trycol._CanInsert != null) attr._CanInsert = trycol.CanInsert; @@ -145,7 +144,6 @@ namespace FreeSql.Internal if (tryattr._IsNullable != null) attr._IsNullable = tryattr.IsNullable; if (tryattr._IsIgnore != null) attr._IsIgnore = tryattr.IsIgnore; if (tryattr._IsVersion != null) attr._IsVersion = tryattr.IsVersion; - if (tryattr._Uniques != null) attr._Uniques = tryattr._Uniques; if (tryattr.MapType != null) attr.MapType = tryattr.MapType; if (tryattr._Position != null) attr._Position = tryattr.Position; if (tryattr._CanInsert != null) attr._CanInsert = tryattr.CanInsert; @@ -161,7 +159,6 @@ namespace FreeSql.Internal if (attr._IsNullable != null) ret = attr; if (attr._IsIgnore != null) ret = attr; if (attr._IsVersion != null) ret = attr; - if (attr._Uniques != null) ret = attr; if (attr.MapType != null) ret = attr; if (attr._Position != null) ret = attr; if (attr._CanInsert != null) ret = attr; @@ -191,6 +188,29 @@ namespace FreeSql.Internal if (attr.ManyToMany != null) ret = attr; return ret; } + public IndexAttribute[] GetEntityIndexAttribute(Type type) + { + var ret = new Dictionary(); ; + if (dicConfigEntity.TryGetValue(type, out var trytb)) + { + foreach (var idxattr in trytb._indexs.Values) + { + if (!string.IsNullOrEmpty(idxattr.Name) && !string.IsNullOrEmpty(idxattr.Fields)) + ret.Add(idxattr.Name, new IndexAttribute(idxattr.Name, idxattr.Fields) { _IsUnique = idxattr._IsUnique }); + } + } + var attrs = type.GetCustomAttributes(typeof(IndexAttribute), true); + foreach (var tryattrobj in attrs) + { + var idxattr = tryattrobj as IndexAttribute; + if (idxattr == null) continue; + if (string.IsNullOrEmpty(idxattr.Name)) continue; + if (string.IsNullOrEmpty(idxattr.Fields)) continue; + if (ret.ContainsKey(idxattr.Name)) ret.Remove(idxattr.Name); + ret.Add(idxattr.Name, new IndexAttribute(idxattr.Name, idxattr.Fields) { _IsUnique = idxattr._IsUnique }); + } + return ret.Values.ToArray(); + } public string WhereObject(TableInfo table, string aliasAndDot, object dywhere) { diff --git a/FreeSql/Internal/Model/IndexInfo.cs b/FreeSql/Internal/Model/IndexInfo.cs new file mode 100644 index 00000000..149730f0 --- /dev/null +++ b/FreeSql/Internal/Model/IndexInfo.cs @@ -0,0 +1,21 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq.Expressions; + +namespace FreeSql.Internal.Model +{ + public class IndexInfo + { + public string Name { get; set; } + public IndexColumnInfo[] Columns { get; set; } + public bool IsUnique { get; set; } + } + + public class IndexColumnInfo + { + public ColumnInfo Column { get; set; } + public bool IsDesc { get; set; } + } +} \ No newline at end of file diff --git a/FreeSql/Internal/Model/TableInfo.cs b/FreeSql/Internal/Model/TableInfo.cs index 1e1b3da8..398721a6 100644 --- a/FreeSql/Internal/Model/TableInfo.cs +++ b/FreeSql/Internal/Model/TableInfo.cs @@ -1,4 +1,5 @@ -using System; +using FreeSql.DataAnnotations; +using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Reflection; @@ -16,7 +17,7 @@ namespace FreeSql.Internal.Model public Dictionary ColumnsByCsIgnore { get; set; } = new Dictionary(StringComparer.CurrentCultureIgnoreCase); public ColumnInfo[] ColumnsByPosition { get; set; } public ColumnInfo[] Primarys { get; set; } - public Dictionary> Uniques { get; set; } + public IndexInfo[] Indexes { get; set; } public string CsName { get; set; } public string DbName { get; set; } public string DbOldName { get; set; } diff --git a/FreeSql/Internal/UtilsExpressionTree.cs b/FreeSql/Internal/UtilsExpressionTree.cs index 09a3fac4..862c3b62 100644 --- a/FreeSql/Internal/UtilsExpressionTree.cs +++ b/FreeSql/Internal/UtilsExpressionTree.cs @@ -103,7 +103,6 @@ namespace FreeSql.Internal IsNullable = tp.Value.isnullable ?? true, IsPrimary = false, IsIgnore = false, - Unique = null, MapType = p.PropertyType }; if (colattr._IsNullable == null) colattr._IsNullable = tp?.isnullable; @@ -119,16 +118,8 @@ namespace FreeSql.Internal if (tp != null && tp.Value.isnullable == null) colattr.IsNullable = tp.Value.dbtypeFull.Contains("NOT NULL") == false; if (colattr.DbType?.Contains("NOT NULL") == true) colattr.IsNullable = false; if (string.IsNullOrEmpty(colattr.Name)) colattr.Name = p.Name; - if (common.CodeFirst.IsSyncStructureToLower) - { - colattr.Name = colattr.Name.ToLower(); - colattr.Unique = colattr.Unique?.ToLower(); - } - if (common.CodeFirst.IsSyncStructureToUpper) - { - colattr.Name = colattr.Name.ToUpper(); - colattr.Unique = colattr.Unique?.ToUpper(); - } + if (common.CodeFirst.IsSyncStructureToLower) colattr.Name = colattr.Name.ToLower(); + if (common.CodeFirst.IsSyncStructureToUpper) colattr.Name = colattr.Name.ToUpper(); if ((colattr.IsNullable != true || colattr.IsIdentity == true || colattr.IsPrimary == true) && colattr.DbType.Contains("NOT NULL") == false) { @@ -183,27 +174,9 @@ namespace FreeSql.Internal if (trytb.VersionColumn.Attribute.MapType.IsNullableType() || trytb.VersionColumn.Attribute.MapType.IsNumberType() == false) throw new Exception($"属性{trytb.VersionColumn.CsName} 被标注为行锁(乐观锁)(IsVersion),但其必须为数字类型,并且不可为 Nullable"); } - trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsPrimary == true).ToArray(); - if (trytb.Primarys.Any() == false) - { - var identcol = trytb.Columns.Values.Where(a => a.Attribute.IsIdentity == true).FirstOrDefault(); - if (identcol != null) trytb.Primarys = new[] { identcol }; - if (trytb.Primarys.Any() == false) - { - trytb.Primarys = trytb.Columns.Values.Where(a => string.Compare(a.Attribute.Name, "id", true) == 0).ToArray(); - if (trytb.Primarys.Any() == false) - { - trytb.Primarys = trytb.Columns.Values.Where(a => string.Compare(a.Attribute.Name, $"{trytb.DbName}id", true) == 0).ToArray(); - if (trytb.Primarys.Any() == false) - { - trytb.Primarys = trytb.Columns.Values.Where(a => string.Compare(a.Attribute.Name, $"{trytb.DbName}_id", true) == 0).ToArray(); - } - } - } - foreach (var col in trytb.Primarys) - col.Attribute.IsPrimary = true; - } - //从数据库查找主键、自增 + + var indexesDict = new Dictionary(StringComparer.CurrentCultureIgnoreCase); + //从数据库查找主键、自增、索引 if (common.CodeFirst.IsConfigEntityFromDbFirst) { try @@ -220,37 +193,99 @@ namespace FreeSql.Internal { foreach (var dbident in dbtb.Identitys) { - if (trytb.Columns.TryGetValue(dbident.Name, out var trycol) && trycol.Attribute.MapType == dbident.CsType || - trytb.ColumnsByCs.TryGetValue(dbident.Name, out trycol) && trycol.Attribute.MapType == dbident.CsType) + if (trytb.Columns.TryGetValue(dbident.Name, out var trycol) && trycol.Attribute.MapType.NullableTypeOrThis() == dbident.CsType.NullableTypeOrThis() || + trytb.ColumnsByCs.TryGetValue(dbident.Name, out trycol) && trycol.Attribute.MapType.NullableTypeOrThis() == dbident.CsType.NullableTypeOrThis()) trycol.Attribute.IsIdentity = true; } foreach (var dbpk in dbtb.Primarys) { - if (trytb.Columns.TryGetValue(dbpk.Name, out var trycol) && trycol.Attribute.MapType == dbpk.CsType || - trytb.ColumnsByCs.TryGetValue(dbpk.Name, out trycol) && trycol.Attribute.MapType == dbpk.CsType) + if (trytb.Columns.TryGetValue(dbpk.Name, out var trycol) && trycol.Attribute.MapType.NullableTypeOrThis() == dbpk.CsType.NullableTypeOrThis() || + trytb.ColumnsByCs.TryGetValue(dbpk.Name, out trycol) && trycol.Attribute.MapType.NullableTypeOrThis() == dbpk.CsType.NullableTypeOrThis()) trycol.Attribute.IsPrimary = true; } - foreach (var dbuk in dbtb.UniquesDict) + foreach (var dbidx in dbtb.IndexesDict) { - foreach (var dbcol in dbuk.Value) + var indexColumns = new List(); + foreach (var dbcol in dbidx.Value.Columns) { - if (trytb.Columns.TryGetValue(dbcol.Name, out var trycol) && trycol.Attribute.MapType == dbcol.CsType || - trytb.ColumnsByCs.TryGetValue(dbcol.Name, out trycol) && trycol.Attribute.MapType == dbcol.CsType) - if (trycol.Attribute._Uniques?.Contains(dbuk.Key) != true) - trycol.Attribute.Unique += $"," + dbuk.Key; + if (trytb.Columns.TryGetValue(dbcol.Column.Name, out var trycol) && trycol.Attribute.MapType.NullableTypeOrThis() == dbcol.Column.CsType.NullableTypeOrThis() || + trytb.ColumnsByCs.TryGetValue(dbcol.Column.Name, out trycol) && trycol.Attribute.MapType.NullableTypeOrThis() == dbcol.Column.CsType.NullableTypeOrThis()) + indexColumns.Add(new IndexColumnInfo + { + Column = trycol, + IsDesc = dbcol.IsDesc + }); } + if (indexColumns.Any() == false) continue; + if (indexesDict.ContainsKey(dbidx.Key)) indexesDict.Remove(dbidx.Key); + indexesDict.Add(dbidx.Key, new IndexInfo + { + Name = dbidx.Key, + Columns = indexColumns.ToArray(), + IsUnique = dbidx.Value.IsUnique + }); } } } } catch { } - trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsPrimary == true).ToArray(); } - var allunique = trytb.Columns.Values.Where(a => a.Attribute._Uniques != null).SelectMany(a => a.Attribute._Uniques).Distinct(); - trytb.Uniques = allunique.ToDictionary(a => a, a => trytb.Columns.Values.Where(b => b.Attribute._Uniques != null && b.Attribute._Uniques.Contains(a)).ToList()); + //索引和唯一键 + var indexes = common.GetEntityIndexAttribute(trytb.Type); + foreach (var index in indexes) + { + var val = index.Fields?.Trim(' ', '\t', ','); + if (string.IsNullOrEmpty(val)) continue; + var arr = val.Split(',').Select(a => a.Trim(' ', '\t').Trim()).Where(a => !string.IsNullOrEmpty(a)).ToArray(); + if (arr.Any() == false) continue; + var indexColumns = new List(); + foreach (var field in arr) + { + var idxcol = new IndexColumnInfo(); + if (field.EndsWith(" DESC", StringComparison.CurrentCultureIgnoreCase)) idxcol.IsDesc = true; + var colname = Regex.Replace(field, " (DESC|ASC)", "", RegexOptions.IgnoreCase); + if (trytb.ColumnsByCs.TryGetValue(colname, out var trycol) || trytb.Columns.TryGetValue(colname, out trycol)) + { + idxcol.Column = trycol; + indexColumns.Add(idxcol); + } + } + if (indexColumns.Any() == false) continue; + var indexName = common.CodeFirst.IsSyncStructureToLower ? index.Name.ToLower() : (common.CodeFirst.IsSyncStructureToUpper ? index.Name.ToUpper() : index.Name); + if (indexesDict.ContainsKey(indexName)) indexesDict.Remove(indexName); + indexesDict.Add(indexName, new IndexInfo + { + Name = indexName, + Columns = indexColumns.ToArray(), + IsUnique = index.IsUnique + }); + } + trytb.Indexes = indexesDict.Values.ToArray(); trytb.ColumnsByPosition = columnsList.Where(a => a.Attribute.Position > 0).OrderBy(a => a.Attribute.Position) .Concat(columnsList.Where(a => a.Attribute.Position == 0)) .Concat(columnsList.Where(a => a.Attribute.Position < 0).OrderBy(a => a.Attribute.Position)).ToArray(); + + trytb.Primarys = trytb.Columns.Values.Where(a => a.Attribute.IsPrimary == true).ToArray(); + if (trytb.Primarys.Any() == false) + { + trytb.Primarys = trytb.Columns.Values.Where(a => string.Compare(a.Attribute.Name, "id", true) == 0).ToArray(); + if (trytb.Primarys.Any() == false) + { + var identcol = trytb.Columns.Values.Where(a => a.Attribute.IsIdentity == true).FirstOrDefault(); + if (identcol != null) trytb.Primarys = new[] { identcol }; + if (trytb.Primarys.Any() == false) + { + trytb.Primarys = trytb.Columns.Values.Where(a => string.Compare(a.Attribute.Name, $"{trytb.DbName}id", true) == 0).ToArray(); + if (trytb.Primarys.Any() == false) + { + trytb.Primarys = trytb.Columns.Values.Where(a => string.Compare(a.Attribute.Name, $"{trytb.DbName}_id", true) == 0).ToArray(); + } + } + } + foreach (var col in trytb.Primarys) + col.Attribute.IsPrimary = true; + } + foreach (var col in trytb.Primarys) col.Attribute.IsNullable = false; tbc.AddOrUpdate(entity, trytb, (oldkey, oldval) => trytb); #region 查找导航属性的关系、virtual 属性延时加载,动态产生新的重写类 diff --git a/Providers/FreeSql.Provider.MySql/MySqlCodeFirst.cs b/Providers/FreeSql.Provider.MySql/MySqlCodeFirst.cs index ae762748..c718608b 100644 --- a/Providers/FreeSql.Provider.MySql/MySqlCodeFirst.cs +++ b/Providers/FreeSql.Provider.MySql/MySqlCodeFirst.cs @@ -131,7 +131,8 @@ namespace FreeSql.MySql if (tboldname == null) { //创建表 - sb.Append("CREATE TABLE IF NOT EXISTS ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ( "); + var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"); + sb.Append("CREATE TABLE IF NOT EXISTS ").Append(createTableName).Append(" ( "); foreach (var tbcol in tb.ColumnsByPosition) { sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" "); @@ -146,14 +147,22 @@ namespace FreeSql.MySql foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); sb.Remove(sb.Length - 2, 2).Append("),"); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n UNIQUE KEY ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append("("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1); sb.Append("\r\n) Engine=InnoDB;\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(createTableName).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } continue; } //如果新表,旧表在一个数据库下,直接修改表名 @@ -235,19 +244,28 @@ where a.table_schema in ({0}) and a.table_name in ({1})", tboldname ?? tbname); var dsuksql = _commonUtils.FormatSql(@" select a.column_name, -a.constraint_name 'index_id' -from information_schema.key_column_usage a -where a.constraint_schema IN ({0}) and a.table_name IN ({1})", tboldname ?? tbname); - var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]) }); - foreach (var uk in tb.Uniques) +a.index_name 'index_id', +0 'IsDesc', +case when a.non_unique = 0 then 1 else 0 end 'IsUnique' +from information_schema.statistics a +where a.table_schema IN ({0}) and a.table_name IN ({1}) and a.index_name <> 'PRIMARY'", tboldname ?? tbname); + var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) }); + foreach (var uk in tb.Indexes) { - if (uk.Key == "PRIMARY" || string.IsNullOrEmpty(uk.Key) || uk.Value.Any() == false) continue; - var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Key, true) == 0).ToArray(); - if (dsukfind1.Any() == false || dsukfind1.Length != uk.Value.Count || dsukfind1.Where(a => uk.Value.Where(b => string.Compare(b.Attribute.Name, a[0], true) == 0).Any()).Count() != uk.Value.Count) + if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue; + var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Name, true) == 0).ToArray(); + if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => (a[3] == "1") == uk.IsUnique && uk.Columns.Where(b => string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length) { - if (dsukfind1.Any()) sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" DROP INDEX ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(";\r\n"); - sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); + if (dsukfind1.Any()) sbalter.Append("DROP INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(";\r\n"); + sbalter.Append("CREATE "); + if (uk.IsUnique) sbalter.Append("UNIQUE "); + sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append("("); + foreach (var tbcol in uk.Columns) + { + sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sbalter.Append(" DESC"); + sbalter.Append(", "); + } sbalter.Remove(sbalter.Length - 2, 2).Append(");\r\n"); } } @@ -277,12 +295,6 @@ where a.constraint_schema IN ({0}) and a.table_name IN ({1})", tboldname ?? tbna foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); sb.Remove(sb.Length - 2, 2).Append("),"); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n UNIQUE KEY ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append("("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1); sb.Append("\r\n) Engine=InnoDB;\r\n"); sb.Append("INSERT INTO ").Append(tmptablename).Append(" ("); @@ -310,6 +322,20 @@ where a.constraint_schema IN ({0}) and a.table_name IN ({1})", tboldname ?? tbna sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append(";\r\n"); sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n"); sb.Append("ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(";\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(tablename).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } } return sb.Length == 0 ? null : sb.ToString(); } diff --git a/Providers/FreeSql.Provider.MySql/MySqlDbFirst.cs b/Providers/FreeSql.Provider.MySql/MySqlDbFirst.cs index 2f2a339a..9df16ee1 100644 --- a/Providers/FreeSql.Provider.MySql/MySqlDbFirst.cs +++ b/Providers/FreeSql.Provider.MySql/MySqlDbFirst.cs @@ -252,21 +252,21 @@ where a.table_schema in ({1}) and a.table_name in ({0}) sql = string.Format(@" select -concat(a.constraint_schema, '.', a.table_name) 'table_id', +concat(a.table_schema, '.', a.table_name) 'table_id', a.column_name, -a.constraint_name 'index_id', -1 'IsUnique', -case when a.constraint_name = 'PRIMARY' then 1 else 0 end 'IsPrimaryKey', +a.index_name 'index_id', +case when a.non_unique = 0 then 1 else 0 end 'IsUnique', +case when a.index_name = 'PRIMARY' then 1 else 0 end 'IsPrimaryKey', 0 'IsClustered', 0 'IsDesc' -from information_schema.key_column_usage a -where a.constraint_schema in ({1}) and a.table_name in ({0}) and isnull(position_in_unique_constraint) +from information_schema.statistics a +where a.table_schema in ({1}) and a.table_name in ({0}) and a.index_name <> 'PRIMARY' ", loc8, databaseIn); ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); if (ds == null) return loc1; - var indexColumns = new Dictionary>>(); - var uniqueColumns = new Dictionary>>(); + var indexColumns = new Dictionary>(); + var uniqueColumns = new Dictionary>(); foreach (var row in ds) { string table_id = string.Concat(row[0]); @@ -275,29 +275,27 @@ where a.constraint_schema in ({1}) and a.table_name in ({0}) and isnull(position bool is_unique = string.Concat(row[3]) == "1"; bool is_primary_key = string.Concat(row[4]) == "1"; bool is_clustered = string.Concat(row[5]) == "1"; - int is_desc = int.Parse(string.Concat(row[6])); + bool is_desc = string.Concat(row[6]) == "1"; if (database.Length == 1) - { table_id = table_id.Substring(table_id.IndexOf('.') + 1); - } if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue; var loc9 = loc3[table_id][column]; if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key; - Dictionary> loc10 = null; - List loc11 = null; + Dictionary loc10 = null; + DbIndexInfo loc11 = null; if (!indexColumns.TryGetValue(table_id, out loc10)) - indexColumns.Add(table_id, loc10 = new Dictionary>()); + indexColumns.Add(table_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); if (is_unique && !is_primary_key) { if (!uniqueColumns.TryGetValue(table_id, out loc10)) - uniqueColumns.Add(table_id, loc10 = new Dictionary>()); + uniqueColumns.Add(table_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); } } foreach (string table_id in indexColumns.Keys) @@ -309,7 +307,7 @@ where a.constraint_schema in ({1}) and a.table_name in ({0}) and isnull(position { foreach (var column in uniqueColumns[table_id]) { - column.Value.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); + column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name)); loc2[table_id].UniquesDict.Add(column.Key, column.Value); } } @@ -372,14 +370,14 @@ where a.constraint_schema in ({1}) and a.table_name in ({0}) and not isnull(posi } foreach (var loc4 in loc2.Values) { - if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) - { - foreach (var loc5 in loc4.UniquesDict.First().Value) - { - loc5.IsPrimary = true; - loc4.Primarys.Add(loc5); - } - } + //if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) + //{ + // foreach (var loc5 in loc4.UniquesDict.First().Value.Columns) + // { + // loc5.Column.IsPrimary = true; + // loc4.Primarys.Add(loc5.Column); + // } + //} loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); loc4.Columns.Sort((c1, c2) => { diff --git a/Providers/FreeSql.Provider.Odbc/MySql/OdbcMySqlCodeFirst.cs b/Providers/FreeSql.Provider.Odbc/MySql/OdbcMySqlCodeFirst.cs index df99ba84..36b06ec7 100644 --- a/Providers/FreeSql.Provider.Odbc/MySql/OdbcMySqlCodeFirst.cs +++ b/Providers/FreeSql.Provider.Odbc/MySql/OdbcMySqlCodeFirst.cs @@ -119,7 +119,8 @@ namespace FreeSql.Odbc.MySql if (tboldname == null) { //创建表 - sb.Append("CREATE TABLE IF NOT EXISTS ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ( "); + var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"); + sb.Append("CREATE TABLE IF NOT EXISTS ").Append(createTableName).Append(" ( "); foreach (var tbcol in tb.ColumnsByPosition) { sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" "); @@ -134,14 +135,22 @@ namespace FreeSql.Odbc.MySql foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); sb.Remove(sb.Length - 2, 2).Append("),"); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n UNIQUE KEY ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append("("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1); sb.Append("\r\n) Engine=InnoDB;\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(createTableName).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } continue; } //如果新表,旧表在一个数据库下,直接修改表名 @@ -223,19 +232,28 @@ where a.table_schema in ({0}) and a.table_name in ({1})", tboldname ?? tbname); var dsuksql = _commonUtils.FormatSql(@" select a.column_name, -a.constraint_name 'index_id' -from information_schema.key_column_usage a -where a.constraint_schema IN ({0}) and a.table_name IN ({1})", tboldname ?? tbname); - var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]) }); - foreach (var uk in tb.Uniques) +a.index_name 'index_id', +0 'IsDesc', +case when a.non_unique = 0 then 1 else 0 end 'IsUnique' +from information_schema.statistics a +where a.table_schema IN ({0}) and a.table_name IN ({1}) and a.index_name <> 'PRIMARY'", tboldname ?? tbname); + var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) }); + foreach (var uk in tb.Indexes) { - if (uk.Key == "PRIMARY" || string.IsNullOrEmpty(uk.Key) || uk.Value.Any() == false) continue; - var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Key, true) == 0).ToArray(); - if (dsukfind1.Any() == false || dsukfind1.Length != uk.Value.Count || dsukfind1.Where(a => uk.Value.Where(b => string.Compare(b.Attribute.Name, a[0], true) == 0).Any()).Count() != uk.Value.Count) + if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue; + var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Name, true) == 0).ToArray(); + if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => (a[3] == "1") == uk.IsUnique && uk.Columns.Where(b => string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length) { - if (dsukfind1.Any()) sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" DROP INDEX ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(";\r\n"); - sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); + if (dsukfind1.Any()) sbalter.Append("DROP INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(";\r\n"); + sbalter.Append("CREATE "); + if (uk.IsUnique) sbalter.Append("UNIQUE "); + sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append("("); + foreach (var tbcol in uk.Columns) + { + sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sbalter.Append(" DESC"); + sbalter.Append(", "); + } sbalter.Remove(sbalter.Length - 2, 2).Append(");\r\n"); } } @@ -265,12 +283,6 @@ where a.constraint_schema IN ({0}) and a.table_name IN ({1})", tboldname ?? tbna foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); sb.Remove(sb.Length - 2, 2).Append("),"); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n UNIQUE KEY ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append("("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1); sb.Append("\r\n) Engine=InnoDB;\r\n"); sb.Append("INSERT INTO ").Append(tmptablename).Append(" ("); @@ -298,6 +310,20 @@ where a.constraint_schema IN ({0}) and a.table_name IN ({1})", tboldname ?? tbna sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append(";\r\n"); sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n"); sb.Append("ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(";\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(tablename).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } } return sb.Length == 0 ? null : sb.ToString(); } diff --git a/Providers/FreeSql.Provider.Odbc/MySql/OdbcMySqlDbFirst.cs b/Providers/FreeSql.Provider.Odbc/MySql/OdbcMySqlDbFirst.cs index 569df99f..6e9d3621 100644 --- a/Providers/FreeSql.Provider.Odbc/MySql/OdbcMySqlDbFirst.cs +++ b/Providers/FreeSql.Provider.Odbc/MySql/OdbcMySqlDbFirst.cs @@ -222,21 +222,21 @@ where a.table_schema in ({1}) and a.table_name in ({0}) sql = string.Format(@" select -concat(a.constraint_schema, '.', a.table_name) 'table_id', +concat(a.table_schema, '.', a.table_name) 'table_id', a.column_name, -a.constraint_name 'index_id', -1 'IsUnique', -case when a.constraint_name = 'PRIMARY' then 1 else 0 end 'IsPrimaryKey', +a.index_name 'index_id', +case when a.non_unique = 0 then 1 else 0 end 'IsUnique', +case when a.index_name = 'PRIMARY' then 1 else 0 end 'IsPrimaryKey', 0 'IsClustered', 0 'IsDesc' -from information_schema.key_column_usage a -where a.constraint_schema in ({1}) and a.table_name in ({0}) and isnull(position_in_unique_constraint) +from information_schema.statistics a +where a.table_schema in ({1}) and a.table_name in ({0}) and a.index_name <> 'PRIMARY' ", loc8, databaseIn); ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); if (ds == null) return loc1; - var indexColumns = new Dictionary>>(); - var uniqueColumns = new Dictionary>>(); + var indexColumns = new Dictionary>(); + var uniqueColumns = new Dictionary>(); foreach (var row in ds) { string table_id = string.Concat(row[0]); @@ -245,29 +245,27 @@ where a.constraint_schema in ({1}) and a.table_name in ({0}) and isnull(position bool is_unique = string.Concat(row[3]) == "1"; bool is_primary_key = string.Concat(row[4]) == "1"; bool is_clustered = string.Concat(row[5]) == "1"; - int is_desc = int.Parse(string.Concat(row[6])); + bool is_desc = string.Concat(row[6]) == "1"; if (database.Length == 1) - { table_id = table_id.Substring(table_id.IndexOf('.') + 1); - } if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue; var loc9 = loc3[table_id][column]; if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key; - Dictionary> loc10 = null; - List loc11 = null; + Dictionary loc10 = null; + DbIndexInfo loc11 = null; if (!indexColumns.TryGetValue(table_id, out loc10)) - indexColumns.Add(table_id, loc10 = new Dictionary>()); + indexColumns.Add(table_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); if (is_unique && !is_primary_key) { if (!uniqueColumns.TryGetValue(table_id, out loc10)) - uniqueColumns.Add(table_id, loc10 = new Dictionary>()); + uniqueColumns.Add(table_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); } } foreach (string table_id in indexColumns.Keys) @@ -279,7 +277,7 @@ where a.constraint_schema in ({1}) and a.table_name in ({0}) and isnull(position { foreach (var column in uniqueColumns[table_id]) { - column.Value.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); + column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name)); loc2[table_id].UniquesDict.Add(column.Key, column.Value); } } @@ -342,14 +340,14 @@ where a.constraint_schema in ({1}) and a.table_name in ({0}) and not isnull(posi } foreach (var loc4 in loc2.Values) { - if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) - { - foreach (var loc5 in loc4.UniquesDict.First().Value) - { - loc5.IsPrimary = true; - loc4.Primarys.Add(loc5); - } - } + //if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) + //{ + // foreach (var loc5 in loc4.UniquesDict.First().Value.Columns) + // { + // loc5.Column.IsPrimary = true; + // loc4.Primarys.Add(loc5.Column); + // } + //} loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); loc4.Columns.Sort((c1, c2) => { diff --git a/Providers/FreeSql.Provider.Odbc/Oracle/OdbcOracleCodeFirst.cs b/Providers/FreeSql.Provider.Odbc/Oracle/OdbcOracleCodeFirst.cs index e92eb774..c1646775 100644 --- a/Providers/FreeSql.Provider.Odbc/Oracle/OdbcOracleCodeFirst.cs +++ b/Providers/FreeSql.Provider.Odbc/Oracle/OdbcOracleCodeFirst.cs @@ -108,7 +108,8 @@ namespace FreeSql.Odbc.Oracle if (tboldname == null) { //创建表 - sb.Append("execute immediate 'CREATE TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ( "); + var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"); + sb.Append("execute immediate 'CREATE TABLE ").Append(createTableName).Append(" ( "); foreach (var tbcol in tb.ColumnsByPosition) { sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(","); @@ -121,14 +122,22 @@ namespace FreeSql.Odbc.Oracle foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); sb.Remove(sb.Length - 2, 2).Append("),"); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE ("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1); sb.Append("\r\n) \r\nLOGGING \r\nNOCOMPRESS \r\nNOCACHE\r\n';\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("execute immediate 'CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(createTableName).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(")';\r\n"); + } //备注 foreach (var tbcol in tb.ColumnsByPosition) { @@ -222,29 +231,39 @@ where a.owner={{0}} and a.table_name={{1}}", tboldname ?? tbname); if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true)); if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n"); } + + CreateOracleFunction(_orm); var dsuksql = _commonUtils.FormatSql(@" select -c.column_name, -c.constraint_name -from -all_constraints a, -all_cons_columns c -where -a.constraint_name = c.constraint_name -and a.owner = c.owner +nvl(freesql_long_2_varchar(a.index_name, c.table_name, c.column_position), c.column_name), +a.index_name, +case when c.descend = 'DESC' then 1 else 0 end, +case when a.uniqueness = 'UNIQUE' then 1 else 0 end, +c.column_position +from all_indexes a, +all_ind_columns c +where a.index_name = c.index_name +and a.table_owner = c.table_owner and a.table_name = c.table_name -and a.constraint_type in ('U') -and a.owner in ({0}) and a.table_name in ({1})", tboldname ?? tbname); - var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]) }); - foreach (var uk in tb.Uniques) +and a.owner in ({0}) and a.table_name in ({1}) +and not exists(select 1 from all_constraints where constraint_name = a.index_name and constraint_type = 'P')", tboldname ?? tbname); + var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]).Trim('"'), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) }).ToArray(); + foreach (var uk in tb.Indexes) { - if (string.IsNullOrEmpty(uk.Key) || uk.Value.Any() == false) continue; - var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Key, true) == 0).ToArray(); - if (dsukfind1.Any() == false || dsukfind1.Length != uk.Value.Count || dsukfind1.Where(a => uk.Value.Where(b => string.Compare(b.Attribute.Name, a[0], true) == 0).Any()).Count() != uk.Value.Count) + if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue; + var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Name, true) == 0).ToArray(); + if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => uk.Columns.Where(b => (a[3] == "1") == uk.IsUnique && string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length) { - if (dsukfind1.Any()) sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" DROP CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append("';\r\n"); - sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); + if (dsukfind1.Any()) sbalter.Append("execute immediate 'DROP INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append("';\r\n"); + sbalter.Append("execute immediate 'CREATE "); + if (uk.IsUnique) sbalter.Append("UNIQUE "); + sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append("("); + foreach (var tbcol in uk.Columns) + { + sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sbalter.Append(" DESC"); + sbalter.Append(", "); + } sbalter.Remove(sbalter.Length - 2, 2).Append(")';\r\n"); } } @@ -275,12 +294,6 @@ and a.owner in ({0}) and a.table_name in ({1})", tboldname ?? tbname); foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); sb.Remove(sb.Length - 2, 2).Append("),"); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE ("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1); sb.Append("\r\n) LOGGING \r\nNOCOMPRESS \r\nNOCACHE\r\n';\r\n"); //备注 @@ -315,6 +328,20 @@ and a.owner in ({0}) and a.table_name in ({1})", tboldname ?? tbname); sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append("';\r\n"); sb.Append("execute immediate 'DROP TABLE ").Append(tablename).Append("';\r\n"); sb.Append("execute immediate 'ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}")).Append("';\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("execute immediate 'CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(tablename).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(")';\r\n"); + } } Dictionary dicDeclare = new Dictionary(); Action dropSequence = seqname => @@ -407,5 +434,27 @@ and a.owner in ({0}) and a.table_name in ({1})", tboldname ?? tbname); sqlType += $"({data_length})"; return sqlType; } + + internal static void CreateOracleFunction(IFreeSql fsql) + { + fsql.Ado.ExecuteNonQuery(CommandType.Text, @" +CREATE OR REPLACE FUNCTION freesql_long_2_varchar ( + p_index_name IN user_ind_expressions.index_name%TYPE, + p_table_name IN user_ind_expressions.table_name%TYPE, + p_COLUMN_POSITION IN user_ind_expressions.table_name%TYPE) + RETURN VARCHAR2 +AS + l_COLUMN_EXPRESSION LONG; +BEGIN + SELECT COLUMN_EXPRESSION + INTO l_COLUMN_EXPRESSION + FROM user_ind_expressions + WHERE index_name = p_index_name + AND table_name = p_table_name + AND COLUMN_POSITION = p_COLUMN_POSITION; + + RETURN SUBSTR (l_COLUMN_EXPRESSION, 1, 4000); +END;"); + } } } \ No newline at end of file diff --git a/Providers/FreeSql.Provider.Odbc/Oracle/OdbcOracleDbFirst.cs b/Providers/FreeSql.Provider.Odbc/Oracle/OdbcOracleDbFirst.cs index 09c98ac7..84ce0cd3 100644 --- a/Providers/FreeSql.Provider.Odbc/Oracle/OdbcOracleDbFirst.cs +++ b/Providers/FreeSql.Provider.Odbc/Oracle/OdbcOracleDbFirst.cs @@ -287,61 +287,59 @@ where a.owner in ({1}) and a.table_name in ({0}) loc3[table_id][column].CsType = this.GetCsTypeInfo(loc3[table_id][column]); } + OdbcOracleCodeFirst.CreateOracleFunction(_orm); sql = string.Format(@" select -a.owner || '.' || a.table_name, -c.column_name, -c.constraint_name, -case when a.constraint_type = 'U' then 1 else 0 end, -case when a.constraint_type = 'P' then 1 else 0 end, +a.table_owner || '.' || a.table_name, +nvl(freesql_long_2_varchar(a.index_name, c.table_name, c.column_position), c.column_name), +c.index_name, +case when a.uniqueness = 'UNIQUE' then 1 else 0 end, 0, -0 -from -all_constraints a, -all_cons_columns c -where -a.constraint_name = c.constraint_name -and a.owner = c.owner +0, +case when c.descend = 'DESC' then 1 else 0 end, +c.column_position +from all_indexes a, +all_ind_columns c +where a.index_name = c.index_name +and a.table_owner = c.table_owner and a.table_name = c.table_name -and a.constraint_type in ('P', 'U') -and a.owner in ({1}) and a.table_name in ({0}) +and a.table_owner in ({1}) and a.table_name in ({0}) +and not exists(select 1 from all_constraints where constraint_name = a.index_name and constraint_type = 'P') ", loc8, databaseIn); ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); if (ds == null) return loc1; - var indexColumns = new Dictionary>>(); - var uniqueColumns = new Dictionary>>(); + var indexColumns = new Dictionary>(); + var uniqueColumns = new Dictionary>(); foreach (var row in ds) { string table_id = string.Concat(row[0]); - string column = string.Concat(row[1]); + string column = string.Concat(row[1]).Trim('"'); string index_id = string.Concat(row[2]); bool is_unique = string.Concat(row[3]) == "1"; bool is_primary_key = string.Concat(row[4]) == "1"; bool is_clustered = string.Concat(row[5]) == "1"; - int is_desc = int.Parse(string.Concat(row[6])); + bool is_desc = string.Concat(row[6]) == "1"; if (database.Length == 1) - { table_id = table_id.Substring(table_id.IndexOf('.') + 1); - } if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue; var loc9 = loc3[table_id][column]; if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key; - Dictionary> loc10 = null; - List loc11 = null; + Dictionary loc10 = null; + DbIndexInfo loc11 = null; if (!indexColumns.TryGetValue(table_id, out loc10)) - indexColumns.Add(table_id, loc10 = new Dictionary>()); + indexColumns.Add(table_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); if (is_unique && !is_primary_key) { if (!uniqueColumns.TryGetValue(table_id, out loc10)) - uniqueColumns.Add(table_id, loc10 = new Dictionary>()); + uniqueColumns.Add(table_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); } } foreach (string table_id in indexColumns.Keys) @@ -353,7 +351,7 @@ and a.owner in ({1}) and a.table_name in ({0}) { foreach (var column in uniqueColumns[table_id]) { - column.Value.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); + column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name)); loc2[table_id].UniquesDict.Add(column.Key, column.Value); } } @@ -441,14 +439,14 @@ and a.owner in ({1}) and a.table_name in ({0}) } foreach (var loc4 in loc2.Values) { - if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) - { - foreach (var loc5 in loc4.UniquesDict.First().Value) - { - loc5.IsPrimary = true; - loc4.Primarys.Add(loc5); - } - } + //if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) + //{ + // foreach (var loc5 in loc4.UniquesDict.First().Value.Columns) + // { + // loc5.Column.IsPrimary = true; + // loc4.Primarys.Add(loc5.Column); + // } + //} loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); loc4.Columns.Sort((c1, c2) => { diff --git a/Providers/FreeSql.Provider.Odbc/PostgreSQL/OdbcPostgreSQLCodeFirst.cs b/Providers/FreeSql.Provider.Odbc/PostgreSQL/OdbcPostgreSQLCodeFirst.cs index 607938f8..fdd063a8 100644 --- a/Providers/FreeSql.Provider.Odbc/PostgreSQL/OdbcPostgreSQLCodeFirst.cs +++ b/Providers/FreeSql.Provider.Odbc/PostgreSQL/OdbcPostgreSQLCodeFirst.cs @@ -108,7 +108,8 @@ namespace FreeSql.Odbc.PostgreSQL if (tboldname == null) { //创建表 - sb.Append("CREATE TABLE IF NOT EXISTS ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ( "); + var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"); + sb.Append("CREATE TABLE IF NOT EXISTS ").Append(createTableName).Append(" ( "); foreach (var tbcol in tb.ColumnsByPosition) { sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(","); @@ -120,14 +121,22 @@ namespace FreeSql.Odbc.PostgreSQL foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); sb.Remove(sb.Length - 2, 2).Append("),"); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1); sb.Append("\r\n) WITH (OIDS=FALSE);\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(createTableName).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } //备注 foreach (var tbcol in tb.ColumnsByPosition) { @@ -233,23 +242,32 @@ where ns.nspname = {0} and c.relname = {1}", tboldname ?? tbname); var dsuksql = _commonUtils.FormatSql(@" select c.attname, -b.relname +b.relname, +case when pg_index_column_has_property(b.oid, c.attnum, 'desc') = 't' then 1 else 0 end IsDesc, +case when indisunique = 't' then 1 else 0 end IsUnique from pg_index a inner join pg_class b on b.oid = a.indexrelid inner join pg_attribute c on c.attnum > 0 and c.attrelid = b.oid inner join pg_namespace ns on ns.oid = b.relnamespace inner join pg_class d on d.oid = a.indrelid -where ns.nspname in ({0}) and d.relname in ({1}) and a.indisunique = 't'", tboldname ?? tbname); - var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]) }); - foreach (var uk in tb.Uniques) +where ns.nspname in ({0}) and d.relname in ({1}) and a.indisprimary = 'f'", tboldname ?? tbname); + var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) }); + foreach (var uk in tb.Indexes) { - if (string.IsNullOrEmpty(uk.Key) || uk.Value.Any() == false) continue; - var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Key, true) == 0).ToArray(); - if (dsukfind1.Any() == false || dsukfind1.Length != uk.Value.Count || dsukfind1.Where(a => uk.Value.Where(b => string.Compare(b.Attribute.Name, a[0], true) == 0).Any()).Count() != uk.Value.Count) + if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue; + var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Name, true) == 0).ToArray(); + if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => uk.Columns.Where(b => (a[3] == "1") == uk.IsUnique && string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length) { - if (dsukfind1.Any()) sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" DROP CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(";\r\n"); - sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); + if (dsukfind1.Any()) sbalter.Append("DROP INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(";\r\n"); + sbalter.Append("CREATE "); + if (uk.IsUnique) sbalter.Append("UNIQUE "); + sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append("("); + foreach (var tbcol in uk.Columns) + { + sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sbalter.Append(" DESC"); + sbalter.Append(", "); + } sbalter.Remove(sbalter.Length - 2, 2).Append(");\r\n"); } } @@ -283,12 +301,6 @@ where pg_namespace.nspname={0} and pg_class.relname={1} and pg_constraint.contyp foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); sb.Remove(sb.Length - 2, 2).Append("),"); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1); sb.Append("\r\n) WITH (OIDS=FALSE);\r\n"); //备注 @@ -320,6 +332,20 @@ where pg_namespace.nspname={0} and pg_class.relname={1} and pg_constraint.contyp sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append(";\r\n"); sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n"); sb.Append("ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName(tbname[1])).Append(";\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(tablename).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } } foreach (var seqcol in seqcols) { diff --git a/Providers/FreeSql.Provider.Odbc/PostgreSQL/OdbcPostgreSQLDbFirst.cs b/Providers/FreeSql.Provider.Odbc/PostgreSQL/OdbcPostgreSQLDbFirst.cs index 94c26fa5..27adf73a 100644 --- a/Providers/FreeSql.Provider.Odbc/PostgreSQL/OdbcPostgreSQLDbFirst.cs +++ b/Providers/FreeSql.Provider.Odbc/PostgreSQL/OdbcPostgreSQLDbFirst.cs @@ -251,7 +251,7 @@ b.relname as index_id, case when a.indisunique then 1 else 0 end IsUnique, case when a.indisprimary then 1 else 0 end IsPrimary, case when a.indisclustered then 0 else 1 end IsClustered, -0 IsDesc, +case when pg_index_column_has_property(b.oid, c.attnum, 'desc') = 't' then 1 else 0 end IsDesc, a.indkey::text, c.attnum from pg_index a @@ -259,13 +259,13 @@ inner join pg_class b on b.oid = a.indexrelid inner join pg_attribute c on c.attnum > 0 and c.attrelid = b.oid inner join pg_namespace ns on ns.oid = b.relnamespace inner join pg_class d on d.oid = a.indrelid -where ns.nspname || '.' || d.relname in ({loc8}) +where ns.nspname || '.' || d.relname in ({loc8}) and a.indisprimary = 'f' "; ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); if (ds == null) return loc1; - var indexColumns = new Dictionary>>(); - var uniqueColumns = new Dictionary>>(); + var indexColumns = new Dictionary>(); + var uniqueColumns = new Dictionary>(); foreach (object[] row in ds) { var object_id = string.Concat(row[0]); @@ -274,7 +274,7 @@ where ns.nspname || '.' || d.relname in ({loc8}) var is_unique = string.Concat(row[3]) == "1"; var is_primary_key = string.Concat(row[4]) == "1"; var is_clustered = string.Concat(row[5]) == "1"; - var is_desc = int.Parse(string.Concat(row[6])); + var is_desc = string.Concat(row[6]) == "1"; var inkey = string.Concat(row[7]).Split(' '); var attnum = int.Parse(string.Concat(row[8])); attnum = int.Parse(inkey[attnum - 1]); @@ -290,20 +290,20 @@ where ns.nspname || '.' || d.relname in ({loc8}) var loc9 = loc3[object_id][column]; if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key; - Dictionary> loc10 = null; - List loc11 = null; + Dictionary loc10 = null; + DbIndexInfo loc11 = null; if (!indexColumns.TryGetValue(object_id, out loc10)) - indexColumns.Add(object_id, loc10 = new Dictionary>()); + indexColumns.Add(object_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); if (is_unique && !is_primary_key) { if (!uniqueColumns.TryGetValue(object_id, out loc10)) - uniqueColumns.Add(object_id, loc10 = new Dictionary>()); + uniqueColumns.Add(object_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); } } foreach (var object_id in indexColumns.Keys) @@ -315,7 +315,7 @@ where ns.nspname || '.' || d.relname in ({loc8}) { foreach (var column in uniqueColumns[object_id]) { - column.Value.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); + column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name)); loc2[object_id].UniquesDict.Add(column.Key, column.Value); } } @@ -382,14 +382,14 @@ where ns.nspname || '.' || b.relname in ({loc8}) } foreach (var loc4 in loc2.Values) { - if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) - { - foreach (var loc5 in loc4.UniquesDict.First().Value) - { - loc5.IsPrimary = true; - loc4.Primarys.Add(loc5); - } - } + //if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) + //{ + // foreach (var loc5 in loc4.UniquesDict.First().Value.Columns) + // { + // loc5.Column.IsPrimary = true; + // loc4.Primarys.Add(loc5.Column); + // } + //} loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); loc4.Columns.Sort((c1, c2) => { diff --git a/Providers/FreeSql.Provider.Odbc/SqlServer/OdbcSqlServerCodeFirst.cs b/Providers/FreeSql.Provider.Odbc/SqlServer/OdbcSqlServerCodeFirst.cs index 82a9d7bc..710d60e0 100644 --- a/Providers/FreeSql.Provider.Odbc/SqlServer/OdbcSqlServerCodeFirst.cs +++ b/Providers/FreeSql.Provider.Odbc/SqlServer/OdbcSqlServerCodeFirst.cs @@ -156,8 +156,9 @@ ELSE } if (tboldname == null) { - //创建新表 - sb.Append("use ").Append(_commonUtils.QuoteSqlName(tbname[0])).Append(";\r\nCREATE TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}.{tbname[2]}")).Append(" ( "); + //创建表 + var createTableName = _commonUtils.QuoteSqlName($"{tbname[1]}.{tbname[2]}"); + sb.Append("use ").Append(_commonUtils.QuoteSqlName(tbname[0])).Append(";\r\nCREATE TABLE ").Append(createTableName).Append(" ( "); var pkidx = 0; foreach (var tbcol in tb.ColumnsByPosition) { @@ -177,13 +178,21 @@ ELSE } sb.Append(","); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1).Append("\r\n);\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(createTableName).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } //备注 foreach (var tbcol in tb.ColumnsByPosition) { @@ -275,30 +284,39 @@ use " + database, tboldname ?? tbname); use [{0}]; select c.name -,d.name +,b.name +,case when a.is_descending_key = 1 then 1 else 0 end +,case when b.is_unique = 1 then 1 else 0 end 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 -left join sys.key_constraints d on d.parent_object_id = b.object_id and d.unique_index_id = b.index_id -where a.object_id in (object_id(N'[{1}].[{2}]')) and b.is_unique = 1; +where a.object_id in (object_id(N'[{1}].[{2}]')) and b.is_primary_key = 0; use " + database, tboldname ?? tbname); - var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]) }); - foreach (var uk in tb.Uniques) + var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) }); + foreach (var uk in tb.Indexes) { - if (string.IsNullOrEmpty(uk.Key) || uk.Value.Any() == false) continue; - var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Key, true) == 0).ToArray(); - if (dsukfind1.Any() == false || dsukfind1.Length != uk.Value.Count || dsukfind1.Where(a => uk.Value.Where(b => string.Compare(b.Attribute.Name, a[0], true) == 0).Any()).Count() != uk.Value.Count) + if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue; + var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Name, true) == 0).ToArray(); + if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => (a[3] == "1") == uk.IsUnique && uk.Columns.Where(b => string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length) { - if (dsukfind1.Any()) sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbname[2]}")).Append(" DROP CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(";\r\n"); - sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbname[2]}")).Append(" ADD CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); + if (dsukfind1.Any()) sbalter.Append("DROP INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}.{tbname[2]}")).Append(";\r\n"); + sbalter.Append("CREATE "); + if (uk.IsUnique) sbalter.Append("UNIQUE "); + sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}.{tbname[2]}")).Append("("); + foreach (var tbcol in uk.Columns) + { + sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sbalter.Append(" DESC"); + sbalter.Append(", "); + } sbalter.Remove(sbalter.Length - 2, 2).Append(");\r\n"); } } } if (istmpatler == false) { - sb.Append(sbalter).Append("\r\nuse " + database); + if (sbalter.Length > 0) + sb.Append(sbalter).Append("\r\nuse " + database); continue; } //创建临时表,数据导进临时表,然后删除原表,将临时表改名为原表名 @@ -337,12 +355,6 @@ use " + database, tboldname ?? tbname); sb.Append(","); idents = idents || tbcol.Attribute.IsIdentity == true; } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1).Append("\r\n);\r\n"); //备注 foreach (var tbcol in tb.ColumnsByPosition) @@ -377,6 +389,20 @@ use " + database, tboldname ?? tbname); if (idents) sb.Append("SET IDENTITY_INSERT ").Append(tmptablename).Append(" OFF;\r\n"); sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n"); sb.Append("EXECUTE sp_rename N'").Append(tmptablename).Append("', N'").Append(tbname[2]).Append("', 'OBJECT';\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(tablename).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } sb.Append("COMMIT;\r\n"); } return sb.Length == 0 ? null : sb.ToString(); diff --git a/Providers/FreeSql.Provider.Odbc/SqlServer/OdbcSqlServerDbFirst.cs b/Providers/FreeSql.Provider.Odbc/SqlServer/OdbcSqlServerDbFirst.cs index 337a424d..e2135a4b 100644 --- a/Providers/FreeSql.Provider.Odbc/SqlServer/OdbcSqlServerDbFirst.cs +++ b/Providers/FreeSql.Provider.Odbc/SqlServer/OdbcSqlServerDbFirst.cs @@ -267,24 +267,23 @@ use [{db}]; select a.object_id 'Object_id' ,c.name 'Column' -,d.name 'Index_id' +,b.name 'Index_id' ,b.is_unique 'IsUnique' ,b.is_primary_key 'IsPrimaryKey' ,cast(case when b.type_desc = 'CLUSTERED' then 1 else 0 end as bit) 'IsClustered' -,case when a.is_descending_key = 1 then 2 when a.is_descending_key = 0 then 1 else 0 end 'IsDesc' +,case when a.is_descending_key = 1 then 1 else 0 end 'IsDesc' 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 -left join sys.key_constraints d on d.parent_object_id = b.object_id and d.unique_index_id = b.index_id -where a.object_id in ({loc8}) +where a.object_id in ({loc8}) and b.is_primary_key = 0 ; use [{olddatabase}]; "; ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); if (ds == null) return loc1; - var indexColumns = new Dictionary>>(); - var uniqueColumns = new Dictionary>>(); + var indexColumns = new Dictionary>(); + var uniqueColumns = new Dictionary>(); foreach (object[] row in ds) { int object_id = int.Parse(string.Concat(row[0])); @@ -293,26 +292,26 @@ use [{olddatabase}]; 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])); + bool is_desc = string.Concat(row[6]) == "1"; 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; + Dictionary loc10 = null; + DbIndexInfo loc11 = null; if (!indexColumns.TryGetValue(object_id, out loc10)) - indexColumns.Add(object_id, loc10 = new Dictionary>()); + indexColumns.Add(object_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); if (is_unique && !is_primary_key) { if (!uniqueColumns.TryGetValue(object_id, out loc10)) - uniqueColumns.Add(object_id, loc10 = new Dictionary>()); + uniqueColumns.Add(object_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); } } foreach (var object_id in indexColumns.Keys) @@ -324,7 +323,7 @@ use [{olddatabase}]; { foreach (var column in uniqueColumns[object_id]) { - column.Value.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); + column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name)); loc2[object_id].UniquesDict.Add(column.Key, column.Value); } } @@ -402,14 +401,14 @@ use [{olddatabase}]; } foreach (var loc4 in loc2.Values) { - if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) - { - foreach (var loc5 in loc4.UniquesDict.First().Value) - { - loc5.IsPrimary = true; - loc4.Primarys.Add(loc5); - } - } + //if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) + //{ + // foreach (var loc5 in loc4.UniquesDict.First().Value.Columns) + // { + // loc5.Column.IsPrimary = true; + // loc4.Primarys.Add(loc5.Column); + // } + //} loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); loc4.Columns.Sort((c1, c2) => { diff --git a/Providers/FreeSql.Provider.Oracle/OracleCodeFirst.cs b/Providers/FreeSql.Provider.Oracle/OracleCodeFirst.cs index 51901c67..863b1cee 100644 --- a/Providers/FreeSql.Provider.Oracle/OracleCodeFirst.cs +++ b/Providers/FreeSql.Provider.Oracle/OracleCodeFirst.cs @@ -109,7 +109,8 @@ namespace FreeSql.Oracle if (tboldname == null) { //创建表 - sb.Append("execute immediate 'CREATE TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ( "); + var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"); + sb.Append("execute immediate 'CREATE TABLE ").Append(createTableName).Append(" ( "); foreach (var tbcol in tb.ColumnsByPosition) { sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(","); @@ -122,14 +123,22 @@ namespace FreeSql.Oracle foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); sb.Remove(sb.Length - 2, 2).Append("),"); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE ("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1); sb.Append("\r\n) \r\nLOGGING \r\nNOCOMPRESS \r\nNOCACHE\r\n';\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("execute immediate 'CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(createTableName).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(")';\r\n"); + } //备注 foreach (var tbcol in tb.ColumnsByPosition) { @@ -223,29 +232,38 @@ where a.owner={{0}} and a.table_name={{1}}", tboldname ?? tbname); if (tbcol.Attribute.IsIdentity == true) seqcols.Add((tbcol, tbname, tbcol.Attribute.IsIdentity == true)); if (string.IsNullOrEmpty(tbcol.Comment) == false) sbalter.Append("execute immediate 'COMMENT ON COLUMN ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbcol.Attribute.Name}")).Append(" IS ").Append(_commonUtils.FormatSql("{0}", tbcol.Comment ?? "").Replace("'", "''")).Append("';\r\n"); } + + CreateOracleFunction(_orm); var dsuksql = _commonUtils.FormatSql(@" select -c.column_name, -c.constraint_name -from -all_constraints a, -all_cons_columns c -where -a.constraint_name = c.constraint_name -and a.owner = c.owner +nvl(freesql_long_2_varchar(a.index_name, c.table_name, c.column_position), c.column_name), +a.index_name, +case when c.descend = 'DESC' then 1 else 0 end, +case when a.uniqueness = 'UNIQUE' then 1 else 0 end +from all_indexes a, +all_ind_columns c +where a.index_name = c.index_name +and a.table_owner = c.table_owner and a.table_name = c.table_name -and a.constraint_type in ('U') -and a.owner in ({0}) and a.table_name in ({1})", tboldname ?? tbname); - var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]) }); - foreach (var uk in tb.Uniques) +and a.owner in ({0}) and a.table_name in ({1}) +and not exists(select 1 from all_constraints where constraint_name = a.index_name and constraint_type = 'P')", tboldname ?? tbname); + var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]).Trim('"'), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) }).ToArray(); + foreach (var uk in tb.Indexes) { - if (string.IsNullOrEmpty(uk.Key) || uk.Value.Any() == false) continue; - var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Key, true) == 0).ToArray(); - if (dsukfind1.Any() == false || dsukfind1.Length != uk.Value.Count || dsukfind1.Where(a => uk.Value.Where(b => string.Compare(b.Attribute.Name, a[0], true) == 0).Any()).Count() != uk.Value.Count) + if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue; + var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Name, true) == 0).ToArray(); + if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => uk.Columns.Where(b => (a[3] == "1") == uk.IsUnique && string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length) { - if (dsukfind1.Any()) sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" DROP CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append("';\r\n"); - sbalter.Append("execute immediate 'ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); + if (dsukfind1.Any()) sbalter.Append("execute immediate 'DROP INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append("';\r\n"); + sbalter.Append("execute immediate 'CREATE "); + if (uk.IsUnique) sbalter.Append("UNIQUE "); + sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append("("); + foreach (var tbcol in uk.Columns) + { + sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sbalter.Append(" DESC"); + sbalter.Append(", "); + } sbalter.Remove(sbalter.Length - 2, 2).Append(")';\r\n"); } } @@ -276,12 +294,6 @@ and a.owner in ({0}) and a.table_name in ({1})", tboldname ?? tbname); foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); sb.Remove(sb.Length - 2, 2).Append("),"); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE ("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1); sb.Append("\r\n) LOGGING \r\nNOCOMPRESS \r\nNOCACHE\r\n';\r\n"); //备注 @@ -316,6 +328,20 @@ and a.owner in ({0}) and a.table_name in ({1})", tboldname ?? tbname); sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append("';\r\n"); sb.Append("execute immediate 'DROP TABLE ").Append(tablename).Append("';\r\n"); sb.Append("execute immediate 'ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}")).Append("';\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("execute immediate 'CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(tablename).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(")';\r\n"); + } } Dictionary dicDeclare = new Dictionary(); Action dropSequence = seqname => @@ -408,5 +434,26 @@ and a.owner in ({0}) and a.table_name in ({1})", tboldname ?? tbname); sqlType += $"({data_length})"; return sqlType; } + internal static void CreateOracleFunction(IFreeSql fsql) + { + fsql.Ado.ExecuteNonQuery(CommandType.Text, @" +CREATE OR REPLACE FUNCTION freesql_long_2_varchar ( + p_index_name IN user_ind_expressions.index_name%TYPE, + p_table_name IN user_ind_expressions.table_name%TYPE, + p_COLUMN_POSITION IN user_ind_expressions.table_name%TYPE) + RETURN VARCHAR2 +AS + l_COLUMN_EXPRESSION LONG; +BEGIN + SELECT COLUMN_EXPRESSION + INTO l_COLUMN_EXPRESSION + FROM user_ind_expressions + WHERE index_name = p_index_name + AND table_name = p_table_name + AND COLUMN_POSITION = p_COLUMN_POSITION; + + RETURN SUBSTR (l_COLUMN_EXPRESSION, 1, 4000); +END;"); + } } } \ No newline at end of file diff --git a/Providers/FreeSql.Provider.Oracle/OracleDbFirst.cs b/Providers/FreeSql.Provider.Oracle/OracleDbFirst.cs index a1ece3c1..e1bf1998 100644 --- a/Providers/FreeSql.Provider.Oracle/OracleDbFirst.cs +++ b/Providers/FreeSql.Provider.Oracle/OracleDbFirst.cs @@ -287,61 +287,59 @@ where a.owner in ({1}) and a.table_name in ({0}) loc3[table_id][column].CsType = this.GetCsTypeInfo(loc3[table_id][column]); } + OracleCodeFirst.CreateOracleFunction(_orm); sql = string.Format(@" select -a.owner || '.' || a.table_name, -c.column_name, -c.constraint_name, -case when a.constraint_type = 'U' then 1 else 0 end, -case when a.constraint_type = 'P' then 1 else 0 end, +a.table_owner || '.' || a.table_name, +nvl(freesql_long_2_varchar(a.index_name, c.table_name, c.column_position), c.column_name), +c.index_name, +case when a.uniqueness = 'UNIQUE' then 1 else 0 end, 0, -0 -from -all_constraints a, -all_cons_columns c -where -a.constraint_name = c.constraint_name -and a.owner = c.owner +0, +case when c.descend = 'DESC' then 1 else 0 end, +c.column_position +from all_indexes a, +all_ind_columns c +where a.index_name = c.index_name +and a.table_owner = c.table_owner and a.table_name = c.table_name -and a.constraint_type in ('P', 'U') -and a.owner in ({1}) and a.table_name in ({0}) +and a.table_owner in ({1}) and a.table_name in ({0}) +and not exists(select 1 from all_constraints where constraint_name = a.index_name and constraint_type = 'P') ", loc8, databaseIn); ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); if (ds == null) return loc1; - var indexColumns = new Dictionary>>(); - var uniqueColumns = new Dictionary>>(); + var indexColumns = new Dictionary>(); + var uniqueColumns = new Dictionary>(); foreach (var row in ds) { string table_id = string.Concat(row[0]); - string column = string.Concat(row[1]); + string column = string.Concat(row[1]).Trim('"'); string index_id = string.Concat(row[2]); bool is_unique = string.Concat(row[3]) == "1"; bool is_primary_key = string.Concat(row[4]) == "1"; bool is_clustered = string.Concat(row[5]) == "1"; - int is_desc = int.Parse(string.Concat(row[6])); + bool is_desc = string.Concat(row[6]) == "1"; if (database.Length == 1) - { table_id = table_id.Substring(table_id.IndexOf('.') + 1); - } if (loc3.ContainsKey(table_id) == false || loc3[table_id].ContainsKey(column) == false) continue; var loc9 = loc3[table_id][column]; if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key; - Dictionary> loc10 = null; - List loc11 = null; + Dictionary loc10 = null; + DbIndexInfo loc11 = null; if (!indexColumns.TryGetValue(table_id, out loc10)) - indexColumns.Add(table_id, loc10 = new Dictionary>()); + indexColumns.Add(table_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); if (is_unique && !is_primary_key) { if (!uniqueColumns.TryGetValue(table_id, out loc10)) - uniqueColumns.Add(table_id, loc10 = new Dictionary>()); + uniqueColumns.Add(table_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); } } foreach (string table_id in indexColumns.Keys) @@ -353,7 +351,7 @@ and a.owner in ({1}) and a.table_name in ({0}) { foreach (var column in uniqueColumns[table_id]) { - column.Value.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); + column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name)); loc2[table_id].UniquesDict.Add(column.Key, column.Value); } } @@ -441,14 +439,14 @@ and a.owner in ({1}) and a.table_name in ({0}) } foreach (var loc4 in loc2.Values) { - if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) - { - foreach (var loc5 in loc4.UniquesDict.First().Value) - { - loc5.IsPrimary = true; - loc4.Primarys.Add(loc5); - } - } + //if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) + //{ + // foreach (var loc5 in loc4.UniquesDict.First().Value.Columns) + // { + // loc5.Column.IsPrimary = true; + // loc4.Primarys.Add(loc5.Column); + // } + //} loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); loc4.Columns.Sort((c1, c2) => { diff --git a/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLCodeFirst.cs b/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLCodeFirst.cs index 5ed26c61..1fd94504 100644 --- a/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLCodeFirst.cs +++ b/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLCodeFirst.cs @@ -150,7 +150,8 @@ namespace FreeSql.PostgreSQL if (tboldname == null) { //创建表 - sb.Append("CREATE TABLE IF NOT EXISTS ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ( "); + var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"); + sb.Append("CREATE TABLE IF NOT EXISTS ").Append(createTableName).Append(" ( "); foreach (var tbcol in tb.ColumnsByPosition) { sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" ").Append(tbcol.Attribute.DbType).Append(","); @@ -162,14 +163,22 @@ namespace FreeSql.PostgreSQL foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); sb.Remove(sb.Length - 2, 2).Append("),"); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1); sb.Append("\r\n) WITH (OIDS=FALSE);\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(createTableName).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } //备注 foreach (var tbcol in tb.ColumnsByPosition) { @@ -275,23 +284,32 @@ where ns.nspname = {0} and c.relname = {1}", tboldname ?? tbname); var dsuksql = _commonUtils.FormatSql(@" select c.attname, -b.relname +b.relname, +case when pg_index_column_has_property(b.oid, c.attnum, 'desc') = 't' then 1 else 0 end IsDesc, +case when indisunique = 't' then 1 else 0 end IsUnique from pg_index a inner join pg_class b on b.oid = a.indexrelid inner join pg_attribute c on c.attnum > 0 and c.attrelid = b.oid inner join pg_namespace ns on ns.oid = b.relnamespace inner join pg_class d on d.oid = a.indrelid -where ns.nspname in ({0}) and d.relname in ({1}) and a.indisunique = 't'", tboldname ?? tbname); - var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]) }); - foreach (var uk in tb.Uniques) +where ns.nspname in ({0}) and d.relname in ({1}) and a.indisprimary = 'f'", tboldname ?? tbname); + var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) }); + foreach (var uk in tb.Indexes) { - if (string.IsNullOrEmpty(uk.Key) || uk.Value.Any() == false) continue; - var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Key, true) == 0).ToArray(); - if (dsukfind1.Any() == false || dsukfind1.Length != uk.Value.Count || dsukfind1.Where(a => uk.Value.Where(b => string.Compare(b.Attribute.Name, a[0], true) == 0).Any()).Count() != uk.Value.Count) + if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue; + var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Name, true) == 0).ToArray(); + if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => uk.Columns.Where(b => (a[3] == "1") == uk.IsUnique && string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length) { - if (dsukfind1.Any()) sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" DROP CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(";\r\n"); - sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ADD CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); + if (dsukfind1.Any()) sbalter.Append("DROP INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(";\r\n"); + sbalter.Append("CREATE "); + if (uk.IsUnique) sbalter.Append("UNIQUE "); + sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append("("); + foreach (var tbcol in uk.Columns) + { + sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sbalter.Append(" DESC"); + sbalter.Append(", "); + } sbalter.Remove(sbalter.Length - 2, 2).Append(");\r\n"); } } @@ -325,12 +343,6 @@ where pg_namespace.nspname={0} and pg_class.relname={1} and pg_constraint.contyp foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); sb.Remove(sb.Length - 2, 2).Append("),"); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1); sb.Append("\r\n) WITH (OIDS=FALSE);\r\n"); //备注 @@ -362,6 +374,20 @@ where pg_namespace.nspname={0} and pg_class.relname={1} and pg_constraint.contyp sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append(";\r\n"); sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n"); sb.Append("ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName(tbname[1])).Append(";\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(tablename).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } } foreach (var seqcol in seqcols) { diff --git a/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLDbFirst.cs b/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLDbFirst.cs index 517b8370..6c448916 100644 --- a/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLDbFirst.cs +++ b/Providers/FreeSql.Provider.PostgreSQL/PostgreSQLDbFirst.cs @@ -362,7 +362,7 @@ b.relname as index_id, case when a.indisunique then 1 else 0 end IsUnique, case when a.indisprimary then 1 else 0 end IsPrimary, case when a.indisclustered then 0 else 1 end IsClustered, -0 IsDesc, +case when pg_index_column_has_property(b.oid, c.attnum, 'desc') = 't' then 1 else 0 end IsDesc, a.indkey::text, c.attnum from pg_index a @@ -370,13 +370,13 @@ inner join pg_class b on b.oid = a.indexrelid inner join pg_attribute c on c.attnum > 0 and c.attrelid = b.oid inner join pg_namespace ns on ns.oid = b.relnamespace inner join pg_class d on d.oid = a.indrelid -where ns.nspname || '.' || d.relname in ({loc8}) +where ns.nspname || '.' || d.relname in ({loc8}) and a.indisprimary = 'f' "; ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); if (ds == null) return loc1; - var indexColumns = new Dictionary>>(); - var uniqueColumns = new Dictionary>>(); + var indexColumns = new Dictionary>(); + var uniqueColumns = new Dictionary>(); foreach (object[] row in ds) { var object_id = string.Concat(row[0]); @@ -385,7 +385,7 @@ where ns.nspname || '.' || d.relname in ({loc8}) var is_unique = string.Concat(row[3]) == "1"; var is_primary_key = string.Concat(row[4]) == "1"; var is_clustered = string.Concat(row[5]) == "1"; - var is_desc = int.Parse(string.Concat(row[6])); + var is_desc = string.Concat(row[6]) == "1"; var inkey = string.Concat(row[7]).Split(' '); var attnum = int.Parse(string.Concat(row[8])); attnum = int.Parse(inkey[attnum - 1]); @@ -401,20 +401,20 @@ where ns.nspname || '.' || d.relname in ({loc8}) var loc9 = loc3[object_id][column]; if (loc9.IsPrimary == false && is_primary_key) loc9.IsPrimary = is_primary_key; - Dictionary> loc10 = null; - List loc11 = null; + Dictionary loc10 = null; + DbIndexInfo loc11 = null; if (!indexColumns.TryGetValue(object_id, out loc10)) - indexColumns.Add(object_id, loc10 = new Dictionary>()); + indexColumns.Add(object_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); if (is_unique && !is_primary_key) { if (!uniqueColumns.TryGetValue(object_id, out loc10)) - uniqueColumns.Add(object_id, loc10 = new Dictionary>()); + uniqueColumns.Add(object_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); } } foreach (var object_id in indexColumns.Keys) @@ -426,7 +426,7 @@ where ns.nspname || '.' || d.relname in ({loc8}) { foreach (var column in uniqueColumns[object_id]) { - column.Value.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); + column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name)); loc2[object_id].UniquesDict.Add(column.Key, column.Value); } } @@ -493,14 +493,14 @@ where ns.nspname || '.' || b.relname in ({loc8}) } foreach (var loc4 in loc2.Values) { - if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) - { - foreach (var loc5 in loc4.UniquesDict.First().Value) - { - loc5.IsPrimary = true; - loc4.Primarys.Add(loc5); - } - } + //if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) + //{ + // foreach (var loc5 in loc4.UniquesDict.First().Value.Columns) + // { + // loc5.Column.IsPrimary = true; + // loc4.Primarys.Add(loc5.Column); + // } + //} loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); loc4.Columns.Sort((c1, c2) => { diff --git a/Providers/FreeSql.Provider.SqlServer/SqlServerCodeFirst.cs b/Providers/FreeSql.Provider.SqlServer/SqlServerCodeFirst.cs index e0b0d18d..98954af7 100644 --- a/Providers/FreeSql.Provider.SqlServer/SqlServerCodeFirst.cs +++ b/Providers/FreeSql.Provider.SqlServer/SqlServerCodeFirst.cs @@ -159,8 +159,9 @@ ELSE } if (tboldname == null) { - //创建新表 - sb.Append("use ").Append(_commonUtils.QuoteSqlName(tbname[0])).Append(";\r\nCREATE TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}.{tbname[2]}")).Append(" ( "); + //创建表 + var createTableName = _commonUtils.QuoteSqlName($"{tbname[1]}.{tbname[2]}"); + sb.Append("use ").Append(_commonUtils.QuoteSqlName(tbname[0])).Append(";\r\nCREATE TABLE ").Append(createTableName).Append(" ( "); var pkidx = 0; foreach (var tbcol in tb.ColumnsByPosition) { @@ -180,13 +181,21 @@ ELSE } sb.Append(","); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1).Append("\r\n);\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(createTableName).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } //备注 foreach (var tbcol in tb.ColumnsByPosition) { @@ -278,30 +287,39 @@ use " + database, tboldname ?? tbname); use [{0}]; select c.name -,d.name +,b.name +,case when a.is_descending_key = 1 then 1 else 0 end +,case when b.is_unique = 1 then 1 else 0 end 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 -left join sys.key_constraints d on d.parent_object_id = b.object_id and d.unique_index_id = b.index_id -where a.object_id in (object_id(N'[{1}].[{2}]')) and b.is_unique = 1; +where a.object_id in (object_id(N'[{1}].[{2}]')) and b.is_primary_key = 0; use " + database, tboldname ?? tbname); - var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]) }); - foreach (var uk in tb.Uniques) + var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) }); + foreach (var uk in tb.Indexes) { - if (string.IsNullOrEmpty(uk.Key) || uk.Value.Any() == false) continue; - var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Key, true) == 0).ToArray(); - if (dsukfind1.Any() == false || dsukfind1.Length != uk.Value.Count || dsukfind1.Where(a => uk.Value.Where(b => string.Compare(b.Attribute.Name, a[0], true) == 0).Any()).Count() != uk.Value.Count) + if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue; + var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Name, true) == 0).ToArray(); + if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => (a[3] == "1") == uk.IsUnique && uk.Columns.Where(b => string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length) { - if (dsukfind1.Any()) sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbname[2]}")).Append(" DROP CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(";\r\n"); - sbalter.Append("ALTER TABLE ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}.{tbname[2]}")).Append(" ADD CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); + if (dsukfind1.Any()) sbalter.Append("DROP INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}.{tbname[2]}")).Append(";\r\n"); + sbalter.Append("CREATE "); + if (uk.IsUnique) sbalter.Append("UNIQUE "); + sbalter.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}.{tbname[2]}")).Append("("); + foreach (var tbcol in uk.Columns) + { + sbalter.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sbalter.Append(" DESC"); + sbalter.Append(", "); + } sbalter.Remove(sbalter.Length - 2, 2).Append(");\r\n"); } } } if (istmpatler == false) { - sb.Append(sbalter).Append("\r\nuse " + database); + if (sbalter.Length > 0) + sb.Append(sbalter).Append("\r\nuse " + database); continue; } //创建临时表,数据导进临时表,然后删除原表,将临时表改名为原表名 @@ -340,12 +358,6 @@ use " + database, tboldname ?? tbname); sb.Append(","); idents = idents || tbcol.Attribute.IsIdentity == true; } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1).Append("\r\n);\r\n"); //备注 foreach (var tbcol in tb.ColumnsByPosition) @@ -380,6 +392,20 @@ use " + database, tboldname ?? tbname); if (idents) sb.Append("SET IDENTITY_INSERT ").Append(tmptablename).Append(" OFF;\r\n"); sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n"); sb.Append("EXECUTE sp_rename N'").Append(tmptablename).Append("', N'").Append(tbname[2]).Append("', 'OBJECT';\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(tablename).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } sb.Append("COMMIT;\r\n"); } return sb.Length == 0 ? null : sb.ToString(); diff --git a/Providers/FreeSql.Provider.SqlServer/SqlServerDbFirst.cs b/Providers/FreeSql.Provider.SqlServer/SqlServerDbFirst.cs index 35b91bee..a91ca3c9 100644 --- a/Providers/FreeSql.Provider.SqlServer/SqlServerDbFirst.cs +++ b/Providers/FreeSql.Provider.SqlServer/SqlServerDbFirst.cs @@ -270,24 +270,23 @@ use [{db}]; select a.object_id 'Object_id' ,c.name 'Column' -,d.name 'Index_id' +,b.name 'Index_id' ,b.is_unique 'IsUnique' ,b.is_primary_key 'IsPrimaryKey' ,cast(case when b.type_desc = 'CLUSTERED' then 1 else 0 end as bit) 'IsClustered' -,case when a.is_descending_key = 1 then 2 when a.is_descending_key = 0 then 1 else 0 end 'IsDesc' +,case when a.is_descending_key = 1 then 1 else 0 end 'IsDesc' 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 -left join sys.key_constraints d on d.parent_object_id = b.object_id and d.unique_index_id = b.index_id -where a.object_id in ({loc8}) +where a.object_id in ({loc8}) and b.is_primary_key = 0 ; use [{olddatabase}]; "; ds = _orm.Ado.ExecuteArray(CommandType.Text, sql); if (ds == null) return loc1; - var indexColumns = new Dictionary>>(); - var uniqueColumns = new Dictionary>>(); + var indexColumns = new Dictionary>(); + var uniqueColumns = new Dictionary>(); foreach (object[] row in ds) { int object_id = int.Parse(string.Concat(row[0])); @@ -296,26 +295,26 @@ use [{olddatabase}]; 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])); + bool is_desc = string.Concat(row[6]) == "1"; 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; + Dictionary loc10 = null; + DbIndexInfo loc11 = null; if (!indexColumns.TryGetValue(object_id, out loc10)) - indexColumns.Add(object_id, loc10 = new Dictionary>()); + indexColumns.Add(object_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); if (is_unique && !is_primary_key) { if (!uniqueColumns.TryGetValue(object_id, out loc10)) - uniqueColumns.Add(object_id, loc10 = new Dictionary>()); + uniqueColumns.Add(object_id, loc10 = new Dictionary()); if (!loc10.TryGetValue(index_id, out loc11)) - loc10.Add(index_id, loc11 = new List()); - loc11.Add(loc9); + loc10.Add(index_id, loc11 = new DbIndexInfo()); + loc11.Columns.Add(new DbIndexColumnInfo { Column = loc9, IsDesc = is_desc }); } } foreach (var object_id in indexColumns.Keys) @@ -327,7 +326,7 @@ use [{olddatabase}]; { foreach (var column in uniqueColumns[object_id]) { - column.Value.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); + column.Value.Columns.Sort((c1, c2) => c1.Column.Name.CompareTo(c2.Column.Name)); loc2[object_id].UniquesDict.Add(column.Key, column.Value); } } @@ -405,14 +404,14 @@ use [{olddatabase}]; } foreach (var loc4 in loc2.Values) { - if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) - { - foreach (var loc5 in loc4.UniquesDict.First().Value) - { - loc5.IsPrimary = true; - loc4.Primarys.Add(loc5); - } - } + //if (loc4.Primarys.Count == 0 && loc4.UniquesDict.Count > 0) + //{ + // foreach (var loc5 in loc4.UniquesDict.First().Value.Columns) + // { + // loc5.Column.IsPrimary = true; + // loc4.Primarys.Add(loc5.Column); + // } + //} loc4.Primarys.Sort((c1, c2) => c1.Name.CompareTo(c2.Name)); loc4.Columns.Sort((c1, c2) => { diff --git a/Providers/FreeSql.Provider.Sqlite/SqliteCodeFirst.cs b/Providers/FreeSql.Provider.Sqlite/SqliteCodeFirst.cs index 7ab66263..9d804e0c 100644 --- a/Providers/FreeSql.Provider.Sqlite/SqliteCodeFirst.cs +++ b/Providers/FreeSql.Provider.Sqlite/SqliteCodeFirst.cs @@ -99,7 +99,8 @@ namespace FreeSql.Sqlite if (tboldname == null) { //创建表 - sb.Append("CREATE TABLE IF NOT EXISTS ").Append(_commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}")).Append(" ( "); + var createTableName = _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}"); + sb.Append("CREATE TABLE IF NOT EXISTS ").Append(createTableName).Append(" ( "); foreach (var tbcol in tb.ColumnsByPosition) { sb.Append(" \r\n ").Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(" "); @@ -117,14 +118,22 @@ namespace FreeSql.Sqlite foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); sb.Remove(sb.Length - 2, 2).Append("),"); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1); sb.Append("\r\n) \r\n;\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(tbname[1]).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } continue; } //如果新表,旧表在一个模式下,直接修改表名 @@ -183,25 +192,26 @@ namespace FreeSql.Sqlite //添加列 istmpatler = true; } - var dsukMatches = _regexUK.Matches(dsql); var dsuk = new List(); - foreach (Match dsukm in dsukMatches) + var dbIndexes = _orm.Ado.ExecuteArray(CommandType.Text, $"PRAGMA {_commonUtils.QuoteSqlName(tbtmp[0])}.INDEX_LIST({_commonUtils.QuoteSqlName(tbtmp[1])})"); + foreach (var dbIndex in dbIndexes) { - var dbsukmg2 = dsukm.Groups[2].Value.Split(','); - if (dbsukmg2.Any() == false) continue; - foreach (var dbfield in dbsukmg2) + if (string.Concat(dbIndex[3]) == "pk") continue; + var dbIndexesColumns = _orm.Ado.ExecuteArray(CommandType.Text, $"PRAGMA {_commonUtils.QuoteSqlName(tbtmp[0])}.INDEX_INFO({dbIndex[1]})"); + var dbIndexesSql = string.Concat(_orm.Ado.ExecuteScalar(CommandType.Text, $"SELECT sql FROM sqlite_master WHERE name = '{dbIndex[1]}'")); + foreach (var dbcolumn in dbIndexesColumns) { - dsuk.Add(new[] { Regex.Match(dbfield, @"""([^""]+)""").Groups[1].Value, dsukm.Groups[1].Value }); + var dbcolumnName = string.Concat(dbcolumn[2]); + var isDesc = dbIndexesSql.IndexOf($@"{dbcolumnName}"" DESC", StringComparison.CurrentCultureIgnoreCase) == -1 ? "0" : "1"; + dsuk.Add(new[] { dbcolumnName, string.Concat(dbIndex[1]), isDesc, string.Concat(dbIndex[2]) }); ; } } - foreach (var uk in tb.Uniques) + foreach (var uk in tb.Indexes) { - if (string.IsNullOrEmpty(uk.Key) || uk.Value.Any() == false) continue; - var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Key, true) == 0).ToArray(); - if (dsukfind1.Any() == false || dsukfind1.Length != uk.Value.Count || dsukfind1.Where(a => uk.Value.Where(b => string.Compare(b.Attribute.Name, a[0], true) == 0).Any()).Count() != uk.Value.Count) - { + if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue; + var dsukfind1 = dsuk.Where(a => string.Compare(a[1], uk.Name, true) == 0).ToArray(); + if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => (a[3] == "1") == uk.IsUnique && uk.Columns.Where(b => string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length) istmpatler = true; - } } } if (istmpatler == false) @@ -212,6 +222,7 @@ namespace FreeSql.Sqlite //创建临时表,数据导进临时表,然后删除原表,将临时表改名为原表名 var tablename = tboldname == null ? _commonUtils.QuoteSqlName($"{tbname[0]}.{tbname[1]}") : _commonUtils.QuoteSqlName($"{tboldname[0]}.{tboldname[1]}"); + var tablenameOnlyTb = tboldname == null ? _commonUtils.QuoteSqlName(tbname[1]) : _commonUtils.QuoteSqlName(tboldname[1]); var tmptablename = _commonUtils.QuoteSqlName($"{tbname[0]}._FreeSqlTmp_{tbname[1]}"); //创建临时表 //创建表 @@ -234,12 +245,6 @@ namespace FreeSql.Sqlite foreach (var tbcol in tb.Primarys) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); sb.Remove(sb.Length - 2, 2).Append("),"); } - foreach (var uk in tb.Uniques) - { - sb.Append(" \r\n CONSTRAINT ").Append(_commonUtils.QuoteSqlName(uk.Key)).Append(" UNIQUE("); - foreach (var tbcol in uk.Value) sb.Append(_commonUtils.QuoteSqlName(tbcol.Attribute.Name)).Append(", "); - sb.Remove(sb.Length - 2, 2).Append("),"); - } sb.Remove(sb.Length - 1, 1); sb.Append("\r\n) \r\n;\r\n"); sb.Append("INSERT INTO ").Append(tmptablename).Append(" ("); @@ -268,9 +273,22 @@ namespace FreeSql.Sqlite sb.Remove(sb.Length - 2, 2).Append(" FROM ").Append(tablename).Append(";\r\n"); sb.Append("DROP TABLE ").Append(tablename).Append(";\r\n"); sb.Append("ALTER TABLE ").Append(tmptablename).Append(" RENAME TO ").Append(_commonUtils.QuoteSqlName($"{tbname[1]}")).Append(";\r\n"); + //创建表的索引 + foreach (var uk in tb.Indexes) + { + sb.Append("CREATE "); + if (uk.IsUnique) sb.Append("UNIQUE "); + sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(uk.Name)).Append(" ON ").Append(tablenameOnlyTb).Append("("); + foreach (var tbcol in uk.Columns) + { + sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); + if (tbcol.IsDesc) sb.Append(" DESC"); + sb.Append(", "); + } + sb.Remove(sb.Length - 2, 2).Append(");\r\n"); + } } return sb.Length == 0 ? null : sb.ToString(); } - static Regex _regexUK = new Regex(@"CONSTRAINT\s*""([^""]+)""\s*UNIQUE\s*\(([^\)]+)\)", RegexOptions.IgnoreCase | RegexOptions.Compiled); } } \ No newline at end of file