/// <summary> /// Creates dictionaries that maps from types fullnames to /// a suitable collection name. The resulting name is usually /// simple the name of the type. When there is more than /// one type with the same name, FullName is progressively /// prepended to name until there is no ambiguity. /// Two dictionaries are generated, one with pluralized last name /// and one with singular one. /// </summary> /// <param name="pPersistables">Types to be translated.</param> /// <param name="pSchema">Schema to add names dictionaries.</param> private static void CreateNamesDictionary(Type[] pPersistables, ref SchemaInfo pSchema) { Dictionary<string, string> lPlural; SortedSet<string> lSingular = new SortedSet<string>(); // Initialy maps FullName to Name. lPlural = pPersistables.ToDictionary(lPersistable => lPersistable.ToGenericTypeString(), lPersistable => lPersistable.Name + "s"); foreach (Type type in pPersistables) lSingular.Add(type.ToGenericTypeString()); // Solve name clashes. pPersistables .ToLookup(lPersistable => lPersistable.Name) .Where(lGroup => lGroup.Count() > 1) .Select(lGroup => SolveNameClash(lGroup)) .ToList() .ForEach(delegate(Dictionary<string, string[]> lSub) { foreach (KeyValuePair<string, string[]> lPair in lSub) { // Singular names just join names. // lSingular[lPair.Key] = String.Join("_", lPair.Value); // Last name gets pluralized for plural names. lPair.Value[lPair.Value.Count() - 1] = lPair.Value.Last() + "s"; lPlural[lPair.Key] = String.Join("_", lPair.Value); } }); pSchema.SingularNames = lSingular; pSchema.TypesNameToPluralName = lPlural; }
/// <summary> /// Load assemblies and get exported persistable types /// from them. /// </summary> /// <param name="pClassesFilenames">Filenames of all assemblies to /// load.</param> /// <param name="pAssemblies">Loaded assemblies.</param> /// <param name="pTypes">Types found.</param> private static void GetAssembliesAndTypes(string[] pClassFilenames, string[] pDependencyFilenames, ref SchemaInfo pSchema) { // Creates a SchemaExtractor instance on a new domain. This is done // so that no assembly is loaded on process start, and at the end, // only needed assemblies are loaded. //Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); AppDomain lDomain = AppDomain.CreateDomain("User assemblies domain."); SchemaExtractor lExtractor; OptimizedPersistable pObj = (OptimizedPersistable)lDomain.CreateInstanceFromAndUnwrap(typeof(OptimizedPersistable).Assembly.CodeBase, typeof(OptimizedPersistable).FullName); lExtractor = (SchemaExtractor)lDomain.CreateInstanceFromAndUnwrap(typeof(SchemaExtractor).Assembly.CodeBase, typeof(SchemaExtractor).FullName); // Load assemblies and types on the new domain. List <string> lTypeNames = null; List <string> lAssemblyNames = null; List <string> lActualDependencies = null; lExtractor.GetAssembliesAndTypesHelper(pClassFilenames, pDependencyFilenames, ref lAssemblyNames, ref lTypeNames, ref lActualDependencies); AppDomain.Unload(lDomain); // Load assemblies on this domain (to be able to access types). Assembly l; foreach (string lDep in lActualDependencies) { l = Assembly.LoadFrom(lDep); } // Obtain types from names and fill in schema. pSchema.PersistableTypes = lTypeNames.Select(lTypeName => Type.GetType(lTypeName, true)).ToArray(); pSchema.LoadedAssemblies = lActualDependencies.ToArray(); pSchema.LoadedAssembliesNames = lAssemblyNames.ToArray(); }
private async void GenerateScripts() { SchemaInfo schemaInfo = this.tvDbObjects.GetSchemaInfo(); if (!this.Validate(schemaInfo)) { return; } this.isBusy = true; this.btnGenerate.Enabled = false; DatabaseType dbType = this.useConnector ? this.dbConnectionProfile.DatabaseType : this.databaseType; DbInterpreterOption option = new DbInterpreterOption() { ScriptOutputMode = GenerateScriptOutputMode.WriteToFile, SortObjectsByReference = true, GetTableAllObjects = true }; if (this.chkTreatBytesAsNull.Checked) { option.TreatBytesAsNullForReading = true; option.TreatBytesAsNullForExecuting = true; } else { if (dbType == DatabaseType.Oracle) { option.TreatBytesAsNullForReading = true; option.TreatBytesAsNullForExecuting = true; } else { option.TreatBytesAsHexStringForFile = true; } } this.SetGenerateScriptOption(option); GenerateScriptMode scriptMode = this.GetGenerateScriptMode(); if (scriptMode == GenerateScriptMode.None) { MessageBox.Show("Please specify the script mode."); return; } this.dbInterpreter = DbInterpreterHelper.GetDbInterpreter(dbType, this.connectionInfo, option); SchemaInfoFilter filter = new SchemaInfoFilter(); SchemaInfoHelper.SetSchemaInfoFilterValues(filter, schemaInfo); try { schemaInfo = await this.dbInterpreter.GetSchemaInfoAsync(filter); this.dbInterpreter.Subscribe(this); GenerateScriptMode mode = GenerateScriptMode.None; DbScriptGenerator dbScriptGenerator = DbScriptGeneratorHelper.GetDbScriptGenerator(this.dbInterpreter); if (scriptMode.HasFlag(GenerateScriptMode.Schema)) { mode = GenerateScriptMode.Schema; dbScriptGenerator.GenerateSchemaScripts(schemaInfo); } if (scriptMode.HasFlag(GenerateScriptMode.Data)) { mode = GenerateScriptMode.Data; await dbScriptGenerator.GenerateDataScriptsAsync(schemaInfo); } this.isBusy = false; ManagerUtil.OpenInExplorer(dbScriptGenerator.GetScriptOutputFilePath(mode)); MessageBox.Show(DONE, "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (Exception ex) { this.HandleException(ex); } this.btnGenerate.Enabled = true; }
private async Task Convert() { SchemaInfo schemaInfo = this.tvDbObjects.GetSchemaInfo(); if (!this.ValidateSource(schemaInfo)) { return; } if (this.targetDbConnectionInfo == null) { MessageBox.Show("Target connection info is null."); return; } if (this.sourceDbConnectionInfo.Server == this.targetDbConnectionInfo.Server && this.sourceDbConnectionInfo.Database == this.targetDbConnectionInfo.Database) { MessageBox.Show("Source database cannot be equal to the target database."); return; } DatabaseType sourceDbType = this.useSourceConnector ? this.sourceDbProfile.DatabaseType : this.sourceDatabaseType; DatabaseType targetDbType = this.targetDbProfile.DatabaseType; DbInterpreterOption sourceScriptOption = new DbInterpreterOption() { ScriptOutputMode = GenerateScriptOutputMode.None, SortObjectsByReference = true, GetTableAllObjects = true }; DbInterpreterOption targetScriptOption = new DbInterpreterOption() { ScriptOutputMode = (GenerateScriptOutputMode.WriteToString) }; this.SetGenerateScriptOption(sourceScriptOption, targetScriptOption); if (this.chkGenerateSourceScripts.Checked) { sourceScriptOption.ScriptOutputMode = sourceScriptOption.ScriptOutputMode | GenerateScriptOutputMode.WriteToFile; } if (this.chkOutputScripts.Checked) { targetScriptOption.ScriptOutputMode = targetScriptOption.ScriptOutputMode | GenerateScriptOutputMode.WriteToFile; } if (this.chkTreatBytesAsNull.Checked) { sourceScriptOption.TreatBytesAsNullForReading = true; targetScriptOption.TreatBytesAsNullForExecuting = true; } targetScriptOption.TableScriptsGenerateOption.GenerateIdentity = this.chkGenerateIdentity.Checked; GenerateScriptMode scriptMode = this.GetGenerateScriptMode(); if (scriptMode == GenerateScriptMode.None) { MessageBox.Show("Please specify the script mode."); return; } DbConveterInfo source = new DbConveterInfo() { DbInterpreter = DbInterpreterHelper.GetDbInterpreter(sourceDbType, this.sourceDbConnectionInfo, sourceScriptOption) }; DbConveterInfo target = new DbConveterInfo() { DbInterpreter = DbInterpreterHelper.GetDbInterpreter(targetDbType, this.targetDbConnectionInfo, targetScriptOption) }; try { using (this.dbConverter = new DbConverter(source, target)) { this.dbConverter.Option.GenerateScriptMode = scriptMode; this.dbConverter.Option.BulkCopy = this.chkBulkCopy.Checked; this.dbConverter.Option.ExecuteScriptOnTargetServer = this.chkExecuteOnTarget.Checked; this.dbConverter.Option.UseTransaction = this.chkUseTransaction.Checked; this.dbConverter.Option.SkipScriptError = this.chkSkipScriptError.Checked; this.dbConverter.Option.PickupTable = this.chkPickup.Checked; this.dbConverter.Option.ConvertComputeColumnExpression = this.chkComputeColumn.Checked; this.dbConverter.Option.OnlyCommentComputeColumnExpressionInScript = this.chkOnlyCommentComputeExpression.Checked; this.dbConverter.Subscribe(this); if (sourceDbType == DatabaseType.MySql) { source.DbInterpreter.Option.InQueryItemLimitCount = 2000; } if (targetDbType == DatabaseType.SqlServer) { target.DbOwner = this.txtTargetDbOwner.Text ?? "dbo"; } else if (targetDbType == DatabaseType.MySql) { target.DbInterpreter.Option.RemoveEmoji = true; } this.dbConverter.Option.SplitScriptsToExecute = true; this.btnExecute.Enabled = false; this.btnCancel.Enabled = true; await this.dbConverter.Convert(schemaInfo); if (!this.hasError && !this.dbConverter.HasError && !source.DbInterpreter.HasError && !target.DbInterpreter.HasError) { this.btnExecute.Enabled = true; this.btnCancel.Enabled = false; if (!this.dbConverter.CancelRequested) { this.txtMessage.AppendText(Environment.NewLine + DONE); MessageBox.Show(DONE, "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { MessageBox.Show("Task has been canceled."); } } } } catch (Exception ex) { this.hasError = true; this.HandleException(ex); } }
/// <summary> /// Extract schema information from assemblies. /// </summary> /// <param name="pClassesFilenames">Assemblies containing /// desired persistable types.</param> /// <param name="pDependenciesFilenames">Assemblies required by /// pClassesFilenames Assemblies.</param> /// <returns></returns> public static SchemaInfo Extract(string[] pClassesFilenames, string[] pDependenciesFilenames) { // Create schema, get persistable types, loaded assemblies and // loaded assemblies names, and finally create names for each type. SchemaInfo lSchema = new SchemaInfo() { UserClassesFiles = pClassesFilenames, UserDependenciesFiles = pDependenciesFilenames }; // Already loaded assemblies sometimes get not found! register // resolver. AppDomain.CurrentDomain.AssemblyResolve += SchemaExtractor.AssemblyResolve; GetAssembliesAndTypes(pClassesFilenames, pDependenciesFilenames, ref lSchema); CreateNamesDictionary(lSchema.PersistableTypes, ref lSchema); AppDomain.CurrentDomain.AssemblyResolve -= SchemaExtractor.AssemblyResolve; return lSchema; }
/// <summary> /// Load assemblies and get exported persistable types /// from them. /// </summary> /// <param name="pClassesFilenames">Filenames of all assemblies to /// load.</param> /// <param name="pAssemblies">Loaded assemblies.</param> /// <param name="pTypes">Types found.</param> private static void GetAssembliesAndTypes(string[] pClassFilenames, string[] pDependencyFilenames,ref SchemaInfo pSchema) { // Creates a SchemaExtractor instance on a new domain. This is done // so that no assembly is loaded on process start, and at the end, // only needed assemblies are loaded. //Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); AppDomain lDomain = AppDomain.CreateDomain("User assemblies domain."); SchemaExtractor lExtractor; OptimizedPersistable pObj = (OptimizedPersistable)lDomain.CreateInstanceFromAndUnwrap(typeof(OptimizedPersistable).Assembly.CodeBase, typeof(OptimizedPersistable).FullName); lExtractor = (SchemaExtractor)lDomain.CreateInstanceFromAndUnwrap(typeof(SchemaExtractor).Assembly.CodeBase,typeof(SchemaExtractor).FullName); // Load assemblies and types on the new domain. List<string> lTypeNames = null; List<string> lAssemblyNames = null; List<string> lActualDependencies = null; lExtractor.GetAssembliesAndTypesHelper(pClassFilenames, pDependencyFilenames, ref lAssemblyNames, ref lTypeNames, ref lActualDependencies); AppDomain.Unload(lDomain); // Load assemblies on this domain (to be able to access types). Assembly l; foreach (string lDep in lActualDependencies) { l = Assembly.LoadFrom(lDep); } // Obtain types from names and fill in schema. pSchema.PersistableTypes = lTypeNames.Select(lTypeName => Type.GetType(lTypeName, true)).ToArray(); pSchema.LoadedAssemblies = lActualDependencies.ToArray(); pSchema.LoadedAssembliesNames = lAssemblyNames.ToArray(); }
private async Task CopyTable() { string name = this.txtName.Text.Trim(); if (!this.ValidateInputs()) { return; } try { GenerateScriptMode scriptMode = this.GetGenerateScriptMode(); bool isTableExisted = false; if (scriptMode.HasFlag(GenerateScriptMode.Schema)) { isTableExisted = await this.IsNameExisted(); } if (isTableExisted) { name = name + "_copy"; } SchemaInfo schemaInfo = new SchemaInfo(); schemaInfo.Tables.Add(this.Table); DatabaseType targetDatabaseType = this.rbAnotherDatabase.Checked ? this.ucConnection.DatabaseType : this.DatabaseType; ConnectionInfo targetConnectionInfo = this.rbAnotherDatabase.Checked ? this.targetDbConnectionInfo : this.ConnectionInfo; DbInterpreterOption sourceOption = new DbInterpreterOption(); DbInterpreterOption targetOption = new DbInterpreterOption(); targetOption.TableScriptsGenerateOption.GenerateIdentity = this.chkGenerateIdentity.Checked; DbConveterInfo source = new DbConveterInfo() { DbInterpreter = DbInterpreterHelper.GetDbInterpreter(this.DatabaseType, this.ConnectionInfo, sourceOption) }; DbConveterInfo target = new DbConveterInfo() { DbInterpreter = DbInterpreterHelper.GetDbInterpreter(targetDatabaseType, targetConnectionInfo, targetOption) }; source.TableNameMappings.Add(this.Table.Name, name); this.btnExecute.Enabled = false; using (this.dbConverter = new DbConverter(source, target)) { this.dbConverter.Option.RenameTableChildren = isTableExisted || this.rbSameDatabase.Checked; this.dbConverter.Option.GenerateScriptMode = scriptMode; this.dbConverter.Option.BulkCopy = true; this.dbConverter.Option.UseTransaction = true; this.dbConverter.Option.ConvertComputeColumnExpression = true; this.dbConverter.Option.IgnoreNotSelfForeignKey = true; this.dbConverter.Subscribe(this); if (this.DatabaseType == DatabaseType.MySql) { source.DbInterpreter.Option.InQueryItemLimitCount = 2000; } if (this.DatabaseType != targetDatabaseType) { if (targetDatabaseType == DatabaseType.SqlServer) { target.DbOwner = "dbo"; } else if (targetDatabaseType == DatabaseType.MySql) { target.DbInterpreter.Option.RemoveEmoji = true; } } else { target.DbOwner = this.Table.Owner; } this.dbConverter.Option.SplitScriptsToExecute = true; await this.dbConverter.Convert(schemaInfo); if (!this.hasError && !this.dbConverter.HasError && !source.DbInterpreter.HasError && !target.DbInterpreter.HasError) { if (!this.dbConverter.CancelRequested) { MessageBox.Show("Copy finished", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); } else { MessageBox.Show("Task has been canceled."); } } } } catch (Exception ex) { this.hasError = true; this.HandleException(ex); } finally { this.btnExecute.Enabled = true; } }
private async void Compare(DatabaseObjectType databaseObjectType) { DatabaseType dbType; if (this.useSourceConnector) { dbType = this.sourceDbProfile.DatabaseType; if (!this.sourceDbProfile.IsDbTypeSelected()) { MessageBox.Show("Please select a source database type."); return; } if (!this.sourceDbProfile.IsProfileSelected()) { MessageBox.Show("Please select a source database profile."); return; } if (!this.sourceDbConnectionInfo.IntegratedSecurity && string.IsNullOrEmpty(this.sourceDbConnectionInfo.Password)) { MessageBox.Show("Please specify password for the source database."); this.sourceDbProfile.ConfigConnection(true); return; } } else { dbType = this.sourceDatabaseType; } if (this.sourceDbConnectionInfo == null) { MessageBox.Show("Source connection is null."); return; } if (this.targetDbConnectionInfo == null) { MessageBox.Show("Target connection info is null."); return; } if (dbType != this.targetDbProfile.DatabaseType) { MessageBox.Show("Target database type must be same as source database type."); return; } if (this.sourceDbConnectionInfo.Server == this.targetDbConnectionInfo.Server && this.sourceDbConnectionInfo.Database == this.targetDbConnectionInfo.Database) { MessageBox.Show("Source database cannot be equal to the target database."); return; } this.btnCompare.Text = "..."; this.btnCompare.Enabled = false; try { DbInterpreterOption sourceOption = new DbInterpreterOption(); DbInterpreterOption targetOption = new DbInterpreterOption(); SchemaInfoFilter sourceFilter = new SchemaInfoFilter() { DatabaseObjectType = databaseObjectType }; SchemaInfoFilter targetFilter = new SchemaInfoFilter() { DatabaseObjectType = databaseObjectType }; if (databaseObjectType.HasFlag(DatabaseObjectType.Table)) { sourceOption.GetTableAllObjects = true; targetOption.GetTableAllObjects = true; } this.sourceInterpreter = DbInterpreterHelper.GetDbInterpreter(dbType, this.sourceDbConnectionInfo, sourceOption); this.targetInterpreter = DbInterpreterHelper.GetDbInterpreter(this.targetDbProfile.DatabaseType, this.targetDbConnectionInfo, targetOption); this.sourceScriptGenerator = DbScriptGeneratorHelper.GetDbScriptGenerator(this.sourceInterpreter); this.targetScriptGenerator = DbScriptGeneratorHelper.GetDbScriptGenerator(this.targetInterpreter); this.sourceInterpreter.Subscribe(this); this.targetInterpreter.Subscribe(this); this.sourceSchemaInfo = await this.sourceInterpreter.GetSchemaInfoAsync(sourceFilter); this.targetSchemaInfo = await this.targetInterpreter.GetSchemaInfoAsync(targetFilter); DbCompare dbCompare = new DbCompare(sourceSchemaInfo, targetSchemaInfo); this.Feedback("Begin to compare..."); this.differences = dbCompare.Compare(); this.Feedback("End compare."); this.LoadData(); } catch (Exception ex) { string message = ExceptionHelper.GetExceptionDetails(ex); LogHelper.LogError(message); MessageBox.Show("Error:" + message); } finally { this.btnCompare.Text = "Compare"; this.btnCompare.Enabled = true; } }