|
12 | 12 | #endregion |
13 | 13 |
|
14 | 14 | using DotNetProjects.Migrator.Framework; |
| 15 | +using DotNetProjects.Migrator.Providers.Models; |
15 | 16 | using Migrator.Framework; |
16 | 17 | using Migrator.Framework.Loggers; |
17 | 18 | using Migrator.Framework.SchemaBuilder; |
@@ -143,31 +144,71 @@ public virtual Column[] GetColumns(string table) |
143 | 144 | public virtual ForeignKeyConstraint[] GetForeignKeyConstraints(string table) |
144 | 145 | { |
145 | 146 | var constraints = new List<ForeignKeyConstraint>(); |
| 147 | + var sb = new StringBuilder(); |
| 148 | + sb.AppendLine("SELECT"); |
| 149 | + sb.AppendLine(" tc.CONSTRAINT_NAME AS FK_KEY,"); |
| 150 | + sb.AppendLine(" tc.TABLE_SCHEMA,"); |
| 151 | + sb.AppendLine(" tc.TABLE_NAME AS CHILD_TABLE,"); |
| 152 | + sb.AppendLine(" kcu.COLUMN_NAME AS CHILD_COLUMN,"); |
| 153 | + sb.AppendLine(" ccu.TABLE_NAME AS PARENT_TABLE,"); |
| 154 | + sb.AppendLine(" ccu.COLUMN_NAME AS PARENT_COLUMN"); |
| 155 | + sb.AppendLine("FROM "); |
| 156 | + sb.AppendLine(" INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc "); |
| 157 | + sb.AppendLine("JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE as kcu"); |
| 158 | + sb.AppendLine(" ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME AND tc.TABLE_SCHEMA = kcu.TABLE_SCHEMA"); |
| 159 | + sb.AppendLine("JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu"); |
| 160 | + sb.AppendLine(" ON tc.CONSTRAINT_NAME = ccu.CONSTRAINT_NAME AND tc.TABLE_SCHEMA = ccu.TABLE_SCHEMA"); |
| 161 | + sb.AppendLine($"WHERE LOWER(tc.TABLE_NAME) = LOWER('{table}') AND tc.CONSTRAINT_TYPE = 'FOREIGN KEY'"); |
| 162 | + sb.AppendLine("ORDER BY kcu.ORDINAL_POSITION"); |
| 163 | + |
| 164 | + var sql = sb.ToString(); |
| 165 | + List<ForeignKeyConstraintItem> foreignKeyConstraintItems = []; |
| 166 | + |
146 | 167 | using (var cmd = CreateCommand()) |
147 | | - using ( |
148 | | - var reader = |
149 | | - // TODO: |
150 | | - // In this statement the naming of alias PK is misleading since INFORMATION_SCHEMA.TABLE_CONSTRAINTS (alias PK) is the child |
151 | | - // while INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS (alias C) is the parent |
152 | | - ExecuteQuery( |
153 | | - cmd, string.Format("SELECT K_Table = FK.TABLE_NAME, FK_Column = CU.COLUMN_NAME, PK_Table = PK.TABLE_NAME, PK_Column = PT.COLUMN_NAME, Constraint_Name = C.CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME INNER JOIN ( SELECT i1.TABLE_NAME, i2.COLUMN_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' ) PT ON PT.TABLE_NAME = PK.TABLE_NAME WHERE FK.table_name = '{0}'", table))) |
| 168 | + using (var reader = ExecuteQuery(cmd, sql)) |
154 | 169 | { |
155 | 170 | while (reader.Read()) |
156 | 171 | { |
157 | | - var constraint = new ForeignKeyConstraint |
| 172 | + var constraintItem = new ForeignKeyConstraintItem |
158 | 173 | { |
159 | | - Name = reader.GetString(4), |
160 | | - ParentTable = reader.GetString(0), |
161 | | - ParentColumns = [reader.GetString(1)], |
162 | | - ChildTable = reader.GetString(2), |
163 | | - ChildColumns = [reader.GetString(3)] |
| 174 | + SchemaName = reader.GetString(reader.GetOrdinal("TABLE_SCHEMA")), |
| 175 | + ForeignKeyName = reader.GetString(reader.GetOrdinal("FK_KEY")), |
| 176 | + ChildTableName = reader.GetString(reader.GetOrdinal("CHILD_TABLE")), |
| 177 | + ChildColumnName = reader.GetString(reader.GetOrdinal("CHILD_COLUMN")), |
| 178 | + ParentTableName = reader.GetString(reader.GetOrdinal("PARENT_TABLE")), |
| 179 | + ParentColumnName = reader.GetString(reader.GetOrdinal("PARENT_COLUMN")) |
164 | 180 | }; |
165 | 181 |
|
166 | | - constraints.Add(constraint); |
| 182 | + foreignKeyConstraintItems.Add(constraintItem); |
167 | 183 | } |
168 | 184 | } |
169 | 185 |
|
170 | | - return constraints.ToArray(); |
| 186 | + var schemaChildTableGroups = foreignKeyConstraintItems.GroupBy(x => new { x.SchemaName, x.ChildTableName }).Count(); |
| 187 | + |
| 188 | + if (schemaChildTableGroups > 1) |
| 189 | + { |
| 190 | + throw new MigrationException($"Duplicates found (grouping by schema name and child table name). Since we do not offer schemas in '{nameof(GetForeignKeyConstraints)}' at this moment in time we cannot filter your target schema. Your database use the same table name in different schemas."); |
| 191 | + } |
| 192 | + |
| 193 | + var groups = foreignKeyConstraintItems.GroupBy(x => x.ForeignKeyName); |
| 194 | + |
| 195 | + foreach (var group in groups) |
| 196 | + { |
| 197 | + var first = group.First(); |
| 198 | + |
| 199 | + var foreignKeyConstraint = new ForeignKeyConstraint |
| 200 | + { |
| 201 | + Name = first.ForeignKeyName, |
| 202 | + ParentTable = first.ParentTableName, |
| 203 | + ParentColumns = [.. group.Select(x => x.ParentColumnName).Distinct()], |
| 204 | + ChildTable = first.ChildTableName, |
| 205 | + ChildColumns = [.. group.Select(x => x.ChildColumnName).Distinct()] |
| 206 | + }; |
| 207 | + |
| 208 | + constraints.Add(foreignKeyConstraint); |
| 209 | + } |
| 210 | + |
| 211 | + return [.. constraints]; |
171 | 212 | } |
172 | 213 |
|
173 | 214 | public virtual string[] GetConstraints(string table) |
@@ -1754,20 +1795,23 @@ public virtual void AddTable(string table, string engine, string columns) |
1754 | 1795 | { |
1755 | 1796 | table = _dialect.TableNameNeedsQuote ? _dialect.Quote(table) : table; |
1756 | 1797 | var sqlCreate = string.Format("CREATE TABLE {0} ({1})", table, columns); |
| 1798 | + |
1757 | 1799 | ExecuteNonQuery(sqlCreate); |
1758 | 1800 | } |
1759 | 1801 |
|
1760 | 1802 | public virtual List<string> GetPrimaryKeys(IEnumerable<Column> columns) |
1761 | 1803 | { |
1762 | | - var pks = new List<string>(); |
| 1804 | + var primaryKeys = new List<string>(); |
| 1805 | + |
1763 | 1806 | foreach (var col in columns) |
1764 | 1807 | { |
1765 | 1808 | if (col.IsPrimaryKey) |
1766 | 1809 | { |
1767 | | - pks.Add(col.Name); |
| 1810 | + primaryKeys.Add(col.Name); |
1768 | 1811 | } |
1769 | 1812 | } |
1770 | | - return pks; |
| 1813 | + |
| 1814 | + return primaryKeys; |
1771 | 1815 | } |
1772 | 1816 |
|
1773 | 1817 | public virtual void AddColumnDefaultValue(string table, string column, object defaultValue) |
|
0 commit comments