예제 #1
0
 /// <summary>
 /// Creates a new database.
 /// </summary>
 /// <param name="info">Information describing the database to affect.</param>
 /// <param name="databaseUserNamePublic">Name of a public database user to create.</param>
 /// <param name="databasePasswordPublic">The database password for the new public user.</param>
 /// <param name="scriptResourceNames">A list of the names of the resource files containing the DDL scripts.</param>
 /// <param name="scriptLoader">Class that can load assemblies containing SQL script resource files.</param>
 /// <param name="creatorCredentials">The credentials used to create the database.</param>
 /// <returns>
 /// An instance of the <see cref="ServiceResponse"/> class.
 /// </returns>
 public ServiceResponse CreateDatabase(DatabaseInfo info, string databaseUserNamePublic, string databasePasswordPublic, IEnumerable<string> scriptResourceNames, ScriptLoader scriptLoader, DatabaseCredentials creatorCredentials)
 {
     return CreateDatabase(info, databaseUserNamePublic, databasePasswordPublic, null, scriptResourceNames, scriptLoader, creatorCredentials);
 }
예제 #2
0
        private ServiceResponse CreateDatabase(DatabaseInfo info, string databaseUserNamePublic, string databasePasswordPublic, string scriptResourceName, IEnumerable<string> scriptResourceNames, ScriptLoader scriptLoader, DatabaseCredentials creatorCredentials)
        {
            var creatorInfo = info.CloneWithNewCredentials(creatorCredentials);
            using (var database = new DatabaseManipulator(creatorInfo))
            {
                try
                {
                    smo.Server sqlServer = database.SqlServer;

                    // Make sure SQL Server allows SQL logins if needed
                    if (creatorInfo.HasUserName())
                    {
                        if (database.LoginMode == smo.ServerLoginMode.Integrated)
                        {
                            _logger.Error("Database Server is not configured for mixed-mode authentication.", "Database Server", creatorInfo.ServerName);
                            _response.AddError(string.Format(CultureInfo.InvariantCulture, "Database Server ({0}) is not configured for mixed-mode authentication.", creatorInfo.ServerName));
                        }
                    }

                    if (!_response.HasErrors)
                    {
                        if (!database.Exists())
                        {
                            _logger.Info("Creating database.", "Database name", info.DatabaseName, "Database Server", info.ServerName);

                            // Create new database
                            var newDatabase = new smo.Database(sqlServer, info.DatabaseName);
                            newDatabase.Create();

                            database.CreateLogin(info.UserName, info.Password, true);
                            database.CreateLogin(databaseUserNamePublic, databasePasswordPublic, false);

                            // I don't know why we have to dispose this here, but I was afraid to remove it
                            database.Dispose();

                            UpdateDatabaseSchema(info, databaseUserNamePublic, scriptResourceName, scriptResourceNames, scriptLoader);

                            _logger.Info("Database created successfully.", info.GenerateCustomLoggingProperties());
                        }
                        else
                        {
                            _logger.Error("Database already exists.", info.GenerateCustomLoggingProperties());
                            _response.AddError(string.Format(CultureInfo.InvariantCulture, "Database ({0}) on server ({1}) already exists.", info.DatabaseName, info.ServerName));
                        }
                    }
                }
                catch (Exception ex)
                {
                    _logger.Error("Creation of Database failed.", ex, info.GenerateCustomLoggingProperties());
                    _response.AddError(string.Format(CultureInfo.InvariantCulture, "Creation of Database ({0}) on server ({1}) failed: {2}", info.DatabaseName, info.ServerName, ex.Message));
                }
            }

            return _response;
        }
