From 785630922e6c58e5b7409a098548487b40109a19 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Fri, 17 Sep 2021 12:02:41 +0200 Subject: [PATCH] Rename IEmbeddedDatabaseCreator to IDatabaseCreator and refactor implementations --- .../Persistence/DbProviderFactoryCreator.cs | 13 ++-- .../Persistence/IDatabaseCreator.cs | 9 +++ .../Persistence/IDbProviderFactoryCreator.cs | 2 +- .../Persistence/IEmbeddedDatabaseCreator.cs | 9 --- .../NoopEmbeddedDatabaseCreator.cs | 14 ----- .../Persistence/SqlServerDatabaseCreator.cs | 63 +++++++++++++++++++ .../SqlServerDbProviderFactoryCreator.cs | 26 +++----- .../SqlCeDatabaseCreator.cs | 16 +++++ .../SqlCeEmbeddedDatabaseCreator.cs | 18 ------ .../Persistence/DatabaseBuilderTests.cs | 8 +-- .../UmbracoBuilderExtensions.cs | 10 +-- 11 files changed, 114 insertions(+), 74 deletions(-) create mode 100644 src/Umbraco.Infrastructure/Persistence/IDatabaseCreator.cs delete mode 100644 src/Umbraco.Infrastructure/Persistence/IEmbeddedDatabaseCreator.cs delete mode 100644 src/Umbraco.Infrastructure/Persistence/NoopEmbeddedDatabaseCreator.cs create mode 100644 src/Umbraco.Infrastructure/Persistence/SqlServerDatabaseCreator.cs create mode 100644 src/Umbraco.Persistence.SqlCe/SqlCeDatabaseCreator.cs delete mode 100644 src/Umbraco.Persistence.SqlCe/SqlCeEmbeddedDatabaseCreator.cs diff --git a/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs b/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs index 942368f5cb..e54c1f5fbc 100644 --- a/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs +++ b/src/Umbraco.Infrastructure/Persistence/DbProviderFactoryCreator.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Data.Common; using System.Linq; using NPoco; -using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; namespace Umbraco.Cms.Infrastructure.Persistence @@ -11,7 +10,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence public class DbProviderFactoryCreator : IDbProviderFactoryCreator { private readonly Func _getFactory; - private readonly IDictionary _embeddedDatabaseCreators; + private readonly IDictionary _databaseCreators; private readonly IDictionary _syntaxProviders; private readonly IDictionary _bulkSqlInsertProviders; private readonly IDictionary _providerSpecificMapperFactories; @@ -20,11 +19,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence Func getFactory, IEnumerable syntaxProviders, IEnumerable bulkSqlInsertProviders, - IEnumerable embeddedDatabaseCreators, + IEnumerable databaseCreators, IEnumerable providerSpecificMapperFactories) { _getFactory = getFactory; - _embeddedDatabaseCreators = embeddedDatabaseCreators.ToDictionary(x => x.ProviderName); + _databaseCreators = databaseCreators.ToDictionary(x => x.ProviderName); _syntaxProviders = syntaxProviders.ToDictionary(x => x.ProviderName); _bulkSqlInsertProviders = bulkSqlInsertProviders.ToDictionary(x => x.ProviderName); _providerSpecificMapperFactories = providerSpecificMapperFactories.ToDictionary(x => x.ProviderName); @@ -60,11 +59,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence return result; } - public void CreateDatabase(string providerName) + public void CreateDatabase(string providerName, string connectionString) { - if (_embeddedDatabaseCreators.TryGetValue(providerName, out var creator)) + if (_databaseCreators.TryGetValue(providerName, out var creator)) { - creator.Create(); + creator.Create(connectionString); } } diff --git a/src/Umbraco.Infrastructure/Persistence/IDatabaseCreator.cs b/src/Umbraco.Infrastructure/Persistence/IDatabaseCreator.cs new file mode 100644 index 0000000000..2d97cfbcd3 --- /dev/null +++ b/src/Umbraco.Infrastructure/Persistence/IDatabaseCreator.cs @@ -0,0 +1,9 @@ +namespace Umbraco.Cms.Infrastructure.Persistence +{ + public interface IDatabaseCreator + { + string ProviderName { get; } + + void Create(string connectionString); + } +} diff --git a/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs b/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs index 99b7469085..6a38dc3c06 100644 --- a/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs +++ b/src/Umbraco.Infrastructure/Persistence/IDbProviderFactoryCreator.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence DbProviderFactory CreateFactory(string providerName); ISqlSyntaxProvider GetSqlSyntaxProvider(string providerName); IBulkSqlInsertProvider CreateBulkSqlInsertProvider(string providerName); - void CreateDatabase(string providerName); + void CreateDatabase(string providerName, string connectionString); NPocoMapperCollection ProviderSpecificMappers(string providerName); } } diff --git a/src/Umbraco.Infrastructure/Persistence/IEmbeddedDatabaseCreator.cs b/src/Umbraco.Infrastructure/Persistence/IEmbeddedDatabaseCreator.cs deleted file mode 100644 index 2461644d0a..0000000000 --- a/src/Umbraco.Infrastructure/Persistence/IEmbeddedDatabaseCreator.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Umbraco.Cms.Infrastructure.Persistence -{ - public interface IEmbeddedDatabaseCreator - { - string ProviderName { get; } - string ConnectionString { get; set; } - void Create(); - } -} diff --git a/src/Umbraco.Infrastructure/Persistence/NoopEmbeddedDatabaseCreator.cs b/src/Umbraco.Infrastructure/Persistence/NoopEmbeddedDatabaseCreator.cs deleted file mode 100644 index fd378d44bc..0000000000 --- a/src/Umbraco.Infrastructure/Persistence/NoopEmbeddedDatabaseCreator.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace Umbraco.Cms.Infrastructure.Persistence -{ - public class NoopEmbeddedDatabaseCreator : IEmbeddedDatabaseCreator - { - public string ProviderName => Cms.Core.Constants.DatabaseProviders.SqlServer; - - public string ConnectionString { get; set; } - - public void Create() - { - - } - } -} diff --git a/src/Umbraco.Infrastructure/Persistence/SqlServerDatabaseCreator.cs b/src/Umbraco.Infrastructure/Persistence/SqlServerDatabaseCreator.cs new file mode 100644 index 0000000000..e7f5934e78 --- /dev/null +++ b/src/Umbraco.Infrastructure/Persistence/SqlServerDatabaseCreator.cs @@ -0,0 +1,63 @@ +using System; +using System.Data.SqlClient; +using System.IO; +using Umbraco.Cms.Core; + +namespace Umbraco.Cms.Infrastructure.Persistence +{ + public class SqlServerDatabaseCreator : IDatabaseCreator + { + public string ProviderName => Constants.DatabaseProviders.SqlServer; + + public void Create(string connectionString) + { + var builder = new SqlConnectionStringBuilder(connectionString); + + // Get connection string without database specific information + var masterBuilder = new SqlConnectionStringBuilder(builder.ConnectionString) + { + AttachDBFilename = string.Empty, + InitialCatalog = string.Empty + }; + var masterConnectionString = masterBuilder.ConnectionString; + + string fileName = builder.AttachDBFilename, + database = builder.InitialCatalog; + + // Create database + if (!string.IsNullOrEmpty(fileName) && !File.Exists(fileName)) + { + if (string.IsNullOrWhiteSpace(database)) + { + // Use a temporary database name + database = "Umbraco-" + Guid.NewGuid(); + } + + using var connection = new SqlConnection(masterConnectionString); + connection.Open(); + + using var command = new SqlCommand( + $"CREATE DATABASE [{database}] ON (NAME='{database}', FILENAME='{fileName}');" + + $"ALTER DATABASE [{database}] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;" + + $"EXEC sp_detach_db @dbname='{database}';", + connection); + command.ExecuteNonQuery(); + + connection.Close(); + } + else if (!string.IsNullOrEmpty(database)) + { + using var connection = new SqlConnection(masterConnectionString); + connection.Open(); + + using var command = new SqlCommand( + $"IF NOT EXISTS (SELECT * FROM sys.databases WHERE name = '{database}') " + + $"CREATE DATABASE [{database}];", + connection); + command.ExecuteNonQuery(); + + connection.Close(); + } + } + } +} diff --git a/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs b/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs index 756490c531..c16e5a75ab 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlServerDbProviderFactoryCreator.cs @@ -3,12 +3,12 @@ using System.Data.Common; using System.Linq; using Microsoft.Extensions.Options; using NPoco; -using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; namespace Umbraco.Cms.Infrastructure.Persistence { + [Obsolete("This is only used for integration tests and should be moved into a test project.")] public class SqlServerDbProviderFactoryCreator : IDbProviderFactoryCreator { private readonly Func _getFactory; @@ -23,35 +23,29 @@ namespace Umbraco.Cms.Infrastructure.Persistence public DbProviderFactory CreateFactory(string providerName) { if (string.IsNullOrEmpty(providerName)) return null; + return _getFactory(providerName); } // gets the sql syntax provider that corresponds, from attribute public ISqlSyntaxProvider GetSqlSyntaxProvider(string providerName) - { - return providerName switch + => providerName switch { Cms.Core.Constants.DbProviderNames.SqlCe => throw new NotSupportedException("SqlCe is not supported"), Cms.Core.Constants.DbProviderNames.SqlServer => new SqlServerSyntaxProvider(_globalSettings), _ => throw new InvalidOperationException($"Unknown provider name \"{providerName}\""), }; - } public IBulkSqlInsertProvider CreateBulkSqlInsertProvider(string providerName) - { - switch (providerName) + => providerName switch { - case Cms.Core.Constants.DbProviderNames.SqlCe: - throw new NotSupportedException("SqlCe is not supported"); - case Cms.Core.Constants.DbProviderNames.SqlServer: - return new SqlServerBulkSqlInsertProvider(); - default: - return new BasicBulkSqlInsertProvider(); - } - } + Cms.Core.Constants.DbProviderNames.SqlCe => throw new NotSupportedException("SqlCe is not supported"), + Cms.Core.Constants.DbProviderNames.SqlServer => new SqlServerBulkSqlInsertProvider(), + _ => new BasicBulkSqlInsertProvider(), + }; - public void CreateDatabase(string providerName) - => throw new NotSupportedException("Embedded databases are not supported"); + public void CreateDatabase(string providerName, string connectionString) + => throw new NotSupportedException("Embedded databases are not supported"); // TODO But LocalDB is? public NPocoMapperCollection ProviderSpecificMappers(string providerName) => new NPocoMapperCollection(() => Enumerable.Empty()); diff --git a/src/Umbraco.Persistence.SqlCe/SqlCeDatabaseCreator.cs b/src/Umbraco.Persistence.SqlCe/SqlCeDatabaseCreator.cs new file mode 100644 index 0000000000..fd360be13a --- /dev/null +++ b/src/Umbraco.Persistence.SqlCe/SqlCeDatabaseCreator.cs @@ -0,0 +1,16 @@ +using Umbraco.Cms.Infrastructure.Persistence; +using Constants = Umbraco.Cms.Core.Constants; + +namespace Umbraco.Cms.Persistence.SqlCe +{ + public class SqlCeDatabaseCreator : IDatabaseCreator + { + public string ProviderName => Constants.DatabaseProviders.SqlCe; + + public void Create(string connectionString) + { + using var engine = new System.Data.SqlServerCe.SqlCeEngine(connectionString); + engine.CreateDatabase(); + } + } +} diff --git a/src/Umbraco.Persistence.SqlCe/SqlCeEmbeddedDatabaseCreator.cs b/src/Umbraco.Persistence.SqlCe/SqlCeEmbeddedDatabaseCreator.cs deleted file mode 100644 index ee2d888109..0000000000 --- a/src/Umbraco.Persistence.SqlCe/SqlCeEmbeddedDatabaseCreator.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Umbraco.Cms.Infrastructure.Migrations.Install; -using Umbraco.Cms.Infrastructure.Persistence; -using Constants = Umbraco.Cms.Core.Constants; - -namespace Umbraco.Cms.Persistence.SqlCe -{ - public class SqlCeEmbeddedDatabaseCreator : IEmbeddedDatabaseCreator - { - public string ProviderName => Constants.DatabaseProviders.SqlCe; - - public string ConnectionString { get; set; } = DatabaseBuilder.EmbeddedDatabaseConnectionString; - public void Create() - { - var engine = new System.Data.SqlServerCe.SqlCeEngine(ConnectionString); - engine.CreateDatabase(); - } - } -} diff --git a/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Infrastructure/Persistence/DatabaseBuilderTests.cs b/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Infrastructure/Persistence/DatabaseBuilderTests.cs index e8269fafa9..500d71dddc 100644 --- a/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Infrastructure/Persistence/DatabaseBuilderTests.cs +++ b/src/Umbraco.Tests.Integration.SqlCe/Umbraco.Infrastructure/Persistence/DatabaseBuilderTests.cs @@ -23,7 +23,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence { private IDbProviderFactoryCreator DbProviderFactoryCreator => GetRequiredService(); private IUmbracoDatabaseFactory UmbracoDatabaseFactory => GetRequiredService(); - private IEmbeddedDatabaseCreator EmbeddedDatabaseCreator => GetRequiredService(); + private IDatabaseCreator EmbeddedDatabaseCreator => GetRequiredService(); public DatabaseBuilderTests() { @@ -42,10 +42,10 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence if (File.Exists(filePath)) File.Delete(filePath); - EmbeddedDatabaseCreator.ConnectionString = $"Datasource=|DataDirectory|{dbFile};Flush Interval=1"; + var connectionString = $"Datasource=|DataDirectory|{dbFile};Flush Interval=1"; - UmbracoDatabaseFactory.Configure(EmbeddedDatabaseCreator.ConnectionString, Constants.DbProviderNames.SqlCe); - DbProviderFactoryCreator.CreateDatabase(Constants.DbProviderNames.SqlCe); + UmbracoDatabaseFactory.Configure(connectionString, Constants.DbProviderNames.SqlCe); + DbProviderFactoryCreator.CreateDatabase(Constants.DbProviderNames.SqlCe, connectionString); UmbracoDatabaseFactory.CreateDatabase(); // test get database type (requires an actual database) diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index 5073eefe2f..4319bc3544 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -150,7 +150,7 @@ namespace Umbraco.Extensions DbProviderFactories.GetFactory, factory.GetServices(), factory.GetServices(), - factory.GetServices(), + factory.GetServices(), factory.GetServices() )); @@ -357,17 +357,17 @@ namespace Umbraco.Extensions Type sqlCeSyntaxProviderType = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeSyntaxProvider"); Type sqlCeBulkSqlInsertProviderType = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeBulkSqlInsertProvider"); - Type sqlCeEmbeddedDatabaseCreatorType = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeEmbeddedDatabaseCreator"); + Type sqlCeDatabaseCreatorType = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeDatabaseCreator"); Type sqlCeSpecificMapperFactory = umbSqlCeAssembly.GetType("Umbraco.Cms.Persistence.SqlCe.SqlCeSpecificMapperFactory"); if (!(sqlCeSyntaxProviderType is null || sqlCeBulkSqlInsertProviderType is null - || sqlCeEmbeddedDatabaseCreatorType is null + || sqlCeDatabaseCreatorType is null || sqlCeSpecificMapperFactory is null)) { builder.Services.AddSingleton(typeof(ISqlSyntaxProvider), sqlCeSyntaxProviderType); builder.Services.AddSingleton(typeof(IBulkSqlInsertProvider), sqlCeBulkSqlInsertProviderType); - builder.Services.AddSingleton(typeof(IEmbeddedDatabaseCreator), sqlCeEmbeddedDatabaseCreatorType); + builder.Services.AddSingleton(typeof(IDatabaseCreator), sqlCeDatabaseCreatorType); builder.Services.AddSingleton(typeof(IProviderSpecificMapperFactory), sqlCeSpecificMapperFactory); } @@ -397,7 +397,7 @@ namespace Umbraco.Extensions builder.Services.AddSingleton(); builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.Services.AddSingleton(); return builder; }