diff --git a/src/Migrator/Framework/ITransformationProvider.cs b/src/Migrator/Framework/ITransformationProvider.cs index d49f1d8..b40837f 100644 --- a/src/Migrator/Framework/ITransformationProvider.cs +++ b/src/Migrator/Framework/ITransformationProvider.cs @@ -598,7 +598,7 @@ IDataReader SelectComplex(IDbCommand cmd, string table, string[] columns, string /// /// /// - string Encode(Guid guid); + object Encode(Guid guid); /// /// Change the target database diff --git a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs index c2dc593..cb35698 100644 --- a/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs +++ b/src/Migrator/Providers/Impl/Oracle/OracleTransformationProvider.cs @@ -448,7 +448,7 @@ void GuardAgainstMaximumColumnNameLengthForOracle(string name, Column[] columns) } } - public override string Encode(Guid guid) + public override object Encode(Guid guid) { byte[] bytes = guid.ToByteArray(); var hex = new StringBuilder(bytes.Length * 2); diff --git a/src/Migrator/Providers/NoOpTransformationProvider.cs b/src/Migrator/Providers/NoOpTransformationProvider.cs index 7d9bcf2..0ec86cd 100644 --- a/src/Migrator/Providers/NoOpTransformationProvider.cs +++ b/src/Migrator/Providers/NoOpTransformationProvider.cs @@ -440,7 +440,7 @@ public string QuoteTableNameIfRequired(string name) throw new NotImplementedException(); } - public string Encode(Guid guid) + public object Encode(Guid guid) { return guid.ToString(); } diff --git a/src/Migrator/Providers/TransformationProvider.cs b/src/Migrator/Providers/TransformationProvider.cs index ef07e61..e7cec99 100644 --- a/src/Migrator/Providers/TransformationProvider.cs +++ b/src/Migrator/Providers/TransformationProvider.cs @@ -1537,9 +1537,9 @@ public virtual string QuoteTableNameIfRequired(string name) return name; } - public virtual string Encode(Guid guid) + public virtual object Encode(Guid guid) { - return guid.ToString(); + return guid; } public virtual string[] QuoteColumnNamesIfRequired(params string[] columnNames) diff --git a/src/Migrator/Tools/CreateNonclusteredDump.cs b/src/Migrator/Tools/CreateNonclusteredDump.cs new file mode 100644 index 0000000..36e3b1a --- /dev/null +++ b/src/Migrator/Tools/CreateNonclusteredDump.cs @@ -0,0 +1,78 @@ +using Migrator.Framework; +using System; + +using System.IO; +using System.Linq; +using Index = Migrator.Framework.Index; + +namespace Migrator.Tools +{ + [Migration(62)] + internal class CreateNonclusteredDump : Migration + { + public override void Up() + { + + var tables = Database.GetTables(); + var tab = tables.Where(o => o.ToUpper().StartsWith("WMS") || o.ToUpper().StartsWith("aaCOMMON") || o.ToUpper().StartsWith("aaVISU") || o.ToUpper().StartsWith("aaMFCV2")).ToList(); + string variable = ""; + string removeFKString = ""; + string removePKString = ""; + string removeIndexString = ""; + string addPKString = ""; + string addFKString = ""; + foreach (var table in tab) + { + foreach (var fk in Database.GetForeignKeyConstraints(table)) + { + removeFKString += $"Database.RemoveForeignKey(\"{table}\", \"{fk.Name}\");"; + var fkcols = fk.Columns; + var pkcols = fk.PkColumns; + var arr = pkcols.ToArray(); + for (int i = 0; i < arr.Length; i++) + { + arr[i] = $"\"{arr[i]}\""; + } + addFKString += $"Database.AddForeignKey(\"{fk.Name}\", \"{fk.Table}\", {doArr(fkcols)}, \"{fk.PkTable}\", {doArr(pkcols)});"; + } + Index[] inds = Database.GetIndexes(table); + var pK = inds.FirstOrDefault(o => o.PrimaryKey && o.KeyColumns.Length == 1); + if (pK == null) + continue; + var pkCol = Database.GetColumnByName(table, pK.KeyColumns[0]); + if (pkCol.Type != System.Data.DbType.Guid) + continue; + + string var = $"pK_{table}String"; + variable += $"String {var}={String.Format("getVariableName(\"{0}\");", table)}"; + removePKString += $"Database.RemovePrimaryKey(\"{table}\");"; + removeIndexString += $"Database.RemoveIndex(\"{table}\",{String.Format("{0}", var)});"; + addPKString += $"Database.AddPrimaryKeyNonClustered({String.Format("{0}", var)}, \"{table}\", new string[] { String.Format("{{\"{0}\"}}", pK.KeyColumns[0]) });"; + } + File.WriteAllText(@"c:\mlog\wms.txt", variable + "" + removeFKString + "" + removePKString + "" + removeIndexString + "" + addPKString + "" + addFKString); + } + private string getVariableName(string table) + { + Index[] inds = Database.GetIndexes(table); + var pK = inds.FirstOrDefault(o => o.PrimaryKey && o.KeyColumns.Length == 1); + if (pK == null) + return $"PK_{table}_N"; + var pkCol = Database.GetColumnByName(table, pK.KeyColumns[0]); + if (pkCol.Type != System.Data.DbType.Guid) + return $"PK_{table}_N"; + return pK.Name; + } + private string doArr(string[] arr) + { + for (int i = 0; i < arr.Length; i++) + { + arr[i] = $"\"{arr[i]}\""; + } + return $"new string[]{String.Format("{{{0}}}", string.Join(",", arr))}"; + } + + public override void Down() + { + } + } +} diff --git a/src/Migrator/Tools/SchemaDumper.cs b/src/Migrator/Tools/SchemaDumper.cs index 31c1153..f61ce09 100755 --- a/src/Migrator/Tools/SchemaDumper.cs +++ b/src/Migrator/Tools/SchemaDumper.cs @@ -13,10 +13,12 @@ using System; using System.Collections.Generic; +using System.Data; using System.IO; using System.Linq; using Migrator.Framework; using Migrator.Providers; +using ForeignKeyConstraint = Migrator.Framework.ForeignKeyConstraint; using Index = Migrator.Framework.Index; namespace Migrator.Tools @@ -28,42 +30,71 @@ public class SchemaDumper List foreignKeys = new List(); List columns = new List(); string dumpResult; - public SchemaDumper(ProviderTypes provider, string connectionString, string defaultSchema, string path = null,string tablePrefix = null) + /// + /// Creates a dumpfile of a MsSQL-Database and saves it to a specified path. It is possible to do a dump of both schema and/or data. + /// + /// e. g. ProviderTypes.SqlServer + /// + /// needed for TransformationProvider + /// directory and name of dumpfile. e.g. c:\test\dump.txt + /// + /// true when schema of db shall be dumped, default true + /// true when data shalle be dumped, default false + public SchemaDumper(ProviderTypes providerType, string connectionString, string defaultSchema, string path = null, string tablePrefix = null, bool isSchema = true, bool isData = false) { - _provider = ProviderFactory.Create(provider, connectionString, defaultSchema); - this.Dump(tablePrefix, path); + _provider = ProviderFactory.Create(providerType, connectionString, defaultSchema); + this.Dump(tablePrefix, path, isSchema, isData); } public string GetDump() { return this.dumpResult; } - private void Dump(string tablePrefix, string path) + + private void Dump(string tablePrefix, string path, bool isSchema = true, bool isData = false) { if (String.IsNullOrEmpty(tablePrefix)) - this.tables = this._provider.GetTables(); + this.tables = this._provider.GetTables().Where(o => o != "SchemaInfo").ToArray(); else - this.tables = this._provider.GetTables().Where(o => o.ToUpper().StartsWith(tablePrefix.ToUpper())).ToArray(); + this.tables = this._provider.GetTables().Where(o => o != "SchemaInfo" && o.ToUpper().StartsWith(tablePrefix.ToUpper())).ToArray(); - foreach (var tab in this.tables) + if (isSchema) { - foreignKeys.AddRange(this._provider.GetForeignKeyConstraints(tab)); + foreach (var tab in this.tables) + { + foreignKeys.AddRange(this._provider.GetForeignKeyConstraints(tab)); + } } + var writer = new StringWriter(); writer.WriteLine("using System.Data;"); writer.WriteLine("using Migrator.Framework;\n"); + + writer.WriteLine($"namespace MCC.{tablePrefix}.DL.DBMigration"); + writer.WriteLine("{"); + writer.WriteLine("\t[Migration(1)]"); - writer.WriteLine("\tpublic class SchemaDump : Migration"); + writer.WriteLine("\tpublic class Migration_01 : Migration"); writer.WriteLine("\t{"); writer.WriteLine("\tpublic override void Up()"); writer.WriteLine("\t{"); - this.addTableStatement(writer); - this.addForeignKeys(writer); + if (isSchema) + { + this.addTableStatement(writer); + this.addForeignKeys(writer); + if (!String.IsNullOrEmpty(tablePrefix)) + writer.WriteLine("\n\t\t" + $@"for (int i = XXXX; i < XXXXX; i++,this.Database.MigrationApplied(i,{String.Format("\"{0}\"", tablePrefix.ToUpper())}));"); + + } + if (isData) + this.GetInserts(this.tables, writer); + writer.WriteLine("\t}"); writer.WriteLine("\tpublic override void Down(){}"); - writer.WriteLine("}"); + writer.WriteLine("}\n}"); this.dumpResult = writer.ToString(); - File.WriteAllText(path, dumpResult); + if (!String.IsNullOrEmpty(path)) + File.WriteAllText(path, dumpResult); } private string GetListString(string[] list) @@ -83,15 +114,14 @@ private void addForeignKeys(StringWriter writer) string[] fkCols = fk.Columns; foreach (var col in fkCols) writer.WriteLine($"\t\tDatabase.AddForeignKey(\"{fk.Name}\", \"{fk.Table}\", {this.GetListString(fk.Columns)}, \"{fk.PkTable}\", {this.GetListString(fk.PkColumns)});"); - //this._provider.AddForeignKey(name, fktable, fkcols, pktable, primaryCols); } } private void addTableStatement(StringWriter writer) { foreach (string table in this.tables) { - string cols = this.getColsStatement(table); - writer.WriteLine($"\t\tDatabase.AddTable(\"{table}\",{cols});"); + string cols = this.GetColsStatement(table); + writer.WriteLine($"\t\tDatabase.AddTable(\"{table}\",{cols.Replace("\"DateTime.UtcNow\"", "DateTime.UtcNow")});"); this.AddIndexes(table, writer); } } @@ -101,8 +131,13 @@ private void AddIndexes(string table, StringWriter writer) Index[] inds = this._provider.GetIndexes(table); foreach (Index ind in inds) { + if (ind.Unique == true) + if (this.UniquAlreadyCreated.Contains(table)) + continue; if (ind.PrimaryKey == true) { + if (this.PKAlreadyCreated.Contains(table)) + continue; string nonclusteredString = (ind.Clustered == false ? "NonClustered" : ""); string[] keys = ind.KeyColumns; @@ -114,35 +149,81 @@ private void AddIndexes(string table, StringWriter writer) writer.WriteLine($"\t\tDatabase.AddPrimaryKey{nonclusteredString}(\"{ind.Name}\",\"{table}\",new string[]{String.Format("{{{0}}}", keysString)});"); continue; } - writer.WriteLine($"\t\tDatabase.AddIndex(\"{table}\",new Index() { String.Format("{{Name = \"{0}\",Clustered = {1}, KeyColumns={2}, IncludeColumns={3}, Unique={4}, UniqueConstraint={5}}}", ind.Name, ind.Clustered.ToString().ToLower(), this.GetListString(ind.KeyColumns), this.GetListString(ind.IncludeColumns), ind.Unique.ToString().ToLower(), ind.UniqueConstraint.ToString().ToLower()) });"); + writer.WriteLine($"\t\tDatabase.AddIndex(\"{table}\",new Index() { String.Format("{{Name = \"{0}\",Clustered = {1}, KeyColumns={2}, IncludeColumns={3}, Unique={4}, UniqueConstraint={5}}}", GetIndexNameOracleConform(ind.Name), ind.Clustered.ToString().ToLower(), this.GetListString(ind.KeyColumns), this.GetListString(ind.IncludeColumns), ind.Unique.ToString().ToLower(), ind.UniqueConstraint.ToString().ToLower()) });"); } } - - private string getColsStatement(string table) + private string GetIndexNameOracleConform(string s) + { + var result = s.Substring(0, s.Length > 30 ? 30 : s.Length); + return result; + } + private string GetColsStatement(string table) { Column[] cols = this._provider.GetColumns(table); List colList = new List(); foreach (var col in cols) { - colList.Add(this.getColStatement(col, table)); + var s = this.GetColStatement(col, table); + colList.Add(s.Replace(",)", ")")); } string result = String.Format("{0}", string.Join(",", colList)); return result; } - private string getColStatement(Column col, string table) + private string GetColStatement(Column col, string table) { + string size = col.Size.ToString(); + object defaultValue = col.DefaultValue; + if ((col.Type == System.Data.DbType.Date || col.Type == System.Data.DbType.DateTime || col.Type == System.Data.DbType.DateTime2 || col.Type == System.Data.DbType.DateTimeOffset)) + { + col.Type = System.Data.DbType.DateTime; + if (col.DefaultValue != null) + defaultValue = "DateTime.UtcNow"; + } + + + if (col.Type == System.Data.DbType.AnsiString && col.Size == -1) + { + size = "int.MaxValue"; + } + if (col.Type == System.Data.DbType.String && col.Size == -1) + { + size = "int.MaxValue"; + } + if (col.Type == System.Data.DbType.VarNumeric && col.Size == -1) + { + size = "int.MaxValue"; + } + if (col.Type == System.Data.DbType.Binary && col.Size == -1) + { + size = "int.MaxValue"; + } + + defaultValue = $"\"{defaultValue}\""; + + if (col.Type == DbType.Guid) + { + defaultValue = defaultValue.ToString().Trim(new[] { '\"' }); + defaultValue = $"this.Database.Encode(new Guid(\"{defaultValue}\"))"; + defaultValue = defaultValue.ToString().Trim(new[] { '\"' }); + } string precision = ""; if (col.Precision != null) precision = $"({col.Precision})"; - string propertyString = this.GetColumnPropertyString(col.ColumnProperty); + string propertyString = this.GetColumnPropertyString(col.ColumnProperty, table); + propertyString += this.GetColumnPropertyUnique(col.Name, table); + if ((col.Name == "CreatedTimeStamp" || col.Name == "ModifiedTimeStamp") && col.DefaultValue != null) + { + defaultValue = "DateTime.UtcNow"; + } if (col.Size != 0 && col.DefaultValue == null && col.ColumnProperty == ColumnProperty.None) { - return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, col.Size); + return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, size); } + if (col.DefaultValue != null && col.ColumnProperty == ColumnProperty.None && col.Size == 0) { - return String.Format("new Column(\"{0}\",DbType.{1},\"{2}\")", col.Name, col.Type, col.DefaultValue); + return String.Format("new Column(\"{0}\",DbType.{1},{2})", col.Name, col.Type, String.Format("{0}", defaultValue)); } if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue == null) { @@ -150,31 +231,84 @@ private string getColStatement(Column col, string table) } if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue == null) { - return String.Format("new Column(\"{0}\",DbType.{1},{2},{3})", col.Name, col.Type, col.Size, propertyString); + return String.Format("new Column(\"{0}\",DbType.{1},{2},{3})", col.Name, col.Type, size, propertyString); } if (col.ColumnProperty != ColumnProperty.None && col.Size != 0 && col.DefaultValue != null) { - return String.Format("new Column(\"{0}\",DbType.{1},{2},{3},\"{4}\")", col.Name, col.Type, col.Size, propertyString, col.DefaultValue); + return String.Format("new Column(\"{0}\",DbType.{1},{2},{3},{4})", col.Name, col.Type, size, propertyString, String.Format("{0}", defaultValue)); } if (col.ColumnProperty != ColumnProperty.None && col.Size == 0 && col.DefaultValue != null) { - return String.Format("new Column(\"{0}\",DbType.{1},{2},\"{3}\")", col.Name, col.Type, propertyString, col.DefaultValue); + return String.Format("new Column(\"{0}\",DbType.{1},{2},{3})", col.Name, col.Type, propertyString, String.Format("{0}", defaultValue)); } return String.Format("new Column(\"{0}\",{1})", col.Name, col.Type); } - private string GetColumnPropertyString(ColumnProperty prp) + private string GetColumnPropertyUnique(String col, String tableName) + { + if (UniquAlreadyCreated.Contains(tableName)) + return ""; + Index[] inds = this._provider.GetIndexes(tableName); + + for (int i = 0; i < inds.Length; i++) + { + Index currIndex = inds[i]; + if (currIndex.KeyColumns != null && currIndex.KeyColumns.Count() == 1 && currIndex.KeyColumns.Contains(col)) + { + if (currIndex.PrimaryKey) + return ""; + if (currIndex.Unique) + { + this.UniquAlreadyCreated.Add(tableName); + return "| ColumnProperty.Unique "; + } + } + } + return ""; + } + private List PKAlreadyCreated = new List(); + private List UniquAlreadyCreated = new List(); + + private string GetColumnPropertyString(ColumnProperty prp, String tableName) { string retVal = ""; + + bool isNonclusteredPk = false; + Index[] inds = this._provider.GetIndexes(tableName); + for (int i = 0; i < inds.Length; i++) + { + Index currIndex = inds[i]; + if (!currIndex.Clustered && currIndex.PrimaryKey) + { + isNonclusteredPk = true; + } + } + if ((prp & ColumnProperty.ForeignKey) == ColumnProperty.ForeignKey) retVal += "ColumnProperty.ForeignKey | "; - if ((prp & ColumnProperty.Identity) == ColumnProperty.Identity) retVal += "ColumnProperty.Identity | "; if ((prp & ColumnProperty.Indexed) == ColumnProperty.Indexed) retVal += "ColumnProperty.Indexed | "; if ((prp & ColumnProperty.NotNull) == ColumnProperty.NotNull) retVal += "ColumnProperty.NotNull | "; if ((prp & ColumnProperty.Null) == ColumnProperty.Null) retVal += "ColumnProperty.Null | "; - //if ((prp & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey) retVal += "ColumnProperty.PrimaryKey | "; - //if ((prp & ColumnProperty.PrimaryKeyWithIdentity) == ColumnProperty.PrimaryKeyWithIdentity) retVal += "ColumnProperty.PrimaryKeyWithIdentity | "; - //if ((prp & ColumnProperty.PrimaryKeyNonClustered) == ColumnProperty.PrimaryKeyNonClustered) retVal += "ColumnProperty.PrimaryKeyNonClustered | "; - if ((prp & ColumnProperty.Unique) == ColumnProperty.Unique) retVal += "ColumnProperty.Unique | "; + + if (!isNonclusteredPk && (prp & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey && (prp & ColumnProperty.Identity) != ColumnProperty.Identity) + { + retVal += "ColumnProperty.PrimaryKey | "; + this.PKAlreadyCreated.Add(tableName); + } + if (isNonclusteredPk && (prp & ColumnProperty.PrimaryKey) == ColumnProperty.PrimaryKey) + { + retVal += "ColumnProperty.PrimaryKeyNonClustered | "; + this.PKAlreadyCreated.Add(tableName); + } + if ((prp & ColumnProperty.Identity) == ColumnProperty.Identity) + { + if ((prp & ColumnProperty.PrimaryKeyWithIdentity) == ColumnProperty.PrimaryKeyWithIdentity) + { + this.PKAlreadyCreated.Add(tableName); + retVal += "ColumnProperty.PrimaryKeyWithIdentity | "; + } + else + retVal += "ColumnProperty.Identity | "; + } if ((prp & ColumnProperty.Unsigned) == ColumnProperty.Unsigned) retVal += "ColumnProperty.Unsigned | "; if (retVal != "") retVal = retVal.Substring(0, retVal.Length - 3); @@ -183,5 +317,110 @@ private string GetColumnPropertyString(ColumnProperty prp) return retVal; } + + + public String GetDatas(string table) + { + string result = ""; + var cols = this._provider.GetColumns(table); + for (int i = 0; i < cols.Length; i++) + { + cols[i].Name = String.Format("\"{0}\"", cols[i].Name); + } + string columString = string.Join(",", cols.Select(o => o.Name)); + List valueList = new List(); + List columList = new List(); + + using (var cmd = this._provider.CreateCommand()) + { + using (IDataReader reader = this._provider.ExecuteQuery(cmd, String.Format("select * from {0}", table.ToUpper()))) + { + + Type[] typesNumber = { typeof(Decimal), typeof(Double), typeof(int), typeof(Int16), typeof(Int32), typeof(Int64), typeof(UInt16), typeof(UInt32), typeof(UInt64), typeof(Byte), typeof(byte), typeof(double), typeof(float) }; + while (reader.Read()) + { + object[] vals = new object[cols.Length]; + valueList = new List(); + columList = new List(); + + for (int i = 0; i < cols.Length; i++) + { + try + { + object curr = reader.GetValue(i); + if (curr is System.DBNull) + { + continue; + } + if (curr == null) + { + continue; + } + if (reader.GetFieldType(i) == typeof(Boolean)) + { + valueList.Add(String.Format("{0}", curr.ToString().ToLower())); + } + else + if (reader.GetFieldType(i) == typeof(DateTime)) + { + valueList.Add(String.Format("DateTime.Parse(\"{0}\").ToUniversalTime()", curr)); + } + else + if (reader.GetFieldType(i) == typeof(Guid)) + { + valueList.Add(String.Format("this.Database.Encode(new Guid(\"{0}\"))", curr).Trim(new char[] { '\"' })); + } + else + { + if (typesNumber.Contains(reader.GetFieldType(i))) + { + if (curr.GetType() == typeof(Array)) + { + continue; + } + if (curr == null) + continue; + + valueList.Add(string.Format(System.Globalization.CultureInfo.GetCultureInfo("en-EN"), "{0}", curr)); + } + else + { + string val = String.Format("\"{0}\"", curr); + if (val == "\"\"") + continue; + valueList.Add(String.Format("\"{0}\"", curr)); + } + } + columList.Add(cols[i].Name); + + } + catch (Exception exc) + { + vals[i] = "null"; + } + } + for (int i = 0; i < columList.Count; i++) + columList[i] = $"{columList[i]}"; + + result += $"\t\tDatabase.Insert(\"{table}\",new[]{String.Format("{{{0}}}", string.Join(",", columList))},new object[]{String.Format("{{{0}}}", string.Join(",", valueList.ToArray()))});\n"; + + } + } + } + return result; + + } + public void GetInserts(string[] tables, StringWriter writer) + { + for (int i = 0; i < tables.Length; i++) + { + string data = this.GetDatas(tables[i]); + if (data != null) + writer.WriteLine(data); + if (data == null) + { + } + } + } } }