예제 #3
0
        private ServiceResponse UpdateDatabaseSchema(DatabaseInfo info, string databaseUserNamePublic, string scriptResourceName, IEnumerable<string> scriptResourceNames, ScriptLoader scriptLoader)
        {
            // Create temp App Domain for loading assemblies
            AppDomain tempAppDomain = AppDomain.CreateDomain("TempAppDomain");

            try
            {
                using (var ts = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 5, 0)))
                {
                    using (var database = new DatabaseManipulator(info))
                    {
                        smo.Server sqlServer = database.SqlServer;

                        // Create the script version info table if needed
                        var versionInfoDao = new SqlScriptVersionInfoDao(info.ConnectionString);
                        versionInfoDao.CreateScriptVersionTable(info);

                        _logger.Info("Verifying database schema...", "Database Name", info.DatabaseName);

                        // Get script execution history as a dictionary
                        var sqlScriptVersionInfoDict = new Dictionary<string, string>();

                        foreach (IVersionInfo sqlScriptVersionInfo in versionInfoDao.ReadList())
                        {
                            sqlScriptVersionInfoDict.Add(sqlScriptVersionInfo.Component, sqlScriptVersionInfo.Version);
                        }

                        // Get all assembly names in the specified directory
                        IEnumerable<string> files = scriptLoader.GetSortedScriptAssemblyList();

                        foreach (string file in files)
                        {
                            // Delegate assembly loading/processing to temp App Domain
                            tempAppDomain.SetData("FileName", file);
                            tempAppDomain.SetData("ResourceFileName", scriptResourceName);
                            tempAppDomain.SetData("ResourceFileNames", scriptResourceNames);

                            var dbScriptsToExecute = new Dictionary<string, string>();

                            try
                            {
                                tempAppDomain.DoCallBack(new CrossAppDomainDelegate(ScriptLoader.GetScriptsFromAssembly));
                                dbScriptsToExecute = (Dictionary<string, string>)tempAppDomain.GetData("DbScriptsToExecute");
                            }
                            catch (Exception)
                            {
                                _logger.Error("Error loading assembly!", "FileName", file);
                            }

                            // Sort the scripts by key
                            string[] sortedScriptKeys = new string[dbScriptsToExecute.Keys.Count];
                            dbScriptsToExecute.Keys.CopyTo(sortedScriptKeys, 0);
                            Array.Sort(sortedScriptKeys);

                            foreach (string scriptKey in sortedScriptKeys)
                            {
                                string scriptValue = dbScriptsToExecute[scriptKey];
                                string[] keyParts = scriptKey.Split("_".ToCharArray());

                                if (keyParts.GetUpperBound(0) != 1)
                                {
                                    throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "Invalid script key format ({0})", scriptKey));
                                }

                                string component = Path.GetFileNameWithoutExtension(file);
                                string version = keyParts[1];

                                // If component has no script history, or current script hasn't been executed, execute it
                                if (!sqlScriptVersionInfoDict.ContainsKey(component) ||
                                    (int.Parse(version, CultureInfo.InvariantCulture) >
                                     int.Parse(sqlScriptVersionInfoDict[component], CultureInfo.InvariantCulture)))
                                {
                                    ConsoleUtils.WriteLine(string.Format(CultureInfo.InvariantCulture,
                                        "        Executing\n          Component: {0}\n          Script:    {1}\n", component, scriptKey), ConsoleColor.Green);

                                    scriptValue = ApplyScriptTokens(scriptValue, databaseUserNamePublic);
                                    sqlServer.Databases[info.DatabaseName].ExecuteNonQuery(scriptValue);

                                    // Check if script version information already exists for this component
                                    IVersionInfo versionInfo = versionInfoDao.Read(component);

                                    AddOrUpdateVersionInfo(component, version, versionInfo, versionInfoDao);
                                }
                            }
                        }

                        ts.Complete();
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.Error("Update of database failed. Please check that you have configured the database server to allow both SQL Server authentication and Windows authentication.", ex, info.GenerateCustomLoggingProperties());
                _response.AddError("Update of database ({0}) on server ({1}) failed.", info.DatabaseName, info.ServerName);
            }
            finally
            {
                // Unload the temp App Domain, which unloads any loaded assemblies
                AppDomain.Unload(tempAppDomain);
            }

            return _response;
        }
예제 #4
0
 /// <summary>
 /// Updates the schema of the specified database by scanning for new SQL scripts
 /// within embedded resource files, and executing those scripts.
 /// </summary>
 /// <param name="info">The information describing the database to update.</param>
 /// <param name="databaseUserNamePublic">The public database user name.</param>
 /// <param name="scriptResourceNames">A list of the names of the resource files containing the DDL scripts.</param>
 /// <param name="scriptLoader">Class that can load assemblies containing SQL script resource files.</param>
 /// <returns>
 /// An instance of the <see cref="ServiceResponse"/> class.
 /// </returns>
 public ServiceResponse UpdateDatabaseSchema(DatabaseInfo info, string databaseUserNamePublic, IEnumerable<string> scriptResourceNames, ScriptLoader scriptLoader)
 {
     return UpdateDatabaseSchema(info, databaseUserNamePublic, null, scriptResourceNames, scriptLoader);
 }