Я пытаюсь создать консольное приложение миграции, которое может запускаться с нуля, то есть на только что установленном сервере SQL, включая выделенного пользователя с учетными данными, которым должен быть db_owner.
У меня это работает на PostgreSQL, но мне нужно получить аналогичное решение для SQL Сервера.
Прежде чем я позвоню context.Database.Migrate()
, я звоню CheckDatabaseCreated(context.Database, configuration)
, который в основном делает это:
Пытается соединиться с данной строкой соединения
В случае неудачи он заменяет пользователя и пароль на пароль SA и SA и подключается к мастеру.
Создает логин, если он не существует.
Создает базу данных, если он не существует.
Подключается к вновь созданной базе данных - все еще как SA.
Создает пользователя с логином и добавляет роль db_owner.
- Наконец, он пытается снова подключиться, используя исходную строку подключения - это то место, где он не работает.
Использование Heidi SQL, я вижу, что база данных создана, но я могу подключиться только с использованием учетных данных SA.
private static void CheckDatabaseCreated(DatabaseFacade contextDatabase, IConfiguration configuration)
{
bool canConnect;
try
{
canConnect = contextDatabase.CanConnect();
Console.WriteLine("Database connected succesfully.");
}
catch (Exception e)
{
Console.WriteLine($"Unable to connect to database: {e.Message}");
canConnect = false;
}
if (!canConnect)
{
var builder = new SqlConnectionStringBuilder(configuration["ConnectionString"]);
var originalUser = builder.UserID;
var originalPassword = builder.Password;
var originalDatabase = builder.InitialCatalog;
builder.UserID = _masterUsername;
builder.Password = _masterPassword;
builder.InitialCatalog = "master";
var login = $"{originalUser}Login";
SqlConnection conn = new SqlConnection(builder.ConnectionString);
try
{
conn.Open();
// Check if login exists
SqlCommand command = new SqlCommand($"SELECT COUNT(*) FROM master.sys.server_principals WHERE name = '{login}'", conn);
object result = command.ExecuteScalar();
result = (result == DBNull.Value) ? null : result;
if (Convert.ToInt32(result) < 1)
{
Console.WriteLine("Login does not exist - creating.");
command = new SqlCommand($"CREATE LOGIN [{login}] WITH PASSWORD = N'{originalPassword}', CHECK_POLICY = OFF, CHECK_EXPIRATION = OFF", conn);
command.ExecuteNonQuery();
}
// Check if database exists
command = new SqlCommand($"SELECT COUNT(*) FROM master.sys.databases WHERE name = '{originalDatabase}'", conn);
result = command.ExecuteScalar();
result = (result == DBNull.Value) ? null : result;
if (Convert.ToInt32(result) < 1)
{
Console.WriteLine("Database does not exist - creating.");
command = new SqlCommand($"CREATE DATABASE \"{originalDatabase}\" ", conn);
command.ExecuteNonQuery();
}
conn.Close();
// Now connect to the (newly created) database - still as sa.
builder.InitialCatalog = originalDatabase;
conn = new SqlConnection(builder.ConnectionString);
try
{
conn.Open();
command = new SqlCommand($"CREATE USER [{originalUser}] FOR LOGIN [{login}]", conn);
command.ExecuteNonQuery();
command = new SqlCommand($"EXEC sp_addrolemember 'db_owner', '{originalUser}'", conn);
command.ExecuteNonQuery();
conn.Close();
}
catch (Exception e)
{
Console.WriteLine($"Unable to connect to {originalDatabase} database: {e.Message}");
}
// Finally try to connect as the user created above.
builder = new SqlConnectionStringBuilder(configuration["ConnectionString"]);
conn = new SqlConnection(builder.ConnectionString);
try
{
conn.Open();
}
catch (Exception e)
{
// This is where it fails.
Console.WriteLine($"Unable to connect to database: {e.Message}");
}
}
catch (Exception e)
{
Console.WriteLine($"Unable to connect to database: {e.Message}");
}
}
}