Merge branch 'dev-v8' of https://github.com/umbraco/Umbraco-CMS into dev-v8
This commit is contained in:
@@ -223,7 +223,17 @@ namespace Umbraco.Core.Components
|
||||
|
||||
private object GetParameter(Type componentType, Type parameterType)
|
||||
{
|
||||
var param = _container.TryGetInstance(parameterType);
|
||||
object param;
|
||||
|
||||
try
|
||||
{
|
||||
param = _container.TryGetInstance(parameterType);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new BootFailedException($"Could not get parameter of type {parameterType.FullName} for component {componentType.FullName}.", e);
|
||||
}
|
||||
|
||||
if (param == null) throw new BootFailedException($"Could not get parameter of type {parameterType.FullName} for component {componentType.FullName}.");
|
||||
return param;
|
||||
}
|
||||
|
||||
@@ -205,45 +205,6 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the database connection string
|
||||
/// </summary>
|
||||
/// <value>The database connection string.</value>
|
||||
[Obsolete("Use System.Configuration.ConfigurationManager.ConnectionStrings[\"umbracoDbDSN\"] instead")]
|
||||
public static string DbDsn
|
||||
{
|
||||
get
|
||||
{
|
||||
var settings = ConfigurationManager.ConnectionStrings[UmbracoConnectionName];
|
||||
var connectionString = string.Empty;
|
||||
|
||||
if (settings != null)
|
||||
{
|
||||
connectionString = settings.ConnectionString;
|
||||
|
||||
// The SqlCe connectionString is formatted slightly differently, so we need to update it
|
||||
if (settings.ProviderName.Contains("SqlServerCe"))
|
||||
connectionString = string.Format("datalayer=SQLCE4Umbraco.SqlCEHelper,SQLCE4Umbraco;{0}", connectionString);
|
||||
}
|
||||
|
||||
return connectionString;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (DbDsn != value)
|
||||
{
|
||||
if (value.ToLower().Contains("SQLCE4Umbraco.SqlCEHelper".ToLower()))
|
||||
{
|
||||
Current.DatabaseContext.ConfigureEmbeddedDatabaseConnection();
|
||||
}
|
||||
else
|
||||
{
|
||||
Current.DatabaseContext.ConfigureDatabaseConnection(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Move these to constants!
|
||||
public const string UmbracoConnectionName = "umbracoDbDSN";
|
||||
public const string UmbracoMigrationName = "Umbraco";
|
||||
|
||||
@@ -15,6 +15,7 @@ using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Plugins;
|
||||
using Umbraco.Core.Services;
|
||||
@@ -180,26 +181,29 @@ namespace Umbraco.Core
|
||||
/// <inheritdoc/>
|
||||
public virtual void Compose(ServiceContainer container)
|
||||
{
|
||||
// compose the very essential things that are needed to bootstrap, before anything else,
|
||||
// and only these things - the rest should be composed in runtime components
|
||||
|
||||
// register basic things
|
||||
container.RegisterSingleton<IProfiler, LogProfiler>();
|
||||
container.RegisterSingleton<ProfilingLogger>();
|
||||
container.RegisterSingleton<IRuntimeState, RuntimeState>();
|
||||
|
||||
// register caches
|
||||
// need the deep clone runtime cache profiver to ensure entities are cached properly, ie
|
||||
// are cloned in and cloned out - no request-based cache here since no web-based context,
|
||||
// will be overriden later or
|
||||
container.RegisterSingleton(_ => new CacheHelper(
|
||||
// we need to have the dep clone runtime cache provider to ensure
|
||||
// all entities are cached properly (cloned in and cloned out)
|
||||
new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()),
|
||||
new StaticCacheProvider(),
|
||||
// we have no request based cache when not running in web-based context
|
||||
new NullCacheProvider(),
|
||||
new IsolatedRuntimeCache(type =>
|
||||
// we need to have the dep clone runtime cache provider to ensure
|
||||
// all entities are cached properly (cloned in and cloned out)
|
||||
new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()))));
|
||||
container.RegisterSingleton(factory => factory.GetInstance<CacheHelper>().RuntimeCache);
|
||||
new IsolatedRuntimeCache(type => new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()))));
|
||||
container.RegisterSingleton(f => f.GetInstance<CacheHelper>().RuntimeCache);
|
||||
|
||||
container.RegisterSingleton(factory => new PluginManager(factory.GetInstance<IRuntimeCacheProvider>(), factory.GetInstance<ProfilingLogger>()));
|
||||
// register the plugin manager
|
||||
container.RegisterSingleton(f => new PluginManager(f.GetInstance<IRuntimeCacheProvider>(), f.GetInstance<ProfilingLogger>()));
|
||||
|
||||
// register syntax providers
|
||||
// register syntax providers - required by database factory
|
||||
container.Register<ISqlSyntaxProvider, MySqlSyntaxProvider>("MySqlSyntaxProvider");
|
||||
container.Register<ISqlSyntaxProvider, SqlCeSyntaxProvider>("SqlCeSyntaxProvider");
|
||||
container.Register<ISqlSyntaxProvider, SqlServerSyntaxProvider>("SqlServerSyntaxProvider");
|
||||
@@ -210,14 +214,21 @@ namespace Umbraco.Core
|
||||
var mapperCollectionBuilder = container.RegisterCollectionBuilder<MapperCollectionBuilder>();
|
||||
ComposeMapperCollection(mapperCollectionBuilder);
|
||||
|
||||
// register database factory
|
||||
// register database factory - required to check for migrations
|
||||
// will be initialized with syntax providers and a logger, and will try to configure
|
||||
// from the default connection string name, if possible, else will remain non-configured
|
||||
// until the database context configures it properly (eg when installing)
|
||||
container.RegisterSingleton<IDatabaseFactory, DefaultDatabaseFactory>();
|
||||
|
||||
// register a database accessor - will be replaced
|
||||
// by HybridUmbracoDatabaseAccessor in the web runtime
|
||||
// register database context
|
||||
container.RegisterSingleton<DatabaseContext>();
|
||||
|
||||
// register query factory - fixme kill
|
||||
container.RegisterSingleton(f => f.GetInstance<IDatabaseFactory>().QueryFactory);
|
||||
|
||||
// register a database accessor - required by database factory
|
||||
// will be replaced by HybridUmbracoDatabaseAccessor in the web runtime
|
||||
// fixme - we should NOT be using thread static at all + will NOT get replaced = wtf?
|
||||
container.RegisterSingleton<IUmbracoDatabaseAccessor, ThreadStaticUmbracoDatabaseAccessor>();
|
||||
|
||||
// register MainDom
|
||||
|
||||
@@ -37,6 +37,10 @@ namespace Umbraco.Core
|
||||
composition.Container.RegisterFrom<ServicesCompositionRoot>();
|
||||
composition.Container.RegisterFrom<CoreModelMappersCompositionRoot>();
|
||||
|
||||
// register database builder
|
||||
// *not* a singleton, don't want to keep it around
|
||||
composition.Container.Register<DatabaseBuilder>();
|
||||
|
||||
//TODO: Don't think we'll need this when the resolvers are all container resolvers
|
||||
composition.Container.RegisterSingleton<IServiceProvider, ActivatorServiceProvider>();
|
||||
|
||||
@@ -117,8 +121,7 @@ namespace Umbraco.Core
|
||||
composition.Container.RegisterSingleton<IPublishedContentModelFactory, NoopPublishedContentModelFactory>();
|
||||
}
|
||||
|
||||
internal void Initialize(
|
||||
IEnumerable<ModelMapperConfiguration> modelMapperConfigurations)
|
||||
internal void Initialize(IEnumerable<ModelMapperConfiguration> modelMapperConfigurations)
|
||||
{
|
||||
//TODO: Remove these for v8!
|
||||
LegacyPropertyEditorIdToAliasConverter.CreateMappingsForCoreEditors();
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
using System;
|
||||
using LightInject;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.Plugins;
|
||||
|
||||
namespace Umbraco.Core.DI
|
||||
{
|
||||
@@ -27,9 +23,6 @@ namespace Umbraco.Core.DI
|
||||
container.RegisterSingleton<IUnitOfWorkProvider, FileUnitOfWorkProvider>();
|
||||
container.RegisterSingleton<IDatabaseUnitOfWorkProvider, NPocoUnitOfWorkProvider>();
|
||||
|
||||
// register query factory
|
||||
container.RegisterSingleton<IQueryFactory, QueryFactory>();
|
||||
|
||||
// register repository factory
|
||||
container.RegisterSingleton<RepositoryFactory>();
|
||||
|
||||
|
||||
621
src/Umbraco.Core/DatabaseBuilder.cs
Normal file
621
src/Umbraco.Core/DatabaseBuilder.cs
Normal file
@@ -0,0 +1,621 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Data.SqlServerCe;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Semver;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Migrations;
|
||||
using Umbraco.Core.Persistence.Migrations.Initial;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Supports building and configuring the database.
|
||||
/// </summary>
|
||||
public class DatabaseBuilder
|
||||
{
|
||||
private readonly IRuntimeState _runtime;
|
||||
private readonly IMigrationEntryService _migrationEntryService;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private DatabaseSchemaResult _databaseSchemaValidationResult;
|
||||
|
||||
public DatabaseBuilder(DatabaseContext databaseContext, IRuntimeState runtime, IMigrationEntryService migrationEntryService, ILogger logger)
|
||||
{
|
||||
DatabaseContext = databaseContext;
|
||||
_runtime = runtime;
|
||||
_migrationEntryService = migrationEntryService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public DatabaseContext DatabaseContext { get; }
|
||||
|
||||
#region Status
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the database is configured. It does not necessarily
|
||||
/// mean that it is possible to connect, nor that Umbraco is installed, nor
|
||||
/// up-to-date.
|
||||
/// </summary>
|
||||
public bool IsDatabaseConfigured => DatabaseContext.IsDatabaseConfigured;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether it is possible to connect to the database.
|
||||
/// </summary>
|
||||
public bool CanConnect => DatabaseContext.CanConnect;
|
||||
|
||||
// that method was originally created by Per in DatabaseHelper- tests the db connection for install
|
||||
// fixed by Shannon to not-ignore the provider
|
||||
// fixed by Stephan as part of the v8 persistence cleanup, now using provider names + SqlCe exception
|
||||
// moved by Stephan to DatabaseBuilder
|
||||
// probably needs to be cleaned up
|
||||
|
||||
public bool CheckConnection(string databaseType, string connectionString, string server, string database, string login, string password, bool integratedAuth)
|
||||
{
|
||||
// we do not test SqlCE connection
|
||||
if (databaseType.InvariantContains("sqlce"))
|
||||
return true;
|
||||
|
||||
string providerName;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(connectionString) == false)
|
||||
{
|
||||
providerName = DbConnectionExtensions.DetectProviderNameFromConnectionString(connectionString);
|
||||
}
|
||||
else if (integratedAuth)
|
||||
{
|
||||
// has to be Sql Server
|
||||
providerName = Constants.DbProviderNames.SqlServer;
|
||||
connectionString = GetIntegratedSecurityDatabaseConnectionString(server, database);
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionString = GetDatabaseConnectionString(
|
||||
server, database, login, password,
|
||||
databaseType, out providerName);
|
||||
}
|
||||
|
||||
return DbConnectionExtensions.IsConnectionAvailable(connectionString, providerName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Configure Connection String
|
||||
|
||||
private const string EmbeddedDatabaseConnectionString = @"Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval=1;";
|
||||
|
||||
/// <summary>
|
||||
/// Configures a connection string for the embedded database.
|
||||
/// </summary>
|
||||
public void ConfigureEmbeddedDatabaseConnection()
|
||||
{
|
||||
ConfigureEmbeddedDatabaseConnection(DatabaseContext.DatabaseFactory, _logger);
|
||||
}
|
||||
|
||||
private static void ConfigureEmbeddedDatabaseConnection(IDatabaseFactory factory, ILogger logger)
|
||||
{
|
||||
SaveConnectionString(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe, logger);
|
||||
|
||||
var path = Path.Combine(GlobalSettings.FullpathToRoot, "App_Data", "Umbraco.sdf");
|
||||
if (File.Exists(path) == false)
|
||||
{
|
||||
// this should probably be in a "using (new SqlCeEngine)" clause but not sure
|
||||
// of the side effects and it's been like this for quite some time now
|
||||
|
||||
var engine = new SqlCeEngine(EmbeddedDatabaseConnectionString);
|
||||
engine.CreateDatabase();
|
||||
}
|
||||
|
||||
factory.Configure(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures a connection string that has been entered manually.
|
||||
/// </summary>
|
||||
/// <param name="connectionString">A connection string.</param>
|
||||
/// <remarks>Has to be either SQL Server or MySql</remarks>
|
||||
public void ConfigureDatabaseConnection(string connectionString)
|
||||
{
|
||||
var provider = DbConnectionExtensions.DetectProviderNameFromConnectionString(connectionString);
|
||||
var providerName = provider.ToString().ToLower().Contains("mysql")
|
||||
? Constants.DbProviderNames.MySql
|
||||
: Constants.DbProviderNames.SqlServer;
|
||||
|
||||
SaveConnectionString(connectionString, providerName, _logger);
|
||||
DatabaseContext.DatabaseFactory.Configure(connectionString, providerName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures a connection string from the installer.
|
||||
/// </summary>
|
||||
/// <param name="server">The name or address of the database server.</param>
|
||||
/// <param name="databaseName">The name of the database.</param>
|
||||
/// <param name="user">The user name.</param>
|
||||
/// <param name="password">The user password.</param>
|
||||
/// <param name="databaseProvider">The name the provider (Sql, Sql Azure, Sql Ce, MySql).</param>
|
||||
public void ConfigureDatabaseConnection(string server, string databaseName, string user, string password, string databaseProvider)
|
||||
{
|
||||
string providerName;
|
||||
var connectionString = GetDatabaseConnectionString(server, databaseName, user, password, databaseProvider, out providerName);
|
||||
|
||||
SaveConnectionString(connectionString, providerName, _logger);
|
||||
DatabaseContext.DatabaseFactory.Configure(connectionString, providerName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a connection string from the installer.
|
||||
/// </summary>
|
||||
/// <param name="server">The name or address of the database server.</param>
|
||||
/// <param name="databaseName">The name of the database.</param>
|
||||
/// <param name="user">The user name.</param>
|
||||
/// <param name="password">The user password.</param>
|
||||
/// <param name="databaseProvider">The name the provider (Sql, Sql Azure, Sql Ce, MySql).</param>
|
||||
/// <param name="providerName"></param>
|
||||
/// <returns>A connection string.</returns>
|
||||
public static string GetDatabaseConnectionString(string server, string databaseName, string user, string password, string databaseProvider, out string providerName)
|
||||
{
|
||||
providerName = Constants.DbProviderNames.SqlServer;
|
||||
var test = databaseProvider.ToLower();
|
||||
if (test.Contains("mysql"))
|
||||
{
|
||||
providerName = Constants.DbProviderNames.MySql;
|
||||
return $"Server={server}; Database={databaseName};Uid={user};Pwd={password}";
|
||||
}
|
||||
if (test.Contains("azure"))
|
||||
{
|
||||
return GetAzureConnectionString(server, databaseName, user, password);
|
||||
}
|
||||
return $"server={server};database={databaseName};user id={user};password={password}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures a connection string using Microsoft SQL Server integrated security.
|
||||
/// </summary>
|
||||
/// <param name="server">The name or address of the database server.</param>
|
||||
/// <param name="databaseName">The name of the database</param>
|
||||
public void ConfigureIntegratedSecurityDatabaseConnection(string server, string databaseName)
|
||||
{
|
||||
var connectionString = GetIntegratedSecurityDatabaseConnectionString(server, databaseName);
|
||||
SaveConnectionString(connectionString, Constants.DbProviderNames.SqlServer, _logger);
|
||||
DatabaseContext.DatabaseFactory.Configure(connectionString, Constants.DbProviderNames.SqlServer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a connection string using Microsoft SQL Server integrated security.
|
||||
/// </summary>
|
||||
/// <param name="server">The name or address of the database server.</param>
|
||||
/// <param name="databaseName">The name of the database</param>
|
||||
/// <returns>A connection string.</returns>
|
||||
public static string GetIntegratedSecurityDatabaseConnectionString(string server, string databaseName)
|
||||
{
|
||||
return $"Server={server};Database={databaseName};Integrated Security=true";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an Azure connection string.
|
||||
/// </summary>
|
||||
/// <param name="server">The name or address of the database server.</param>
|
||||
/// <param name="databaseName">The name of the database.</param>
|
||||
/// <param name="user">The user name.</param>
|
||||
/// <param name="password">The user password.</param>
|
||||
/// <returns>A connection string.</returns>
|
||||
public static string GetAzureConnectionString(string server, string databaseName, string user, string password)
|
||||
{
|
||||
if (server.Contains(".") && ServerStartsWithTcp(server) == false)
|
||||
server = $"tcp:{server}";
|
||||
|
||||
if (server.Contains(".") == false && ServerStartsWithTcp(server))
|
||||
{
|
||||
string serverName = server.Contains(",")
|
||||
? server.Substring(0, server.IndexOf(",", StringComparison.Ordinal))
|
||||
: server;
|
||||
|
||||
var portAddition = string.Empty;
|
||||
|
||||
if (server.Contains(","))
|
||||
portAddition = server.Substring(server.IndexOf(",", StringComparison.Ordinal));
|
||||
|
||||
server = $"{serverName}.database.windows.net{portAddition}";
|
||||
}
|
||||
|
||||
if (ServerStartsWithTcp(server) == false)
|
||||
server = $"tcp:{server}.database.windows.net";
|
||||
|
||||
if (server.Contains(",") == false)
|
||||
server = $"{server},1433";
|
||||
|
||||
if (user.Contains("@") == false)
|
||||
{
|
||||
var userDomain = server;
|
||||
|
||||
if (ServerStartsWithTcp(server))
|
||||
userDomain = userDomain.Substring(userDomain.IndexOf(":", StringComparison.Ordinal) + 1);
|
||||
|
||||
if (userDomain.Contains("."))
|
||||
userDomain = userDomain.Substring(0, userDomain.IndexOf(".", StringComparison.Ordinal));
|
||||
|
||||
user = $"{user}@{userDomain}";
|
||||
}
|
||||
|
||||
return $"Server={server};Database={databaseName};User ID={user};Password={password}";
|
||||
}
|
||||
|
||||
private static bool ServerStartsWithTcp(string server)
|
||||
{
|
||||
return server.ToLower().StartsWith("tcp:".ToLower());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the connection string as a proper .net connection string in web.config.
|
||||
/// </summary>
|
||||
/// <remarks>Saves the ConnectionString in the very nasty 'medium trust'-supportive way.</remarks>
|
||||
/// <param name="connectionString">The connection string.</param>
|
||||
/// <param name="providerName">The provider name.</param>
|
||||
/// <param name="logger">A logger.</param>
|
||||
private static void SaveConnectionString(string connectionString, string providerName, ILogger logger)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(connectionString)) throw new ArgumentNullOrEmptyException(nameof(connectionString));
|
||||
if (string.IsNullOrWhiteSpace(providerName)) throw new ArgumentNullOrEmptyException(nameof(providerName));
|
||||
|
||||
// set the connection string for the new datalayer
|
||||
var connectionStringSettings = new ConnectionStringSettings(GlobalSettings.UmbracoConnectionName, connectionString, providerName);
|
||||
|
||||
var fileName = IOHelper.MapPath($"{SystemDirectories.Root}/web.config");
|
||||
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
|
||||
if (xml.Root == null) throw new Exception("Invalid web.config file.");
|
||||
var connectionStrings = xml.Root.DescendantsAndSelf("connectionStrings").FirstOrDefault();
|
||||
if (connectionStrings == null) throw new Exception("Invalid web.config file.");
|
||||
|
||||
// update connectionString if it exists, or else create a new connectionString
|
||||
var setting = connectionStrings.Descendants("add").FirstOrDefault(s => s.Attribute("name").Value == GlobalSettings.UmbracoConnectionName);
|
||||
if (setting == null)
|
||||
{
|
||||
connectionStrings.Add(new XElement("add",
|
||||
new XAttribute("name", GlobalSettings.UmbracoConnectionName),
|
||||
new XAttribute("connectionString", connectionStringSettings),
|
||||
new XAttribute("providerName", providerName)));
|
||||
}
|
||||
else
|
||||
{
|
||||
setting.Attribute("connectionString").Value = connectionString;
|
||||
setting.Attribute("providerName").Value = providerName;
|
||||
}
|
||||
|
||||
xml.Save(fileName, SaveOptions.DisableFormatting);
|
||||
logger.Info<DatabaseContext>("Configured a new ConnectionString using the '" + providerName + "' provider.");
|
||||
}
|
||||
|
||||
internal bool IsConnectionStringConfigured(ConnectionStringSettings databaseSettings)
|
||||
{
|
||||
var dbIsSqlCe = false;
|
||||
if (databaseSettings?.ProviderName != null)
|
||||
dbIsSqlCe = databaseSettings.ProviderName == Constants.DbProviderNames.SqlCe;
|
||||
var sqlCeDatabaseExists = false;
|
||||
if (dbIsSqlCe)
|
||||
{
|
||||
var parts = databaseSettings.ConnectionString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var dataSourcePart = parts.FirstOrDefault(x => x.InvariantStartsWith("Data Source="));
|
||||
if (dataSourcePart != null)
|
||||
{
|
||||
var datasource = dataSourcePart.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory").ToString());
|
||||
var filePath = datasource.Replace("Data Source=", string.Empty);
|
||||
sqlCeDatabaseExists = File.Exists(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
// Either the connection details are not fully specified or it's a SQL CE database that doesn't exist yet
|
||||
if (databaseSettings == null
|
||||
|| string.IsNullOrWhiteSpace(databaseSettings.ConnectionString) || string.IsNullOrWhiteSpace(databaseSettings.ProviderName)
|
||||
|| (dbIsSqlCe && sqlCeDatabaseExists == false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utils
|
||||
|
||||
internal static void GiveLegacyAChance(IDatabaseFactory factory, ILogger logger)
|
||||
{
|
||||
// look for the legacy appSettings key
|
||||
var legacyConnString = ConfigurationManager.AppSettings[GlobalSettings.UmbracoConnectionName];
|
||||
if (string.IsNullOrWhiteSpace(legacyConnString)) return;
|
||||
|
||||
var test = legacyConnString.ToLowerInvariant();
|
||||
if (test.Contains("sqlce4umbraco"))
|
||||
{
|
||||
// sql ce
|
||||
ConfigureEmbeddedDatabaseConnection(factory, logger);
|
||||
}
|
||||
else if (test.Contains("tcp:"))
|
||||
{
|
||||
// sql azure
|
||||
SaveConnectionString(legacyConnString, Constants.DbProviderNames.SqlServer, logger);
|
||||
factory.Configure(legacyConnString, Constants.DbProviderNames.SqlServer);
|
||||
}
|
||||
else if (test.Contains("datalayer=mysql"))
|
||||
{
|
||||
// mysql
|
||||
|
||||
// strip the datalayer part off
|
||||
var connectionStringWithoutDatalayer = string.Empty;
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
foreach (var variable in legacyConnString.Split(';').Where(x => x.ToLowerInvariant().StartsWith("datalayer") == false))
|
||||
connectionStringWithoutDatalayer = $"{connectionStringWithoutDatalayer}{variable};";
|
||||
|
||||
SaveConnectionString(connectionStringWithoutDatalayer, Constants.DbProviderNames.MySql, logger);
|
||||
factory.Configure(connectionStringWithoutDatalayer, Constants.DbProviderNames.MySql);
|
||||
}
|
||||
else
|
||||
{
|
||||
// sql server
|
||||
SaveConnectionString(legacyConnString, Constants.DbProviderNames.SqlServer, logger);
|
||||
factory.Configure(legacyConnString, Constants.DbProviderNames.SqlServer);
|
||||
}
|
||||
|
||||
// remove the legacy connection string, so we don't end up in a loop if something goes wrong
|
||||
GlobalSettings.RemoveSetting(GlobalSettings.UmbracoConnectionName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Database Schema
|
||||
|
||||
internal DatabaseSchemaResult ValidateDatabaseSchema()
|
||||
{
|
||||
if (DatabaseContext.DatabaseFactory.Configured == false)
|
||||
return new DatabaseSchemaResult(DatabaseContext.SqlSyntax);
|
||||
|
||||
if (_databaseSchemaValidationResult != null)
|
||||
return _databaseSchemaValidationResult;
|
||||
|
||||
var database = DatabaseContext.DatabaseFactory.GetDatabase();
|
||||
var dbSchema = new DatabaseSchemaCreation(database, _logger);
|
||||
_databaseSchemaValidationResult = dbSchema.ValidateSchema();
|
||||
return _databaseSchemaValidationResult;
|
||||
}
|
||||
|
||||
internal Result CreateDatabaseSchemaAndData()
|
||||
{
|
||||
try
|
||||
{
|
||||
var readyForInstall = CheckReadyForInstall();
|
||||
if (readyForInstall.Success == false)
|
||||
{
|
||||
return readyForInstall.Result;
|
||||
}
|
||||
|
||||
_logger.Info<DatabaseContext>("Database configuration status: Started");
|
||||
|
||||
var database = DatabaseContext.DatabaseFactory.GetDatabase();
|
||||
|
||||
// If MySQL, we're going to ensure that database calls are maintaining proper casing as to remove the necessity for checks
|
||||
// for case insensitive queries. In an ideal situation (which is what we're striving for), all calls would be case sensitive.
|
||||
|
||||
/*
|
||||
var supportsCaseInsensitiveQueries = SqlSyntax.SupportsCaseInsensitiveQueries(database);
|
||||
if (supportsCaseInsensitiveQueries == false)
|
||||
{
|
||||
message = "<p> </p><p>The database you're trying to use does not support case insensitive queries. <br />We currently do not support these types of databases.</p>" +
|
||||
"<p>You can fix this by changing the following setting in your my.ini file in your MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1</pre><br />" +
|
||||
"<p>Note: Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
|
||||
return new Result { Message = message, Success = false, Percentage = "15" };
|
||||
}
|
||||
*/
|
||||
|
||||
var message = GetResultMessageForMySql();
|
||||
var schemaResult = ValidateDatabaseSchema();
|
||||
var installedSchemaVersion = schemaResult.DetermineInstalledVersion();
|
||||
|
||||
//If Configuration Status is empty and the determined version is "empty" its a new install - otherwise upgrade the existing
|
||||
if (string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus) && installedSchemaVersion.Equals(new Version(0, 0, 0)))
|
||||
{
|
||||
var helper = new DatabaseSchemaHelper(database, _logger);
|
||||
helper.CreateDatabaseSchema(_runtime, _migrationEntryService, true);
|
||||
|
||||
message = message + "<p>Installation completed!</p>";
|
||||
|
||||
//now that everything is done, we need to determine the version of SQL server that is executing
|
||||
_logger.Info<DatabaseContext>("Database configuration status: " + message);
|
||||
return new Result { Message = message, Success = true, Percentage = "100" };
|
||||
}
|
||||
|
||||
//we need to do an upgrade so return a new status message and it will need to be done during the next step
|
||||
_logger.Info<DatabaseContext>("Database requires upgrade");
|
||||
message = "<p>Upgrading database, this may take some time...</p>";
|
||||
return new Result
|
||||
{
|
||||
RequiresUpgrade = true,
|
||||
Message = message,
|
||||
Success = true,
|
||||
Percentage = "30"
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return HandleInstallException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This assumes all of the previous checks are done!
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal Result UpgradeSchemaAndData(IMigrationEntryService migrationEntryService, MigrationCollectionBuilder builder)
|
||||
{
|
||||
try
|
||||
{
|
||||
var readyForInstall = CheckReadyForInstall();
|
||||
if (readyForInstall.Success == false)
|
||||
{
|
||||
return readyForInstall.Result;
|
||||
}
|
||||
|
||||
_logger.Info<DatabaseContext>("Database upgrade started");
|
||||
|
||||
var database = DatabaseContext.DatabaseFactory.GetDatabase();
|
||||
//var supportsCaseInsensitiveQueries = SqlSyntax.SupportsCaseInsensitiveQueries(database);
|
||||
|
||||
var message = GetResultMessageForMySql();
|
||||
|
||||
var schemaResult = ValidateDatabaseSchema();
|
||||
|
||||
var installedSchemaVersion = new SemVersion(schemaResult.DetermineInstalledVersion());
|
||||
var installedMigrationVersion = schemaResult.DetermineInstalledVersionByMigrations(migrationEntryService);
|
||||
var targetVersion = UmbracoVersion.Current;
|
||||
|
||||
//In some cases - like upgrading from 7.2.6 -> 7.3, there will be no migration information in the database and therefore it will
|
||||
// return a version of 0.0.0 and we don't necessarily want to run all migrations from 0 -> 7.3, so we'll just ensure that the
|
||||
// migrations are run for the target version
|
||||
if (installedMigrationVersion == new SemVersion(new Version(0, 0, 0)) && installedSchemaVersion > new SemVersion(new Version(0, 0, 0)))
|
||||
{
|
||||
//set the installedMigrationVersion to be one less than the target so the latest migrations are guaranteed to execute
|
||||
installedMigrationVersion = new SemVersion(targetVersion.SubtractRevision());
|
||||
}
|
||||
|
||||
//Figure out what our current installed version is. If the web.config doesn't have a version listed, then we'll use the minimum
|
||||
// version detected between the schema installed and the migrations listed in the migration table.
|
||||
// If there is a version in the web.config, we'll take the minimum between the listed migration in the db and what
|
||||
// is declared in the web.config.
|
||||
|
||||
var currentInstalledVersion = string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus)
|
||||
//Take the minimum version between the detected schema version and the installed migration version
|
||||
? new[] { installedSchemaVersion, installedMigrationVersion }.Min()
|
||||
//Take the minimum version between the installed migration version and the version specified in the config
|
||||
: new[] { SemVersion.Parse(GlobalSettings.ConfigurationStatus), installedMigrationVersion }.Min();
|
||||
|
||||
//Ok, another edge case here. If the current version is a pre-release,
|
||||
// then we want to ensure all migrations for the current release are executed.
|
||||
if (currentInstalledVersion.Prerelease.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
currentInstalledVersion = new SemVersion(currentInstalledVersion.GetVersion().SubtractRevision());
|
||||
}
|
||||
|
||||
//DO the upgrade!
|
||||
|
||||
var runner = new MigrationRunner(builder, migrationEntryService, _logger, currentInstalledVersion, UmbracoVersion.SemanticVersion, GlobalSettings.UmbracoMigrationName);
|
||||
|
||||
var migrationContext = new MigrationContext(database, _logger);
|
||||
var upgraded = runner.Execute(migrationContext /*, true*/);
|
||||
|
||||
if (upgraded == false)
|
||||
{
|
||||
throw new ApplicationException("Upgrading failed, either an error occurred during the upgrade process or an event canceled the upgrade process, see log for full details");
|
||||
}
|
||||
|
||||
message = message + "<p>Upgrade completed!</p>";
|
||||
|
||||
//now that everything is done, we need to determine the version of SQL server that is executing
|
||||
|
||||
_logger.Info<DatabaseContext>("Database configuration status: " + message);
|
||||
|
||||
return new Result { Message = message, Success = true, Percentage = "100" };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return HandleInstallException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetResultMessageForMySql()
|
||||
{
|
||||
if (DatabaseContext.SqlSyntax.GetType() == typeof(MySqlSyntaxProvider))
|
||||
{
|
||||
return "<p> </p><p>Congratulations, the database step ran successfully!</p>" +
|
||||
"<p>Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.</p>" +
|
||||
"<p>However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries</p>" +
|
||||
"<p>Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>They can check this by looking for the following setting in the my.ini file in their MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1</pre><br />" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/*
|
||||
private string GetResultMessageForMySql(bool? supportsCaseInsensitiveQueries)
|
||||
{
|
||||
if (supportsCaseInsensitiveQueries == null)
|
||||
{
|
||||
return "<p> </p><p>Warning! Could not check if your database type supports case insensitive queries. <br />We currently do not support these databases that do not support case insensitive queries.</p>" +
|
||||
"<p>You can check this by looking for the following setting in your my.ini file in your MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1</pre><br />" +
|
||||
"<p>Note: Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
}
|
||||
if (SqlSyntax.GetType() == typeof(MySqlSyntaxProvider))
|
||||
{
|
||||
return "<p> </p><p>Congratulations, the database step ran successfully!</p>" +
|
||||
"<p>Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.</p>" +
|
||||
"<p>However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries</p>" +
|
||||
"<p>Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>They can check this by looking for the following setting in the my.ini file in their MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1</pre><br />" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
}
|
||||
return string.Empty;
|
||||
}*/
|
||||
|
||||
private Attempt<Result> CheckReadyForInstall()
|
||||
{
|
||||
if (DatabaseContext.DatabaseFactory.Configured == false)
|
||||
{
|
||||
return Attempt.Fail(new Result
|
||||
{
|
||||
Message = "Database configuration is invalid. Please check that the entered database exists and"
|
||||
+ " that the provided username and password has write access to the database.",
|
||||
Success = false,
|
||||
Percentage = "10"
|
||||
});
|
||||
}
|
||||
return Attempt<Result>.Succeed();
|
||||
}
|
||||
|
||||
private Result HandleInstallException(Exception ex)
|
||||
{
|
||||
_logger.Error<DatabaseContext>("Database configuration failed", ex);
|
||||
|
||||
if (_databaseSchemaValidationResult != null)
|
||||
{
|
||||
_logger.Info<DatabaseContext>("The database schema validation produced the following summary: \n" + _databaseSchemaValidationResult.GetSummary());
|
||||
}
|
||||
|
||||
return new Result
|
||||
{
|
||||
Message =
|
||||
"The database configuration failed with the following message: " + ex.Message +
|
||||
"\n Please check log file for additional information (can be found in '/App_Data/Logs/UmbracoTraceLog.txt')",
|
||||
Success = false,
|
||||
Percentage = "90"
|
||||
};
|
||||
}
|
||||
|
||||
internal class Result
|
||||
{
|
||||
public bool RequiresUpgrade { get; set; }
|
||||
public string Message { get; set; }
|
||||
public bool Success { get; set; }
|
||||
public string Percentage { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,10 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Data.SqlServerCe;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Configuration;
|
||||
using System.Xml.Linq;
|
||||
using NPoco;
|
||||
using Semver;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.DI;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Migrations;
|
||||
using Umbraco.Core.Persistence.Migrations.Initial;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
@@ -28,43 +14,64 @@ namespace Umbraco.Core
|
||||
/// <remarks>One per AppDomain. Ensures that the database is available.</remarks>
|
||||
public class DatabaseContext
|
||||
{
|
||||
private readonly IDatabaseFactory _factory;
|
||||
private readonly ILogger _logger;
|
||||
private readonly IRuntimeState _runtime;
|
||||
private readonly IMigrationEntryService _migrationEntryService;
|
||||
private DatabaseSchemaResult _databaseSchemaValidationResult;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DatabaseContext"/> class.
|
||||
/// </summary>
|
||||
/// <param name="factory">A database factory.</param>
|
||||
/// <param name="logger">A logger.</param>
|
||||
/// <param name="runtime"></param>
|
||||
/// <param name="migrationEntryService"></param>
|
||||
/// <param name="databaseFactory">A database factory.</param>
|
||||
/// <remarks>The database factory will try to configure itself but may fail eg if the default
|
||||
/// Umbraco connection string is not available because we are installing. In which case this
|
||||
/// database context must sort things out and configure the database factory before it can be
|
||||
/// used.</remarks>
|
||||
public DatabaseContext(IDatabaseFactory factory, ILogger logger, IRuntimeState runtime, IMigrationEntryService migrationEntryService)
|
||||
public DatabaseContext(IDatabaseFactory databaseFactory)
|
||||
{
|
||||
if (factory == null) throw new ArgumentNullException(nameof(factory));
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
if (databaseFactory == null) throw new ArgumentNullException(nameof(databaseFactory));
|
||||
|
||||
_factory = factory;
|
||||
_logger = logger;
|
||||
_runtime = runtime;
|
||||
_migrationEntryService = migrationEntryService;
|
||||
DatabaseFactory = databaseFactory;
|
||||
}
|
||||
|
||||
// FIXME
|
||||
// this is basically exposing a subset of the database factory...
|
||||
// so why? why not "just" merge with database factory?
|
||||
// which can create & manage ambient database,
|
||||
// create Sql<SqlContext> expressions
|
||||
// create IQuery<T> expressions
|
||||
// ?
|
||||
|
||||
internal IDatabaseFactory DatabaseFactory { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the QueryFactory
|
||||
/// </summary>
|
||||
public IQueryFactory QueryFactory => _factory.QueryFactory;
|
||||
public IQueryFactory QueryFactory => DatabaseFactory.QueryFactory; // fixme obsolete?
|
||||
|
||||
/// <summary>
|
||||
/// Gets the database sql syntax.
|
||||
/// </summary>
|
||||
public ISqlSyntaxProvider SqlSyntax => _factory.QueryFactory.SqlSyntax;
|
||||
public ISqlSyntaxProvider SqlSyntax => DatabaseFactory.SqlSyntax;
|
||||
|
||||
// fixme
|
||||
// created by the database factory?
|
||||
// add PocoDataFactory
|
||||
// add DatabaseType
|
||||
// add Sql() and Query<T>()
|
||||
// so it can finally replace SqlContext entirely?
|
||||
// need an IDatabaseContext interface?
|
||||
|
||||
public Sql<SqlContext> Sql()
|
||||
{
|
||||
var factory = (DefaultDatabaseFactory) DatabaseFactory; // fixme
|
||||
return NPoco.Sql.BuilderFor(factory.SqlContext);
|
||||
}
|
||||
|
||||
public Sql<SqlContext> Sql(string sql, params object[] args)
|
||||
{
|
||||
return Sql().Append(sql, args);
|
||||
}
|
||||
|
||||
public IQuery<T> Query<T>()
|
||||
{
|
||||
return DatabaseFactory.QueryFactory.Create<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Database"/> object for doing CRUD operations
|
||||
@@ -74,14 +81,14 @@ namespace Umbraco.Core
|
||||
/// This should not be used for CRUD operations or queries against the
|
||||
/// standard Umbraco tables! Use the Public services for that.
|
||||
/// </remarks>
|
||||
public UmbracoDatabase Database => _factory.GetDatabase();
|
||||
public UmbracoDatabase Database => DatabaseFactory.GetDatabase();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the database is configured. It does not necessarily
|
||||
/// mean that it is possible to connect, nor that Umbraco is installed, nor
|
||||
/// up-to-date.
|
||||
/// </summary>
|
||||
public bool IsDatabaseConfigured => _factory.Configured;
|
||||
public bool IsDatabaseConfigured => DatabaseFactory.Configured;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether it is possible to connect to the database.
|
||||
@@ -90,547 +97,11 @@ namespace Umbraco.Core
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsDatabaseConfigured == false) return false;
|
||||
var canConnect = _factory.CanConnect;
|
||||
if (DatabaseFactory.Configured == false) return false;
|
||||
var canConnect = DatabaseFactory.CanConnect;
|
||||
Current.Logger.Info<DatabaseContext>("CanConnect = " + canConnect);
|
||||
return canConnect;
|
||||
}
|
||||
}
|
||||
|
||||
#region Configure Connection String
|
||||
|
||||
private const string EmbeddedDatabaseConnectionString = @"Data Source=|DataDirectory|\Umbraco.sdf;Flush Interval=1;";
|
||||
|
||||
/// <summary>
|
||||
/// Configures a connection string for the embedded database.
|
||||
/// </summary>
|
||||
public void ConfigureEmbeddedDatabaseConnection()
|
||||
{
|
||||
ConfigureEmbeddedDatabaseConnection(_factory, _logger);
|
||||
}
|
||||
|
||||
private static void ConfigureEmbeddedDatabaseConnection(IDatabaseFactory factory, ILogger logger)
|
||||
{
|
||||
SaveConnectionString(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe, logger);
|
||||
|
||||
var path = Path.Combine(GlobalSettings.FullpathToRoot, "App_Data", "Umbraco.sdf");
|
||||
if (File.Exists(path) == false)
|
||||
{
|
||||
// this should probably be in a "using (new SqlCeEngine)" clause but not sure
|
||||
// of the side effects and it's been like this for quite some time now
|
||||
|
||||
var engine = new SqlCeEngine(EmbeddedDatabaseConnectionString);
|
||||
engine.CreateDatabase();
|
||||
}
|
||||
|
||||
factory.Configure(EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures a connection string that has been entered manually.
|
||||
/// </summary>
|
||||
/// <param name="connectionString">A connection string.</param>
|
||||
/// <remarks>Has to be either SQL Server or MySql</remarks>
|
||||
public void ConfigureDatabaseConnection(string connectionString)
|
||||
{
|
||||
var provider = DbConnectionExtensions.DetectProviderNameFromConnectionString(connectionString);
|
||||
var providerName = provider.ToString().ToLower().Contains("mysql")
|
||||
? Constants.DbProviderNames.MySql
|
||||
: Constants.DbProviderNames.SqlServer;
|
||||
|
||||
SaveConnectionString(connectionString, providerName, _logger);
|
||||
_factory.Configure(connectionString, providerName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures a connection string from the installer.
|
||||
/// </summary>
|
||||
/// <param name="server">The name or address of the database server.</param>
|
||||
/// <param name="databaseName">The name of the database.</param>
|
||||
/// <param name="user">The user name.</param>
|
||||
/// <param name="password">The user password.</param>
|
||||
/// <param name="databaseProvider">The name the provider (Sql, Sql Azure, Sql Ce, MySql).</param>
|
||||
public void ConfigureDatabaseConnection(string server, string databaseName, string user, string password, string databaseProvider)
|
||||
{
|
||||
string providerName;
|
||||
var connectionString = GetDatabaseConnectionString(server, databaseName, user, password, databaseProvider, out providerName);
|
||||
|
||||
SaveConnectionString(connectionString, providerName, _logger);
|
||||
_factory.Configure(connectionString, providerName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a connection string from the installer.
|
||||
/// </summary>
|
||||
/// <param name="server">The name or address of the database server.</param>
|
||||
/// <param name="databaseName">The name of the database.</param>
|
||||
/// <param name="user">The user name.</param>
|
||||
/// <param name="password">The user password.</param>
|
||||
/// <param name="databaseProvider">The name the provider (Sql, Sql Azure, Sql Ce, MySql).</param>
|
||||
/// <param name="providerName"></param>
|
||||
/// <returns>A connection string.</returns>
|
||||
public static string GetDatabaseConnectionString(string server, string databaseName, string user, string password, string databaseProvider, out string providerName)
|
||||
{
|
||||
providerName = Constants.DbProviderNames.SqlServer;
|
||||
var test = databaseProvider.ToLower();
|
||||
if (test.Contains("mysql"))
|
||||
{
|
||||
providerName = Constants.DbProviderNames.MySql;
|
||||
return $"Server={server}; Database={databaseName};Uid={user};Pwd={password}";
|
||||
}
|
||||
if (test.Contains("azure"))
|
||||
{
|
||||
return GetAzureConnectionString(server, databaseName, user, password);
|
||||
}
|
||||
return $"server={server};database={databaseName};user id={user};password={password}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures a connection string using Microsoft SQL Server integrated security.
|
||||
/// </summary>
|
||||
/// <param name="server">The name or address of the database server.</param>
|
||||
/// <param name="databaseName">The name of the database</param>
|
||||
public void ConfigureIntegratedSecurityDatabaseConnection(string server, string databaseName)
|
||||
{
|
||||
var connectionString = GetIntegratedSecurityDatabaseConnectionString(server, databaseName);
|
||||
SaveConnectionString(connectionString, Constants.DbProviderNames.SqlServer, _logger);
|
||||
_factory.Configure(connectionString, Constants.DbProviderNames.SqlServer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a connection string using Microsoft SQL Server integrated security.
|
||||
/// </summary>
|
||||
/// <param name="server">The name or address of the database server.</param>
|
||||
/// <param name="databaseName">The name of the database</param>
|
||||
/// <returns>A connection string.</returns>
|
||||
public static string GetIntegratedSecurityDatabaseConnectionString(string server, string databaseName)
|
||||
{
|
||||
return $"Server={server};Database={databaseName};Integrated Security=true";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an Azure connection string.
|
||||
/// </summary>
|
||||
/// <param name="server">The name or address of the database server.</param>
|
||||
/// <param name="databaseName">The name of the database.</param>
|
||||
/// <param name="user">The user name.</param>
|
||||
/// <param name="password">The user password.</param>
|
||||
/// <returns>A connection string.</returns>
|
||||
public static string GetAzureConnectionString(string server, string databaseName, string user, string password)
|
||||
{
|
||||
if (server.Contains(".") && ServerStartsWithTcp(server) == false)
|
||||
server = $"tcp:{server}";
|
||||
|
||||
if (server.Contains(".") == false && ServerStartsWithTcp(server))
|
||||
{
|
||||
string serverName = server.Contains(",")
|
||||
? server.Substring(0, server.IndexOf(",", StringComparison.Ordinal))
|
||||
: server;
|
||||
|
||||
var portAddition = string.Empty;
|
||||
|
||||
if (server.Contains(","))
|
||||
portAddition = server.Substring(server.IndexOf(",", StringComparison.Ordinal));
|
||||
|
||||
server = $"{serverName}.database.windows.net{portAddition}";
|
||||
}
|
||||
|
||||
if (ServerStartsWithTcp(server) == false)
|
||||
server = $"tcp:{server}.database.windows.net";
|
||||
|
||||
if (server.Contains(",") == false)
|
||||
server = $"{server},1433";
|
||||
|
||||
if (user.Contains("@") == false)
|
||||
{
|
||||
var userDomain = server;
|
||||
|
||||
if (ServerStartsWithTcp(server))
|
||||
userDomain = userDomain.Substring(userDomain.IndexOf(":", StringComparison.Ordinal) + 1);
|
||||
|
||||
if (userDomain.Contains("."))
|
||||
userDomain = userDomain.Substring(0, userDomain.IndexOf(".", StringComparison.Ordinal));
|
||||
|
||||
user = $"{user}@{userDomain}";
|
||||
}
|
||||
|
||||
return $"Server={server};Database={databaseName};User ID={user};Password={password}";
|
||||
}
|
||||
|
||||
private static bool ServerStartsWithTcp(string server)
|
||||
{
|
||||
return server.ToLower().StartsWith("tcp:".ToLower());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the connection string as a proper .net connection string in web.config.
|
||||
/// </summary>
|
||||
/// <remarks>Saves the ConnectionString in the very nasty 'medium trust'-supportive way.</remarks>
|
||||
/// <param name="connectionString">The connection string.</param>
|
||||
/// <param name="providerName">The provider name.</param>
|
||||
/// <param name="logger">A logger.</param>
|
||||
private static void SaveConnectionString(string connectionString, string providerName, ILogger logger)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(connectionString)) throw new ArgumentNullOrEmptyException(nameof(connectionString));
|
||||
if (string.IsNullOrWhiteSpace(providerName)) throw new ArgumentNullOrEmptyException(nameof(providerName));
|
||||
|
||||
// set the connection string for the new datalayer
|
||||
var connectionStringSettings = new ConnectionStringSettings(GlobalSettings.UmbracoConnectionName, connectionString, providerName);
|
||||
|
||||
var fileName = IOHelper.MapPath($"{SystemDirectories.Root}/web.config");
|
||||
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
|
||||
if (xml.Root == null) throw new Exception("Invalid web.config file.");
|
||||
var connectionStrings = xml.Root.DescendantsAndSelf("connectionStrings").FirstOrDefault();
|
||||
if (connectionStrings == null) throw new Exception("Invalid web.config file.");
|
||||
|
||||
// update connectionString if it exists, or else create a new connectionString
|
||||
var setting = connectionStrings.Descendants("add").FirstOrDefault(s => s.Attribute("name").Value == GlobalSettings.UmbracoConnectionName);
|
||||
if (setting == null)
|
||||
{
|
||||
connectionStrings.Add(new XElement("add",
|
||||
new XAttribute("name", GlobalSettings.UmbracoConnectionName),
|
||||
new XAttribute("connectionString", connectionStringSettings),
|
||||
new XAttribute("providerName", providerName)));
|
||||
}
|
||||
else
|
||||
{
|
||||
setting.Attribute("connectionString").Value = connectionString;
|
||||
setting.Attribute("providerName").Value = providerName;
|
||||
}
|
||||
|
||||
xml.Save(fileName, SaveOptions.DisableFormatting);
|
||||
logger.Info<DatabaseContext>("Configured a new ConnectionString using the '" + providerName + "' provider.");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utils
|
||||
|
||||
internal static void GiveLegacyAChance(IDatabaseFactory factory, ILogger logger)
|
||||
{
|
||||
// look for the legacy appSettings key
|
||||
var legacyConnString = ConfigurationManager.AppSettings[GlobalSettings.UmbracoConnectionName];
|
||||
if (string.IsNullOrWhiteSpace(legacyConnString)) return;
|
||||
|
||||
var test = legacyConnString.ToLowerInvariant();
|
||||
if (test.Contains("sqlce4umbraco"))
|
||||
{
|
||||
// sql ce
|
||||
ConfigureEmbeddedDatabaseConnection(factory, logger);
|
||||
}
|
||||
else if (test.Contains("tcp:"))
|
||||
{
|
||||
// sql azure
|
||||
SaveConnectionString(legacyConnString, Constants.DbProviderNames.SqlServer, logger);
|
||||
factory.Configure(legacyConnString, Constants.DbProviderNames.SqlServer);
|
||||
}
|
||||
else if (test.Contains("datalayer=mysql"))
|
||||
{
|
||||
// mysql
|
||||
|
||||
// strip the datalayer part off
|
||||
var connectionStringWithoutDatalayer = string.Empty;
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
foreach (var variable in legacyConnString.Split(';').Where(x => x.ToLowerInvariant().StartsWith("datalayer") == false))
|
||||
connectionStringWithoutDatalayer = $"{connectionStringWithoutDatalayer}{variable};";
|
||||
|
||||
SaveConnectionString(connectionStringWithoutDatalayer, Constants.DbProviderNames.MySql, logger);
|
||||
factory.Configure(connectionStringWithoutDatalayer, Constants.DbProviderNames.MySql);
|
||||
}
|
||||
else
|
||||
{
|
||||
// sql server
|
||||
SaveConnectionString(legacyConnString, Constants.DbProviderNames.SqlServer, logger);
|
||||
factory.Configure(legacyConnString, Constants.DbProviderNames.SqlServer);
|
||||
}
|
||||
|
||||
// remove the legacy connection string, so we don't end up in a loop if something goes wrong
|
||||
GlobalSettings.RemoveSetting(GlobalSettings.UmbracoConnectionName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Database Schema
|
||||
|
||||
internal DatabaseSchemaResult ValidateDatabaseSchema()
|
||||
{
|
||||
if (_factory.Configured == false)
|
||||
return new DatabaseSchemaResult(SqlSyntax);
|
||||
|
||||
if (_databaseSchemaValidationResult != null)
|
||||
return _databaseSchemaValidationResult;
|
||||
|
||||
var database = _factory.GetDatabase();
|
||||
var dbSchema = new DatabaseSchemaCreation(database, _logger);
|
||||
_databaseSchemaValidationResult = dbSchema.ValidateSchema();
|
||||
return _databaseSchemaValidationResult;
|
||||
}
|
||||
|
||||
internal Result CreateDatabaseSchemaAndData()
|
||||
{
|
||||
try
|
||||
{
|
||||
var readyForInstall = CheckReadyForInstall();
|
||||
if (readyForInstall.Success == false)
|
||||
{
|
||||
return readyForInstall.Result;
|
||||
}
|
||||
|
||||
_logger.Info<DatabaseContext>("Database configuration status: Started");
|
||||
|
||||
var database = _factory.GetDatabase();
|
||||
|
||||
// If MySQL, we're going to ensure that database calls are maintaining proper casing as to remove the necessity for checks
|
||||
// for case insensitive queries. In an ideal situation (which is what we're striving for), all calls would be case sensitive.
|
||||
|
||||
/*
|
||||
var supportsCaseInsensitiveQueries = SqlSyntax.SupportsCaseInsensitiveQueries(database);
|
||||
if (supportsCaseInsensitiveQueries == false)
|
||||
{
|
||||
message = "<p> </p><p>The database you're trying to use does not support case insensitive queries. <br />We currently do not support these types of databases.</p>" +
|
||||
"<p>You can fix this by changing the following setting in your my.ini file in your MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1</pre><br />" +
|
||||
"<p>Note: Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
|
||||
return new Result { Message = message, Success = false, Percentage = "15" };
|
||||
}
|
||||
*/
|
||||
|
||||
var message = GetResultMessageForMySql();
|
||||
var schemaResult = ValidateDatabaseSchema();
|
||||
var installedSchemaVersion = schemaResult.DetermineInstalledVersion();
|
||||
|
||||
//If Configuration Status is empty and the determined version is "empty" its a new install - otherwise upgrade the existing
|
||||
if (string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus) && installedSchemaVersion.Equals(new Version(0, 0, 0)))
|
||||
{
|
||||
var helper = new DatabaseSchemaHelper(database, _logger);
|
||||
helper.CreateDatabaseSchema(_runtime, _migrationEntryService, true);
|
||||
|
||||
message = message + "<p>Installation completed!</p>";
|
||||
|
||||
//now that everything is done, we need to determine the version of SQL server that is executing
|
||||
_logger.Info<DatabaseContext>("Database configuration status: " + message);
|
||||
return new Result { Message = message, Success = true, Percentage = "100" };
|
||||
}
|
||||
|
||||
//we need to do an upgrade so return a new status message and it will need to be done during the next step
|
||||
_logger.Info<DatabaseContext>("Database requires upgrade");
|
||||
message = "<p>Upgrading database, this may take some time...</p>";
|
||||
return new Result
|
||||
{
|
||||
RequiresUpgrade = true,
|
||||
Message = message,
|
||||
Success = true,
|
||||
Percentage = "30"
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return HandleInstallException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This assumes all of the previous checks are done!
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal Result UpgradeSchemaAndData(IMigrationEntryService migrationEntryService, MigrationCollectionBuilder builder)
|
||||
{
|
||||
try
|
||||
{
|
||||
var readyForInstall = CheckReadyForInstall();
|
||||
if (readyForInstall.Success == false)
|
||||
{
|
||||
return readyForInstall.Result;
|
||||
}
|
||||
|
||||
_logger.Info<DatabaseContext>("Database upgrade started");
|
||||
|
||||
var database = _factory.GetDatabase();
|
||||
//var supportsCaseInsensitiveQueries = SqlSyntax.SupportsCaseInsensitiveQueries(database);
|
||||
|
||||
var message = GetResultMessageForMySql();
|
||||
|
||||
var schemaResult = ValidateDatabaseSchema();
|
||||
|
||||
var installedSchemaVersion = new SemVersion(schemaResult.DetermineInstalledVersion());
|
||||
var installedMigrationVersion = schemaResult.DetermineInstalledVersionByMigrations(migrationEntryService);
|
||||
var targetVersion = UmbracoVersion.Current;
|
||||
|
||||
//In some cases - like upgrading from 7.2.6 -> 7.3, there will be no migration information in the database and therefore it will
|
||||
// return a version of 0.0.0 and we don't necessarily want to run all migrations from 0 -> 7.3, so we'll just ensure that the
|
||||
// migrations are run for the target version
|
||||
if (installedMigrationVersion == new SemVersion(new Version(0, 0, 0)) && installedSchemaVersion > new SemVersion(new Version(0, 0, 0)))
|
||||
{
|
||||
//set the installedMigrationVersion to be one less than the target so the latest migrations are guaranteed to execute
|
||||
installedMigrationVersion = new SemVersion(targetVersion.SubtractRevision());
|
||||
}
|
||||
|
||||
//Figure out what our current installed version is. If the web.config doesn't have a version listed, then we'll use the minimum
|
||||
// version detected between the schema installed and the migrations listed in the migration table.
|
||||
// If there is a version in the web.config, we'll take the minimum between the listed migration in the db and what
|
||||
// is declared in the web.config.
|
||||
|
||||
var currentInstalledVersion = string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus)
|
||||
//Take the minimum version between the detected schema version and the installed migration version
|
||||
? new[] {installedSchemaVersion, installedMigrationVersion}.Min()
|
||||
//Take the minimum version between the installed migration version and the version specified in the config
|
||||
: new[] { SemVersion.Parse(GlobalSettings.ConfigurationStatus), installedMigrationVersion }.Min();
|
||||
|
||||
//Ok, another edge case here. If the current version is a pre-release,
|
||||
// then we want to ensure all migrations for the current release are executed.
|
||||
if (currentInstalledVersion.Prerelease.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
currentInstalledVersion = new SemVersion(currentInstalledVersion.GetVersion().SubtractRevision());
|
||||
}
|
||||
|
||||
//DO the upgrade!
|
||||
|
||||
var runner = new MigrationRunner(builder, migrationEntryService, _logger, currentInstalledVersion, UmbracoVersion.SemanticVersion, GlobalSettings.UmbracoMigrationName);
|
||||
|
||||
var migrationContext = new MigrationContext(database, _logger);
|
||||
var upgraded = runner.Execute(migrationContext /*, true*/);
|
||||
|
||||
if (upgraded == false)
|
||||
{
|
||||
throw new ApplicationException("Upgrading failed, either an error occurred during the upgrade process or an event canceled the upgrade process, see log for full details");
|
||||
}
|
||||
|
||||
message = message + "<p>Upgrade completed!</p>";
|
||||
|
||||
//now that everything is done, we need to determine the version of SQL server that is executing
|
||||
|
||||
_logger.Info<DatabaseContext>("Database configuration status: " + message);
|
||||
|
||||
return new Result { Message = message, Success = true, Percentage = "100" };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return HandleInstallException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private string GetResultMessageForMySql()
|
||||
{
|
||||
if (SqlSyntax.GetType() == typeof(MySqlSyntaxProvider))
|
||||
{
|
||||
return "<p> </p><p>Congratulations, the database step ran successfully!</p>" +
|
||||
"<p>Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.</p>" +
|
||||
"<p>However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries</p>" +
|
||||
"<p>Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>They can check this by looking for the following setting in the my.ini file in their MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1</pre><br />" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/*
|
||||
private string GetResultMessageForMySql(bool? supportsCaseInsensitiveQueries)
|
||||
{
|
||||
if (supportsCaseInsensitiveQueries == null)
|
||||
{
|
||||
return "<p> </p><p>Warning! Could not check if your database type supports case insensitive queries. <br />We currently do not support these databases that do not support case insensitive queries.</p>" +
|
||||
"<p>You can check this by looking for the following setting in your my.ini file in your MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1</pre><br />" +
|
||||
"<p>Note: Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
}
|
||||
if (SqlSyntax.GetType() == typeof(MySqlSyntaxProvider))
|
||||
{
|
||||
return "<p> </p><p>Congratulations, the database step ran successfully!</p>" +
|
||||
"<p>Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.</p>" +
|
||||
"<p>However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries</p>" +
|
||||
"<p>Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>They can check this by looking for the following setting in the my.ini file in their MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1</pre><br />" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
}
|
||||
return string.Empty;
|
||||
}*/
|
||||
|
||||
private Attempt<Result> CheckReadyForInstall()
|
||||
{
|
||||
if (_factory.Configured == false)
|
||||
{
|
||||
return Attempt.Fail(new Result
|
||||
{
|
||||
Message = "Database configuration is invalid. Please check that the entered database exists and"
|
||||
+ " that the provided username and password has write access to the database.",
|
||||
Success = false,
|
||||
Percentage = "10"
|
||||
});
|
||||
}
|
||||
return Attempt<Result>.Succeed();
|
||||
}
|
||||
|
||||
private Result HandleInstallException(Exception ex)
|
||||
{
|
||||
_logger.Error<DatabaseContext>("Database configuration failed", ex);
|
||||
|
||||
if (_databaseSchemaValidationResult != null)
|
||||
{
|
||||
_logger.Info<DatabaseContext>("The database schema validation produced the following summary: \n" + _databaseSchemaValidationResult.GetSummary());
|
||||
}
|
||||
|
||||
return new Result
|
||||
{
|
||||
Message =
|
||||
"The database configuration failed with the following message: " + ex.Message +
|
||||
"\n Please check log file for additional information (can be found in '/App_Data/Logs/UmbracoTraceLog.txt')",
|
||||
Success = false,
|
||||
Percentage = "90"
|
||||
};
|
||||
}
|
||||
|
||||
internal class Result
|
||||
{
|
||||
public bool RequiresUpgrade { get; set; }
|
||||
public string Message { get; set; }
|
||||
public bool Success { get; set; }
|
||||
public string Percentage { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal bool IsConnectionStringConfigured(ConnectionStringSettings databaseSettings)
|
||||
{
|
||||
var dbIsSqlCe = false;
|
||||
if (databaseSettings?.ProviderName != null)
|
||||
dbIsSqlCe = databaseSettings.ProviderName == Constants.DbProviderNames.SqlCe;
|
||||
var sqlCeDatabaseExists = false;
|
||||
if (dbIsSqlCe)
|
||||
{
|
||||
var parts = databaseSettings.ConnectionString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
var dataSourcePart = parts.FirstOrDefault(x => x.InvariantStartsWith("Data Source="));
|
||||
if (dataSourcePart != null)
|
||||
{
|
||||
var datasource = dataSourcePart.Replace("|DataDirectory|", AppDomain.CurrentDomain.GetData("DataDirectory").ToString());
|
||||
var filePath = datasource.Replace("Data Source=", string.Empty);
|
||||
sqlCeDatabaseExists = File.Exists(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
// Either the connection details are not fully specified or it's a SQL CE database that doesn't exist yet
|
||||
if (databaseSettings == null
|
||||
|| string.IsNullOrWhiteSpace(databaseSettings.ConnectionString) || string.IsNullOrWhiteSpace(databaseSettings.ProviderName)
|
||||
|| (dbIsSqlCe && sqlCeDatabaseExists == false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// fixme - kill!
|
||||
public Sql<SqlContext> Sql()
|
||||
{
|
||||
return Database.Sql();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,8 @@
|
||||
/// itself it the factory has no model for that content type.</returns>
|
||||
IPublishedContent CreateModel(IPublishedContent content);
|
||||
|
||||
T CreateModel<T>(IPublishedFragment content);
|
||||
// temp - dont break MB
|
||||
//T CreateModel<T>(IPublishedFragment content);
|
||||
|
||||
// fixme
|
||||
// and we'd need a
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using NPoco;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Web.PublishedCache.NuCache.DataSource
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[TableName("cmsContentNu")]
|
||||
[PrimaryKey("nodeId", AutoIncrement = false)]
|
||||
@@ -30,6 +30,7 @@ namespace Umbraco.Core.Persistence
|
||||
{
|
||||
private readonly IUmbracoDatabaseAccessor _umbracoDatabaseAccessor;
|
||||
private readonly ISqlSyntaxProvider[] _sqlSyntaxProviders;
|
||||
private readonly IMapperCollection _mappers;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private DatabaseFactory _databaseFactory;
|
||||
@@ -39,6 +40,8 @@ namespace Umbraco.Core.Persistence
|
||||
private DbProviderFactory _dbProviderFactory;
|
||||
private DatabaseType _databaseType;
|
||||
private ISqlSyntaxProvider _sqlSyntax;
|
||||
private IQueryFactory _queryFactory;
|
||||
private SqlContext _sqlContext;
|
||||
private RetryPolicy _connectionRetryPolicy;
|
||||
private RetryPolicy _commandRetryPolicy;
|
||||
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
||||
@@ -49,13 +52,13 @@ namespace Umbraco.Core.Persistence
|
||||
/// <param name="sqlSyntaxProviders">The collection of available sql syntax providers.</param>
|
||||
/// <param name="logger">A logger.</param>
|
||||
/// <param name="umbracoDatabaseAccessor"></param>
|
||||
/// <param name="queryFactory"></param>
|
||||
/// <param name="mappers"></param>
|
||||
/// <remarks>Used by LightInject.</remarks>
|
||||
public DefaultDatabaseFactory(IEnumerable<ISqlSyntaxProvider> sqlSyntaxProviders, ILogger logger, IUmbracoDatabaseAccessor umbracoDatabaseAccessor, IQueryFactory queryFactory)
|
||||
: this(GlobalSettings.UmbracoConnectionName, sqlSyntaxProviders, logger, umbracoDatabaseAccessor, queryFactory)
|
||||
public DefaultDatabaseFactory(IEnumerable<ISqlSyntaxProvider> sqlSyntaxProviders, ILogger logger, IUmbracoDatabaseAccessor umbracoDatabaseAccessor, IMapperCollection mappers)
|
||||
: this(GlobalSettings.UmbracoConnectionName, sqlSyntaxProviders, logger, umbracoDatabaseAccessor, mappers)
|
||||
{
|
||||
if (Configured == false)
|
||||
DatabaseContext.GiveLegacyAChance(this, logger);
|
||||
DatabaseBuilder.GiveLegacyAChance(this, logger);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -65,17 +68,17 @@ namespace Umbraco.Core.Persistence
|
||||
/// <param name="sqlSyntaxProviders">The collection of available sql syntax providers.</param>
|
||||
/// <param name="logger">A logger</param>
|
||||
/// <param name="umbracoDatabaseAccessor"></param>
|
||||
/// <param name="queryFactory"></param>
|
||||
/// <param name="mappers"></param>
|
||||
/// <remarks>Used by the other ctor and in tests.</remarks>
|
||||
public DefaultDatabaseFactory(string connectionStringName, IEnumerable<ISqlSyntaxProvider> sqlSyntaxProviders, ILogger logger, IUmbracoDatabaseAccessor umbracoDatabaseAccessor, IQueryFactory queryFactory)
|
||||
public DefaultDatabaseFactory(string connectionStringName, IEnumerable<ISqlSyntaxProvider> sqlSyntaxProviders, ILogger logger, IUmbracoDatabaseAccessor umbracoDatabaseAccessor, IMapperCollection mappers)
|
||||
{
|
||||
if (sqlSyntaxProviders == null) throw new ArgumentNullException(nameof(sqlSyntaxProviders));
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
if (umbracoDatabaseAccessor == null) throw new ArgumentNullException(nameof(umbracoDatabaseAccessor));
|
||||
if (string.IsNullOrWhiteSpace(connectionStringName)) throw new ArgumentNullOrEmptyException(nameof(connectionStringName));
|
||||
if (queryFactory == null) throw new ArgumentNullException(nameof(queryFactory));
|
||||
if (mappers == null) throw new ArgumentNullException(nameof(mappers));
|
||||
|
||||
QueryFactory = queryFactory;
|
||||
_mappers = mappers;
|
||||
_sqlSyntaxProviders = sqlSyntaxProviders.ToArray();
|
||||
_logger = logger;
|
||||
_umbracoDatabaseAccessor = umbracoDatabaseAccessor;
|
||||
@@ -105,16 +108,16 @@ namespace Umbraco.Core.Persistence
|
||||
/// <param name="sqlSyntaxProviders">The collection of available sql syntax providers.</param>
|
||||
/// <param name="logger">A logger.</param>
|
||||
/// <param name="umbracoDatabaseAccessor"></param>
|
||||
/// <param name="queryFactory"></param>
|
||||
/// <param name="mappers"></param>
|
||||
/// <remarks>Used in tests.</remarks>
|
||||
public DefaultDatabaseFactory(string connectionString, string providerName, IEnumerable<ISqlSyntaxProvider> sqlSyntaxProviders, ILogger logger, IUmbracoDatabaseAccessor umbracoDatabaseAccessor, IQueryFactory queryFactory)
|
||||
public DefaultDatabaseFactory(string connectionString, string providerName, IEnumerable<ISqlSyntaxProvider> sqlSyntaxProviders, ILogger logger, IUmbracoDatabaseAccessor umbracoDatabaseAccessor, IMapperCollection mappers)
|
||||
{
|
||||
if (sqlSyntaxProviders == null) throw new ArgumentNullException(nameof(sqlSyntaxProviders));
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
if (umbracoDatabaseAccessor == null) throw new ArgumentNullException(nameof(umbracoDatabaseAccessor));
|
||||
if (queryFactory == null) throw new ArgumentNullException(nameof(queryFactory));
|
||||
if (mappers == null) throw new ArgumentNullException(nameof(mappers));
|
||||
|
||||
QueryFactory = queryFactory;
|
||||
_mappers = mappers;
|
||||
_sqlSyntaxProviders = sqlSyntaxProviders.ToArray();
|
||||
_logger = logger;
|
||||
_umbracoDatabaseAccessor = umbracoDatabaseAccessor;
|
||||
@@ -154,7 +157,16 @@ namespace Umbraco.Core.Persistence
|
||||
/// <summary>
|
||||
/// Gets the database query factory.
|
||||
/// </summary>
|
||||
public IQueryFactory QueryFactory { get; }
|
||||
public IQueryFactory QueryFactory {
|
||||
get
|
||||
{
|
||||
EnsureConfigured();
|
||||
return _queryFactory;
|
||||
}
|
||||
}
|
||||
|
||||
// fixme
|
||||
public SqlContext SqlContext => _sqlContext;
|
||||
|
||||
// will be configured by the database context
|
||||
public void Configure(string connectionString, string providerName)
|
||||
@@ -199,6 +211,12 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
if (_databaseFactory == null) throw new NullReferenceException("The call to DatabaseFactory.Config yielded a null DatabaseFactory instance.");
|
||||
|
||||
// these are created here because it is the DefaultDatabaseFactory that determines
|
||||
// the sql syntax, poco data factory, and database type - so it "owns" the context
|
||||
// and the query factory
|
||||
_sqlContext = new SqlContext(_sqlSyntax, _pocoDataFactory, _databaseType);
|
||||
_queryFactory = new QueryFactory(_sqlSyntax, _mappers);
|
||||
|
||||
_logger.Debug<DefaultDatabaseFactory>("Configured.");
|
||||
Configured = true;
|
||||
}
|
||||
@@ -232,7 +250,7 @@ namespace Umbraco.Core.Persistence
|
||||
// method used by NPoco's DatabaseFactory to actually create the database instance
|
||||
private UmbracoDatabase CreateDatabaseInstance()
|
||||
{
|
||||
return new UmbracoDatabase(_connectionString, _sqlSyntax, _databaseType, _dbProviderFactory, _logger, _connectionRetryPolicy, _commandRetryPolicy);
|
||||
return new UmbracoDatabase(_connectionString, _sqlContext, _dbProviderFactory, _logger, _connectionRetryPolicy, _commandRetryPolicy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -246,7 +264,7 @@ namespace Umbraco.Core.Persistence
|
||||
// check if it's in scope
|
||||
var db = _umbracoDatabaseAccessor.UmbracoDatabase;
|
||||
if (db != null) return db;
|
||||
db = (UmbracoDatabase)_databaseFactory.GetDatabase();
|
||||
db = (UmbracoDatabase) _databaseFactory.GetDatabase();
|
||||
_umbracoDatabaseAccessor.UmbracoDatabase = db;
|
||||
return db;
|
||||
}
|
||||
|
||||
@@ -22,5 +22,7 @@ namespace Umbraco.Core.Persistence
|
||||
bool CanConnect { get; }
|
||||
|
||||
IQueryFactory QueryFactory { get; }
|
||||
|
||||
ISqlSyntaxProvider SqlSyntax { get; }
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,8 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
{46, typeof (UmbracoDeployChecksumDto)},
|
||||
{47, typeof (UmbracoDeployDependencyDto)},
|
||||
{48, typeof (RedirectUrlDto) },
|
||||
{49, typeof (LockDto) }
|
||||
{49, typeof (LockDto) },
|
||||
{50, typeof (ContentNuDto) }
|
||||
};
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using NPoco;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.Migrations.Syntax.Alter;
|
||||
using Umbraco.Core.Persistence.Migrations.Syntax.Create;
|
||||
@@ -45,14 +44,11 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
|
||||
public IUpdateBuilder Update => new UpdateBuilder(Context);
|
||||
|
||||
protected Sql<SqlContext> Sql() => Context.Database.Sql();
|
||||
|
||||
public IIfDatabaseBuilder IfDatabase(params DatabaseType[] supportedDatabaseTypes)
|
||||
{
|
||||
return new IfDatabaseBuilder(Context, supportedDatabaseTypes);
|
||||
}
|
||||
|
||||
protected Sql<SqlContext> Sql()
|
||||
{
|
||||
return Context.Database.Sql();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,26 +30,21 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
/// <returns>This instance so calls to this method are chainable</returns>
|
||||
public virtual IQuery<T> Where(Expression<Func<T, bool>> predicate)
|
||||
{
|
||||
if (predicate != null)
|
||||
{
|
||||
//TODO: This should have an SqlSyntax object passed in, this ctor is relying on a singleton
|
||||
var expressionHelper = new ModelToSqlExpressionVisitor<T>(_sqlSyntax, _mappers);
|
||||
string whereExpression = expressionHelper.Visit(predicate);
|
||||
if (predicate == null) return this;
|
||||
|
||||
var expressionHelper = new ModelToSqlExpressionVisitor<T>(_sqlSyntax, _mappers);
|
||||
var whereExpression = expressionHelper.Visit(predicate);
|
||||
_wheres.Add(new Tuple<string, object[]>(whereExpression, expressionHelper.GetSqlParameters()));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public virtual IQuery<T> WhereIn(Expression<Func<T, object>> fieldSelector, IEnumerable values)
|
||||
{
|
||||
if (fieldSelector != null)
|
||||
{
|
||||
var expressionHelper = new ModelToSqlExpressionVisitor<T>(_sqlSyntax, _mappers);
|
||||
string whereExpression = expressionHelper.Visit(fieldSelector);
|
||||
if (fieldSelector == null) return this;
|
||||
|
||||
_wheres.Add(new Tuple<string, object[]>(whereExpression + " IN (@values)", new object[] { new { @values = values } }));
|
||||
}
|
||||
var expressionHelper = new ModelToSqlExpressionVisitor<T>(_sqlSyntax, _mappers);
|
||||
var whereExpression = expressionHelper.Visit(fieldSelector);
|
||||
_wheres.Add(new Tuple<string, object[]>(whereExpression + " IN (@values)", new object[] { new { values } }));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal class AuditRepository : NPocoRepositoryBase<int, AuditItem>, IAuditRepository
|
||||
{
|
||||
public AuditRepository(IDatabaseUnitOfWork work, [Inject(RepositoryCompositionRoot.DisabledCache)] CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public AuditRepository(IDatabaseUnitOfWork work, [Inject(RepositoryCompositionRoot.DisabledCache)] CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private readonly CacheHelper _cacheHelper;
|
||||
private PermissionRepository<IContent> _permissionRepository;
|
||||
|
||||
public ContentRepository(IDatabaseUnitOfWork work, CacheHelper cacheHelper, ILogger logger, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, IContentSection contentSection, IQueryFactory queryFactory)
|
||||
: base(work, cacheHelper, logger, contentSection, queryFactory)
|
||||
public ContentRepository(IDatabaseUnitOfWork work, CacheHelper cacheHelper, ILogger logger, IContentTypeRepository contentTypeRepository, ITemplateRepository templateRepository, ITagRepository tagRepository, IContentSection contentSection)
|
||||
: base(work, cacheHelper, logger, contentSection)
|
||||
{
|
||||
if (contentTypeRepository == null) throw new ArgumentNullException(nameof(contentTypeRepository));
|
||||
if (templateRepository == null) throw new ArgumentNullException(nameof(templateRepository));
|
||||
@@ -43,7 +43,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
_tagRepository = tagRepository;
|
||||
_cacheHelper = cacheHelper;
|
||||
|
||||
_publishedQuery = queryFactory.Create<IContent>().Where(x => x.Published);
|
||||
_publishedQuery = work.DatabaseContext.Query<IContent>().Where(x => x.Published);
|
||||
|
||||
EnsureUniqueNaming = true;
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private readonly ITemplateRepository _templateRepository;
|
||||
private IRepositoryCachePolicy<IContentType, int> _cachePolicy;
|
||||
|
||||
public ContentTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ITemplateRepository templateRepository, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public ContentTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ITemplateRepository templateRepository)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
_templateRepository = templateRepository;
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
internal abstract class ContentTypeRepositoryBase<TEntity> : NPocoRepositoryBase<int, TEntity>, IReadRepository<Guid, TEntity>
|
||||
where TEntity : class, IContentTypeComposition
|
||||
{
|
||||
protected ContentTypeRepositoryBase(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
protected ContentTypeRepositoryBase(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{ }
|
||||
|
||||
public IEnumerable<MoveEventInfo<TEntity>> Move(TEntity moving, EntityContainer container)
|
||||
|
||||
@@ -7,8 +7,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
class DataTypeContainerRepository : EntityContainerRepository, IDataTypeContainerRepository
|
||||
{
|
||||
public DataTypeContainerRepository(IDatabaseUnitOfWork uow, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(uow, cache, logger, queryFactory, Constants.ObjectTypes.DataTypeContainerGuid)
|
||||
public DataTypeContainerRepository(IDatabaseUnitOfWork uow, CacheHelper cache, ILogger logger)
|
||||
: base(uow, cache, logger, Constants.ObjectTypes.DataTypeContainerGuid)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -31,11 +31,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private readonly IContentTypeRepository _contentTypeRepository;
|
||||
private readonly DataTypePreValueRepository _preValRepository;
|
||||
|
||||
public DataTypeDefinitionRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IContentTypeRepository contentTypeRepository, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public DataTypeDefinitionRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IContentTypeRepository contentTypeRepository)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
_contentTypeRepository = contentTypeRepository;
|
||||
_preValRepository = new DataTypePreValueRepository(work, CacheHelper.CreateDisabledCacheHelper(), logger, queryFactory);
|
||||
_preValRepository = new DataTypePreValueRepository(work, CacheHelper.CreateDisabledCacheHelper(), logger);
|
||||
}
|
||||
|
||||
#region Overrides of RepositoryBase<int,DataTypeDefinition>
|
||||
@@ -533,8 +533,8 @@ AND umbracoNode.id <> @id",
|
||||
/// </summary>
|
||||
private class DataTypePreValueRepository : NPocoRepositoryBase<int, PreValueEntity>
|
||||
{
|
||||
public DataTypePreValueRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public DataTypePreValueRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
private IRepositoryCachePolicy<IDictionaryItem, int> _cachePolicy;
|
||||
|
||||
public DictionaryRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public DictionaryRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{ }
|
||||
|
||||
protected override IRepositoryCachePolicy<IDictionaryItem, int> CachePolicy
|
||||
@@ -240,13 +240,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
public IDictionaryItem Get(Guid uniqueId)
|
||||
{
|
||||
var uniqueIdRepo = new DictionaryByUniqueIdRepository(this, UnitOfWork, RepositoryCache, Logger, QueryFactory);
|
||||
var uniqueIdRepo = new DictionaryByUniqueIdRepository(this, UnitOfWork, Cache, Logger);
|
||||
return uniqueIdRepo.Get(uniqueId);
|
||||
}
|
||||
|
||||
public IDictionaryItem Get(string key)
|
||||
{
|
||||
var keyRepo = new DictionaryByKeyRepository(this, UnitOfWork, RepositoryCache, Logger, QueryFactory);
|
||||
var keyRepo = new DictionaryByKeyRepository(this, UnitOfWork, Cache, Logger);
|
||||
return keyRepo.Get(key);
|
||||
}
|
||||
|
||||
@@ -294,8 +294,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private IRepositoryCachePolicy<IDictionaryItem, Guid> _cachePolicy;
|
||||
private readonly DictionaryRepository _dictionaryRepository;
|
||||
|
||||
public DictionaryByUniqueIdRepository(DictionaryRepository dictionaryRepository, IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public DictionaryByUniqueIdRepository(DictionaryRepository dictionaryRepository, IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
_dictionaryRepository = dictionaryRepository;
|
||||
}
|
||||
@@ -355,8 +355,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private IRepositoryCachePolicy<IDictionaryItem, string> _cachePolicy;
|
||||
private readonly DictionaryRepository _dictionaryRepository;
|
||||
|
||||
public DictionaryByKeyRepository(DictionaryRepository dictionaryRepository, IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public DictionaryByKeyRepository(DictionaryRepository dictionaryRepository, IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
_dictionaryRepository = dictionaryRepository;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
@@ -8,8 +7,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
class DocumentTypeContainerRepository : EntityContainerRepository, IDocumentTypeContainerRepository
|
||||
{
|
||||
public DocumentTypeContainerRepository(IDatabaseUnitOfWork uow, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(uow, cache, logger, queryFactory, Constants.ObjectTypes.DocumentTypeContainerGuid)
|
||||
public DocumentTypeContainerRepository(IDatabaseUnitOfWork uow, CacheHelper cache, ILogger logger)
|
||||
: base(uow, cache, logger, Constants.ObjectTypes.DocumentTypeContainerGuid)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
private IRepositoryCachePolicy<IDomain, int> _cachePolicy;
|
||||
|
||||
public DomainRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public DomainRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
private readonly Guid _containerObjectType;
|
||||
|
||||
public EntityContainerRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory, Guid containerObjectType)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public EntityContainerRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, Guid containerObjectType)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
var allowedContainers = new[] {Constants.ObjectTypes.DocumentTypeContainerGuid, Constants.ObjectTypes.MediaTypeContainerGuid, Constants.ObjectTypes.DataTypeContainerGuid};
|
||||
_containerObjectType = containerObjectType;
|
||||
|
||||
@@ -19,12 +19,9 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </remarks>
|
||||
internal class EntityRepository : DisposableObject, IEntityRepository
|
||||
{
|
||||
private readonly IQueryFactory _queryFactory;
|
||||
|
||||
public EntityRepository(IDatabaseUnitOfWork work, IQueryFactory queryFactory)
|
||||
public EntityRepository(IDatabaseUnitOfWork work)
|
||||
{
|
||||
UnitOfWork = work;
|
||||
_queryFactory = queryFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -34,7 +31,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
#region Query Methods
|
||||
|
||||
public IQuery<IUmbracoEntity> Query => _queryFactory.Create<IUmbracoEntity>();
|
||||
public IQuery<IUmbracoEntity> Query => UnitOfWork.DatabaseContext.Query<IUmbracoEntity>();
|
||||
|
||||
public Sql<SqlContext> Sql() { return UnitOfWork.Database.Sql();}
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal class ExternalLoginRepository : NPocoRepositoryBase<int, IIdentityUserLogin>, IExternalLoginRepository
|
||||
{
|
||||
public ExternalLoginRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public ExternalLoginRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IAuditRepository : IRepositoryQueryable<int, AuditItem>
|
||||
public interface IAuditRepository : IQueryRepository<int, AuditItem>
|
||||
{
|
||||
void CleanLogs(int maximumAgeOfLogsInMinutes);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IContentTypeRepositoryBase<TItem> : IRepositoryQueryable<int, TItem>, IReadRepository<Guid, TItem>
|
||||
public interface IContentTypeRepositoryBase<TItem> : IQueryRepository<int, TItem>, IReadRepository<Guid, TItem>
|
||||
where TItem : IContentTypeComposition
|
||||
{
|
||||
TItem Get(string alias);
|
||||
|
||||
@@ -6,7 +6,7 @@ using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IDataTypeDefinitionRepository : IRepositoryQueryable<int, IDataTypeDefinition>
|
||||
public interface IDataTypeDefinitionRepository : IQueryRepository<int, IDataTypeDefinition>
|
||||
{
|
||||
|
||||
PreValueCollection GetPreValuesCollectionByDataTypeId(int dataTypeId);
|
||||
|
||||
@@ -4,7 +4,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IDictionaryRepository : IRepositoryQueryable<int, IDictionaryItem>
|
||||
public interface IDictionaryRepository : IQueryRepository<int, IDictionaryItem>
|
||||
{
|
||||
IDictionaryItem Get(Guid uniqueId);
|
||||
IDictionaryItem Get(string key);
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IDomainRepository : IRepositoryQueryable<int, IDomain>
|
||||
public interface IDomainRepository : IQueryRepository<int, IDomain>
|
||||
{
|
||||
IDomain GetByName(string domainName);
|
||||
bool Exists(string domainName);
|
||||
|
||||
@@ -4,7 +4,7 @@ using Umbraco.Core.Models.Identity;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IExternalLoginRepository : IRepositoryQueryable<int, IIdentityUserLogin>
|
||||
public interface IExternalLoginRepository : IQueryRepository<int, IIdentityUserLogin>
|
||||
{
|
||||
void SaveUserLogins(int memberId, IEnumerable<UserLoginInfo> logins);
|
||||
void DeleteUserLogins(int memberId);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface ILanguageRepository : IRepositoryQueryable<int, ILanguage>
|
||||
public interface ILanguageRepository : IQueryRepository<int, ILanguage>
|
||||
{
|
||||
ILanguage GetByCultureName(string cultureName);
|
||||
ILanguage GetByIsoCode(string isoCode);
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal interface IMacroRepository : IRepositoryQueryable<int, IMacro>
|
||||
internal interface IMacroRepository : IQueryRepository<int, IMacro>
|
||||
{
|
||||
|
||||
//IEnumerable<IMacro> GetAll(params string[] aliases);
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IMemberGroupRepository : IRepositoryQueryable<int, IMemberGroup>
|
||||
public interface IMemberGroupRepository : IQueryRepository<int, IMemberGroup>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a member group by it's name
|
||||
|
||||
@@ -4,7 +4,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IMigrationEntryRepository : IRepositoryQueryable<int, IMigrationEntry>
|
||||
public interface IMigrationEntryRepository : IQueryRepository<int, IMigrationEntry>
|
||||
{
|
||||
IMigrationEntry FindEntry(string migrationName, SemVersion version);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IPublicAccessRepository : IRepositoryQueryable<Guid, PublicAccessEntry>
|
||||
public interface IPublicAccessRepository : IQueryRepository<Guid, PublicAccessEntry>
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -6,12 +6,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
//TODO: This should be decoupled! Shouldn't inherit from the IRepository
|
||||
|
||||
/// <summary>
|
||||
/// Defines the implementation of a Repository, which allows queries against the <see cref="TEntity"/>
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity">Type of <see cref="IAggregateRoot"/> entity for which the repository is used</typeparam>
|
||||
/// <typeparam name="TId">Type of the Id used for this entity</typeparam>
|
||||
public interface IRepositoryQueryable<in TId, TEntity> : IRepository<TId, TEntity>
|
||||
public interface IQueryRepository<in TId, TEntity> : IRepository<TId, TEntity>
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a query instance
|
||||
@@ -7,7 +7,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <summary>
|
||||
/// Defines the <see cref="IRedirectUrl"/> repository.
|
||||
/// </summary>
|
||||
public interface IRedirectUrlRepository : IRepositoryQueryable<Guid, IRedirectUrl>
|
||||
public interface IRedirectUrlRepository : IQueryRepository<Guid, IRedirectUrl>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a redirect url.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IRelationRepository : IRepositoryQueryable<int, IRelation>
|
||||
public interface IRelationRepository : IQueryRepository<int, IRelation>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IRelationTypeRepository : IRepositoryQueryable<int, IRelationType>
|
||||
public interface IRelationTypeRepository : IQueryRepository<int, IRelationType>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the base implementation of a Repository
|
||||
/// Defines the base implementation of a repository.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently this interface is empty but it is useful for flagging a repository without having generic parameters, it also might
|
||||
/// come in handy if we need to add anything to the base/non-generic repository interface.
|
||||
/// </remarks>
|
||||
public interface IRepository
|
||||
{
|
||||
|
||||
}
|
||||
{ }
|
||||
|
||||
public interface IReadRepository<in TId, out TEntity> : IRepository
|
||||
{
|
||||
@@ -39,12 +32,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
bool Exists(TId id);
|
||||
}
|
||||
|
||||
//TODO: This should be decoupled! Shouldn't inherit from the IReadRepository and should be named IWriteRepository
|
||||
|
||||
/// <summary>
|
||||
/// Defines the implementation of a Repository
|
||||
/// </summary>
|
||||
public interface IRepository<in TId, TEntity> : IReadRepository<TId, TEntity>
|
||||
public interface IWriteRepository<in TEntity> : IRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds or Updates an Entity
|
||||
@@ -58,4 +46,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <param name="entity"></param>
|
||||
void Delete(TEntity entity);
|
||||
}
|
||||
|
||||
public interface IRepository<in TId, TEntity> : IReadRepository<TId, TEntity>, IWriteRepository<TEntity>
|
||||
{ }
|
||||
}
|
||||
@@ -10,7 +10,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity">Type of <see cref="IAggregateRoot"/> entity for which the repository is used</typeparam>
|
||||
/// <typeparam name="TId">Type of the Id used for this entity</typeparam>
|
||||
public interface IRepositoryVersionable<TId, TEntity> : IRepositoryQueryable<TId, TEntity>
|
||||
public interface IRepositoryVersionable<TId, TEntity> : IQueryRepository<TId, TEntity>
|
||||
where TEntity : IAggregateRoot
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IServerRegistrationRepository : IRepositoryQueryable<int, IServerRegistration>
|
||||
public interface IServerRegistrationRepository : IQueryRepository<int, IServerRegistration>
|
||||
{
|
||||
void DeactiveStaleServers(TimeSpan staleTimeout);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface ITagRepository : IRepositoryQueryable<int, ITag>
|
||||
public interface ITagRepository : IQueryRepository<int, ITag>
|
||||
{
|
||||
|
||||
TaggedEntity GetTaggedEntityByKey(Guid key);
|
||||
|
||||
@@ -4,7 +4,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface ITaskRepository : IRepositoryQueryable<int, Task>
|
||||
public interface ITaskRepository : IQueryRepository<int, Task>
|
||||
{
|
||||
IEnumerable<Task> GetTasks(int? itemId = null, int? assignedUser = null, int? ownerUser = null, string taskTypeAlias = null, bool includeClosed = false);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface ITaskTypeRepository : IRepositoryQueryable<int, TaskType>
|
||||
public interface ITaskTypeRepository : IQueryRepository<int, TaskType>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface ITemplateRepository : IRepositoryQueryable<int, ITemplate>
|
||||
public interface ITemplateRepository : IQueryRepository<int, ITemplate>
|
||||
{
|
||||
ITemplate Get(string alias);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IUserRepository : IRepositoryQueryable<int, IUser>
|
||||
public interface IUserRepository : IQueryRepository<int, IUser>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the count of items based on a complex query
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IUserTypeRepository : IRepositoryQueryable<int, IUserType>
|
||||
public interface IUserTypeRepository : IQueryRepository<int, IUserType>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
private IRepositoryCachePolicy<ILanguage, int> _cachePolicy;
|
||||
|
||||
public LanguageRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public LanguageRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
internal class MacroRepository : NPocoRepositoryBase<int, IMacro>, IMacroRepository
|
||||
{
|
||||
|
||||
public MacroRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public MacroRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private readonly IMediaTypeRepository _mediaTypeRepository;
|
||||
private readonly ITagRepository _tagRepository;
|
||||
|
||||
public MediaRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IMediaTypeRepository mediaTypeRepository, ITagRepository tagRepository, IContentSection contentSection, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, contentSection, queryFactory)
|
||||
public MediaRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IMediaTypeRepository mediaTypeRepository, ITagRepository tagRepository, IContentSection contentSection)
|
||||
: base(work, cache, logger, contentSection)
|
||||
{
|
||||
if (mediaTypeRepository == null) throw new ArgumentNullException(nameof(mediaTypeRepository));
|
||||
if (tagRepository == null) throw new ArgumentNullException(nameof(tagRepository));
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
@@ -8,8 +7,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
class MediaTypeContainerRepository : EntityContainerRepository, IMediaTypeContainerRepository
|
||||
{
|
||||
public MediaTypeContainerRepository(IDatabaseUnitOfWork uow, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(uow, cache, logger, queryFactory, Constants.ObjectTypes.MediaTypeContainerGuid)
|
||||
public MediaTypeContainerRepository(IDatabaseUnitOfWork uow, CacheHelper cache, ILogger logger)
|
||||
: base(uow, cache, logger, Constants.ObjectTypes.MediaTypeContainerGuid)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -18,8 +18,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
private IRepositoryCachePolicy<IMediaType, int> _cachePolicy;
|
||||
|
||||
public MediaTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public MediaTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{ }
|
||||
|
||||
protected override IRepositoryCachePolicy<IMediaType, int> CachePolicy
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
internal class MemberGroupRepository : NPocoRepositoryBase<int, IMemberGroup>, IMemberGroupRepository
|
||||
{
|
||||
public MemberGroupRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public MemberGroupRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{ }
|
||||
|
||||
private readonly MemberGroupFactory _modelFactory = new MemberGroupFactory();
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private readonly ITagRepository _tagRepository;
|
||||
private readonly IMemberGroupRepository _memberGroupRepository;
|
||||
|
||||
public MemberRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IMemberTypeRepository memberTypeRepository, IMemberGroupRepository memberGroupRepository, ITagRepository tagRepository, IContentSection contentSection, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, contentSection, queryFactory)
|
||||
public MemberRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IMemberTypeRepository memberTypeRepository, IMemberGroupRepository memberGroupRepository, ITagRepository tagRepository, IContentSection contentSection)
|
||||
: base(work, cache, logger, contentSection)
|
||||
{
|
||||
if (memberTypeRepository == null) throw new ArgumentNullException(nameof(memberTypeRepository));
|
||||
if (tagRepository == null) throw new ArgumentNullException(nameof(tagRepository));
|
||||
|
||||
@@ -21,8 +21,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
private IRepositoryCachePolicy<IMemberType, int> _cachePolicy;
|
||||
|
||||
public MemberTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public MemberTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{ }
|
||||
|
||||
protected override IRepositoryCachePolicy<IMemberType, int> CachePolicy
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal class MigrationEntryRepository : NPocoRepositoryBase<int, IMigrationEntry>, IMigrationEntryRepository
|
||||
{
|
||||
public MigrationEntryRepository(IDatabaseUnitOfWork work, [Inject(RepositoryCompositionRoot.DisabledCache)] CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public MigrationEntryRepository(IDatabaseUnitOfWork work, [Inject(RepositoryCompositionRoot.DisabledCache)] CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -24,11 +24,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <param name="work">A database unit of work.</param>
|
||||
/// <param name="cache">A cache helper.</param>
|
||||
/// <param name="logger">A logger.</param>
|
||||
/// <param name="queryFactory">A query factory.</param>
|
||||
protected NPocoRepositoryBase(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
protected NPocoRepositoryBase(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
QueryFactory = queryFactory;
|
||||
QueryFactory = work.DatabaseContext.QueryFactory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -44,7 +43,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// <summary>
|
||||
/// Gets the repository's database sql syntax.
|
||||
/// </summary>
|
||||
public ISqlSyntaxProvider SqlSyntax => Database.SqlSyntax;
|
||||
public ISqlSyntaxProvider SqlSyntax => UnitOfWork.DatabaseContext.SqlSyntax;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the repository's query factory.
|
||||
@@ -61,10 +60,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// Creates a new Sql statement.
|
||||
/// </summary>
|
||||
/// <returns>A new Sql statement.</returns>
|
||||
protected Sql<SqlContext> Sql()
|
||||
{
|
||||
return Database.Sql();
|
||||
}
|
||||
protected Sql<SqlContext> Sql() => UnitOfWork.DatabaseContext.Sql();
|
||||
|
||||
#region Abstract Methods
|
||||
|
||||
@@ -103,7 +99,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual new TId GetEntityId(TEntity entity)
|
||||
protected new virtual TId GetEntityId(TEntity entity)
|
||||
{
|
||||
return (TId)(object) entity.Id;
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
private IRepositoryCachePolicy<PublicAccessEntry, Guid> _cachePolicy;
|
||||
|
||||
public PublicAccessRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public PublicAccessRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{ }
|
||||
|
||||
protected override IRepositoryCachePolicy<PublicAccessEntry, Guid> CachePolicy
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
where TEntity : class, IUmbracoEntity
|
||||
where TRepository : class, IRepository
|
||||
{
|
||||
protected RecycleBinRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IContentSection contentSection, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, contentSection, queryFactory)
|
||||
protected RecycleBinRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IContentSection contentSection)
|
||||
: base(work, cache, logger, contentSection)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal class RedirectUrlRepository : NPocoRepositoryBase<Guid, IRedirectUrl>, IRedirectUrlRepository
|
||||
{
|
||||
public RedirectUrlRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public RedirectUrlRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{ }
|
||||
|
||||
protected override int PerformCount(IQuery<IRedirectUrl> query)
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
private readonly IRelationTypeRepository _relationTypeRepository;
|
||||
|
||||
public RelationRepository(IDatabaseUnitOfWork work, [Inject(RepositoryCompositionRoot.DisabledCache)] CacheHelper cache, ILogger logger, IRelationTypeRepository relationTypeRepository, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public RelationRepository(IDatabaseUnitOfWork work, [Inject(RepositoryCompositionRoot.DisabledCache)] CacheHelper cache, ILogger logger, IRelationTypeRepository relationTypeRepository)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
_relationTypeRepository = relationTypeRepository;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
private IRepositoryCachePolicy<IRelationType, int> _cachePolicy;
|
||||
|
||||
public RelationTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public RelationTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{ }
|
||||
|
||||
protected override IRepositoryCachePolicy<IRelationType, int> CachePolicy
|
||||
|
||||
@@ -10,8 +10,13 @@ using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a base class to all repositories.
|
||||
/// </summary>
|
||||
internal abstract class RepositoryBase
|
||||
{
|
||||
private static readonly Dictionary<Type, string> CacheTypeKeys = new Dictionary<Type, string>();
|
||||
|
||||
protected RepositoryBase(IUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
{
|
||||
if (work == null) throw new ArgumentNullException(nameof(work));
|
||||
@@ -19,46 +24,42 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
if (logger == null) throw new ArgumentNullException(nameof(logger));
|
||||
Logger = logger;
|
||||
UnitOfWork = work;
|
||||
RepositoryCache = cache;
|
||||
Cache = cache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Unit of Work added to the repository
|
||||
/// </summary>
|
||||
protected internal IUnitOfWork UnitOfWork { get; }
|
||||
protected IUnitOfWork UnitOfWork { get; }
|
||||
|
||||
protected CacheHelper RepositoryCache { get; }
|
||||
protected CacheHelper Cache { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The runtime cache used for this repo - by standard this is the runtime cache exposed by the CacheHelper but can be overridden
|
||||
/// </summary>
|
||||
protected virtual IRuntimeCacheProvider RuntimeCache => RepositoryCache.RuntimeCache;
|
||||
protected virtual IRuntimeCacheProvider RuntimeCache => Cache.RuntimeCache;
|
||||
|
||||
public static string GetCacheIdKey<T>(object id)
|
||||
{
|
||||
return $"{GetCacheTypeKey<T>()}{id}";
|
||||
}
|
||||
protected ILogger Logger { get; }
|
||||
|
||||
public static string GetCacheIdKey<T>(object id) => GetCacheTypeKey<T>() + id;
|
||||
|
||||
public static string GetCacheTypeKey<T>()
|
||||
{
|
||||
return $"uRepo_{typeof (T).Name}_";
|
||||
string key;
|
||||
var type = typeof (T);
|
||||
return CacheTypeKeys.TryGetValue(type, out key) ? key : (CacheTypeKeys[type] = "uRepo_" + type.Name + "_");
|
||||
}
|
||||
|
||||
protected ILogger Logger { get; private set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represent an abstract Repository, which is the base of the Repository implementations
|
||||
/// Provides a base class to all repositories.
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity">Type of <see cref="IAggregateRoot"/> entity for which the repository is used</typeparam>
|
||||
/// <typeparam name="TId">Type of the Id used for this entity</typeparam>
|
||||
internal abstract class RepositoryBase<TId, TEntity> : RepositoryBase, IRepositoryQueryable<TId, TEntity>, IUnitOfWorkRepository
|
||||
/// <typeparam name="TEntity">The type of the entity managed by this repository.</typeparam>
|
||||
/// <typeparam name="TId">The type of the entity's unique identifier.</typeparam>
|
||||
internal abstract class RepositoryBase<TId, TEntity> : RepositoryBase, IReadRepository<TId, TEntity>, IWriteRepository<TEntity>, IQueryRepository<TId, TEntity>, IUnitOfWorkRepository
|
||||
where TEntity : class, IAggregateRoot
|
||||
{
|
||||
private IRepositoryCachePolicy<TEntity, TId> _cachePolicy;
|
||||
|
||||
protected RepositoryBase(IUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
protected override IRuntimeCacheProvider RuntimeCache => Cache.IsolatedRuntimeCache.GetOrCreateCache<TEntity>();
|
||||
|
||||
/// <summary>
|
||||
/// Used to create a new query instance
|
||||
@@ -79,37 +80,17 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected virtual TId GetEntityId(TEntity entity)
|
||||
{
|
||||
return (TId)(object)entity.Id;
|
||||
return (TId) (object) entity.Id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The runtime cache used for this repo by default is the isolated cache for this type
|
||||
/// </summary>
|
||||
protected override IRuntimeCacheProvider RuntimeCache => RepositoryCache.IsolatedRuntimeCache.GetOrCreateCache<TEntity>();
|
||||
|
||||
private IRepositoryCachePolicy<TEntity, TId> _cachePolicy;
|
||||
|
||||
protected virtual IRepositoryCachePolicy<TEntity, TId> CachePolicy
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_cachePolicy != null) return _cachePolicy;
|
||||
|
||||
var options = new RepositoryCachePolicyOptions(() =>
|
||||
{
|
||||
//create it once if it is needed (no need for locking here)
|
||||
if (_hasIdQuery == null)
|
||||
{
|
||||
_hasIdQuery = Query.Where(x => x.Id != 0);
|
||||
}
|
||||
|
||||
//Get count of all entities of current type (TEntity) to ensure cached result is correct
|
||||
return PerformCount(_hasIdQuery);
|
||||
});
|
||||
|
||||
_cachePolicy = new DefaultRepositoryCachePolicy<TEntity, TId>(RuntimeCache, options);
|
||||
|
||||
return _cachePolicy;
|
||||
if (_hasIdQuery == null) _hasIdQuery = Query.Where(x => x.Id != 0);
|
||||
var options = new RepositoryCachePolicyOptions(() => PerformCount(_hasIdQuery));
|
||||
return _cachePolicy = new DefaultRepositoryCachePolicy<TEntity, TId>(RuntimeCache, options);
|
||||
}
|
||||
set
|
||||
{
|
||||
@@ -125,14 +106,10 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public void AddOrUpdate(TEntity entity)
|
||||
{
|
||||
if (entity.HasIdentity == false)
|
||||
{
|
||||
UnitOfWork.RegisterCreated(entity, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnitOfWork.RegisterUpdated(entity, this);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the passed in entity
|
||||
@@ -178,6 +155,12 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
}
|
||||
|
||||
protected abstract IEnumerable<TEntity> PerformGetByQuery(IQuery<TEntity> query);
|
||||
protected abstract bool PerformExists(TId id);
|
||||
protected abstract int PerformCount(IQuery<TEntity> query);
|
||||
protected abstract void PersistNewItem(TEntity item);
|
||||
protected abstract void PersistUpdatedItem(TEntity item);
|
||||
protected abstract void PersistDeletedItem(TEntity item);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of entities by the passed in query
|
||||
/// </summary>
|
||||
@@ -190,7 +173,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
.WhereNotNull();
|
||||
}
|
||||
|
||||
protected abstract bool PerformExists(TId id);
|
||||
/// <summary>
|
||||
/// Returns a boolean indicating whether an entity with the passed Id exists
|
||||
/// </summary>
|
||||
@@ -201,7 +183,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return CachePolicy.Exists(id, PerformExists, PerformGetAll);
|
||||
}
|
||||
|
||||
protected abstract int PerformCount(IQuery<TEntity> query);
|
||||
/// <summary>
|
||||
/// Returns an integer with the count of entities found with the passed in query
|
||||
/// </summary>
|
||||
@@ -238,9 +219,5 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
CachePolicy.Delete((TEntity) entity, PersistDeletedItem);
|
||||
}
|
||||
|
||||
protected abstract void PersistNewItem(TEntity item);
|
||||
protected abstract void PersistUpdatedItem(TEntity item);
|
||||
protected abstract void PersistDeletedItem(TEntity item);
|
||||
}
|
||||
}
|
||||
@@ -16,8 +16,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
private IRepositoryCachePolicy<IServerRegistration, int> _cachePolicy;
|
||||
|
||||
public ServerRegistrationRepository(IDatabaseUnitOfWork work, CacheHelper cacheHelper, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, CacheHelper.CreateDisabledCacheHelper(), logger, queryFactory)
|
||||
public ServerRegistrationRepository(IDatabaseUnitOfWork work, CacheHelper cacheHelper, ILogger logger)
|
||||
: base(work, CacheHelper.CreateDisabledCacheHelper(), logger)
|
||||
{ }
|
||||
|
||||
protected override IRepositoryCachePolicy<IServerRegistration, int> CachePolicy => _cachePolicy
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
where TDto: class
|
||||
{
|
||||
|
||||
protected SimpleGetRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
protected SimpleGetRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal class TagRepository : NPocoRepositoryBase<int, ITag>, ITagRepository
|
||||
{
|
||||
public TagRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public TagRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal class TaskRepository : NPocoRepositoryBase<int, Task>, ITaskRepository
|
||||
{
|
||||
public TaskRepository(IDatabaseUnitOfWork work, [Inject(RepositoryCompositionRoot.DisabledCache)] CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public TaskRepository(IDatabaseUnitOfWork work, [Inject(RepositoryCompositionRoot.DisabledCache)] CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
internal class TaskTypeRepository : NPocoRepositoryBase<int, TaskType>, ITaskTypeRepository
|
||||
{
|
||||
public TaskTypeRepository(IDatabaseUnitOfWork work, [Inject(RepositoryCompositionRoot.DisabledCache)] CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public TaskTypeRepository(IDatabaseUnitOfWork work, [Inject(RepositoryCompositionRoot.DisabledCache)] CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -37,8 +37,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private readonly MasterPageHelper _masterPageHelper;
|
||||
private IRepositoryCachePolicy<ITemplate, int> _cachePolicy;
|
||||
|
||||
public TemplateRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IFileSystem masterpageFileSystem, IFileSystem viewFileSystem, ITemplatesSection templateConfig, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public TemplateRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IFileSystem masterpageFileSystem, IFileSystem viewFileSystem, ITemplatesSection templateConfig)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
_masterpagesFileSystem = masterpageFileSystem;
|
||||
_viewsFileSystem = viewFileSystem;
|
||||
|
||||
@@ -28,8 +28,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private readonly CacheHelper _cacheHelper;
|
||||
private PermissionRepository<IContent> _permissionRepository;
|
||||
|
||||
public UserRepository(IDatabaseUnitOfWork work, CacheHelper cacheHelper, ILogger logger, IUserTypeRepository userTypeRepository, IQueryFactory queryFactory)
|
||||
: base(work, cacheHelper, logger, queryFactory)
|
||||
public UserRepository(IDatabaseUnitOfWork work, CacheHelper cacheHelper, ILogger logger, IUserTypeRepository userTypeRepository)
|
||||
: base(work, cacheHelper, logger)
|
||||
{
|
||||
_userTypeRepository = userTypeRepository;
|
||||
_cacheHelper = cacheHelper;
|
||||
|
||||
@@ -8,9 +8,7 @@ using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
|
||||
using Umbraco.Core.Persistence.Factories;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
@@ -20,8 +18,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </summary>
|
||||
internal class UserTypeRepository : NPocoRepositoryBase<int, IUserType>, IUserTypeRepository
|
||||
{
|
||||
public UserTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
public UserTypeRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -50,8 +50,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
//private readonly IContentSection _contentSection;
|
||||
|
||||
protected VersionableRepositoryBase(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IContentSection contentSection, IQueryFactory queryFactory)
|
||||
: base(work, cache, logger, queryFactory)
|
||||
protected VersionableRepositoryBase(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, IContentSection contentSection)
|
||||
: base(work, cache, logger)
|
||||
{
|
||||
//_contentSection = contentSection;
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Umbraco.Core.Persistence
|
||||
private const IsolationLevel DefaultIsolationLevel = IsolationLevel.RepeatableRead;
|
||||
|
||||
private readonly ILogger _logger;
|
||||
private readonly SqlContext _sqlContext;
|
||||
private readonly RetryPolicy _connectionRetryPolicy;
|
||||
private readonly RetryPolicy _commandRetryPolicy;
|
||||
private bool _enableCount;
|
||||
@@ -35,7 +36,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// </summary>
|
||||
internal Guid InstanceId { get; } = Guid.NewGuid();
|
||||
|
||||
public ISqlSyntaxProvider SqlSyntax { get; }
|
||||
public ISqlSyntaxProvider SqlSyntax => _sqlContext.SqlSyntax;
|
||||
|
||||
/// <summary>
|
||||
/// Generally used for testing, will output all SQL statements executed to the logger
|
||||
@@ -68,38 +69,40 @@ namespace Umbraco.Core.Persistence
|
||||
// creates one instance per request
|
||||
// also used by DatabaseContext for creating DBs and upgrading
|
||||
public UmbracoDatabase(string connectionString,
|
||||
ISqlSyntaxProvider sqlSyntax, DatabaseType databaseType, DbProviderFactory provider,
|
||||
ILogger logger,
|
||||
SqlContext sqlContext, DbProviderFactory provider, ILogger logger,
|
||||
RetryPolicy connectionRetryPolicy = null, RetryPolicy commandRetryPolicy = null)
|
||||
: base(connectionString, databaseType, provider, DefaultIsolationLevel)
|
||||
: base(connectionString, sqlContext.DatabaseType, provider, DefaultIsolationLevel)
|
||||
{
|
||||
SqlSyntax = sqlSyntax;
|
||||
_sqlContext = sqlContext;
|
||||
|
||||
_logger = logger;
|
||||
_connectionRetryPolicy = connectionRetryPolicy;
|
||||
_commandRetryPolicy = commandRetryPolicy;
|
||||
|
||||
EnableSqlTrace = false;
|
||||
}
|
||||
|
||||
// INTERNAL FOR UNIT TESTS
|
||||
internal UmbracoDatabase(DbConnection connection,
|
||||
ISqlSyntaxProvider sqlSyntax, DatabaseType databaseType,
|
||||
ILogger logger)
|
||||
ISqlSyntaxProvider sqlSyntax, DatabaseType databaseType, ILogger logger)
|
||||
: base(connection, databaseType, DefaultIsolationLevel)
|
||||
{
|
||||
SqlSyntax = sqlSyntax;
|
||||
_sqlContext = new SqlContext(sqlSyntax, null, databaseType); // beware! no pocoDataFactory!
|
||||
|
||||
_logger = logger;
|
||||
|
||||
EnableSqlTrace = false;
|
||||
}
|
||||
|
||||
// fixme: these two could be an extension method of IUmbracoDatabaseConfig
|
||||
public Sql<SqlContext> Sql()
|
||||
{
|
||||
return NPoco.Sql.BuilderFor(new SqlContext(this));
|
||||
return NPoco.Sql.BuilderFor(_sqlContext);
|
||||
}
|
||||
|
||||
public Sql<SqlContext> Sql(string sql, params object[] args)
|
||||
{
|
||||
return NPoco.Sql.BuilderFor(new SqlContext(this)).Append(sql, args);
|
||||
return Sql().Append(sql, args);
|
||||
}
|
||||
|
||||
//protected override void OnConnectionClosing(DbConnection conn)
|
||||
@@ -159,5 +162,7 @@ namespace Umbraco.Core.Persistence
|
||||
}
|
||||
base.OnExecutedCommand(cmd);
|
||||
}
|
||||
|
||||
// fixme - see v7.6 - what about disposing & managing context and call context?
|
||||
}
|
||||
}
|
||||
@@ -11,10 +11,10 @@
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NPocoUnitOfWork"/> class with a a repository factory.
|
||||
/// </summary>
|
||||
/// <param name="factory">A repository factory.</param>
|
||||
/// <param name="repositoryFactory">A repository factory.</param>
|
||||
/// <remarks>This should be used by the FileUnitOfWorkProvider exclusively.</remarks>
|
||||
public FileUnitOfWork(RepositoryFactory factory)
|
||||
: base(factory)
|
||||
public FileUnitOfWork(RepositoryFactory repositoryFactory)
|
||||
: base(repositoryFactory)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
@@ -25,7 +25,7 @@
|
||||
/// <returns>The created repository for the unit of work.</returns>
|
||||
public override TRepository CreateRepository<TRepository>(string name = null)
|
||||
{
|
||||
return Factory.CreateRepository<TRepository>(this, name);
|
||||
return RepositoryFactory.CreateRepository<TRepository>(this, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,9 +5,26 @@ namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
/// </summary>
|
||||
public interface IDatabaseUnitOfWork : IUnitOfWork
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the database context.
|
||||
/// </summary>
|
||||
DatabaseContext DatabaseContext { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current database instance.
|
||||
/// </summary>
|
||||
UmbracoDatabase Database { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Read-locks some lock objects.
|
||||
/// </summary>
|
||||
/// <param name="lockIds">The lock object identifiers.</param>
|
||||
void ReadLock(params int[] lockIds);
|
||||
|
||||
/// <summary>
|
||||
/// Write-locks some lock objects.
|
||||
/// </summary>
|
||||
/// <param name="lockIds">The lock object identifiers.</param>
|
||||
void WriteLock(params int[] lockIds);
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,11 @@ namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
/// </summary>
|
||||
public interface IDatabaseUnitOfWorkProvider
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the database context.
|
||||
/// </summary>
|
||||
DatabaseContext DatabaseContext { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a unit of work.
|
||||
/// </summary>
|
||||
|
||||
@@ -14,36 +14,30 @@ namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="NPocoUnitOfWork"/> class with a database and a repository factory.
|
||||
/// </summary>
|
||||
/// <param name="databaseContext">The database context.</param>
|
||||
/// <param name="database">A database.</param>
|
||||
/// <param name="factory">A repository factory.</param>
|
||||
/// <param name="repositoryFactory">A repository factory.</param>
|
||||
/// <remarks>This should be used by the NPocoUnitOfWorkProvider exclusively.</remarks>
|
||||
internal NPocoUnitOfWork(UmbracoDatabase database, RepositoryFactory factory)
|
||||
: base(factory)
|
||||
internal NPocoUnitOfWork(DatabaseContext databaseContext, UmbracoDatabase database, RepositoryFactory repositoryFactory)
|
||||
: base(repositoryFactory)
|
||||
{
|
||||
DatabaseContext = databaseContext;
|
||||
Database = database;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unit of work underlying database.
|
||||
/// </summary>
|
||||
public UmbracoDatabase Database { get; }
|
||||
/// <inheritdoc />
|
||||
public DatabaseContext DatabaseContext { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a repository.
|
||||
/// </summary>
|
||||
/// <typeparam name="TRepository">The type of the repository.</typeparam>
|
||||
/// <param name="name">The optional name of the repository.</param>
|
||||
/// <returns>The created repository for the unit of work.</returns>
|
||||
/// <inheritdoc />
|
||||
public UmbracoDatabase Database { get; } // => DatabaseContext.Database; // fixme + change ctor
|
||||
|
||||
/// <inheritdoc />
|
||||
public override TRepository CreateRepository<TRepository>(string name = null)
|
||||
{
|
||||
return Factory.CreateRepository<TRepository>(this, name);
|
||||
return RepositoryFactory.CreateRepository<TRepository>(this, name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that we have a transaction.
|
||||
/// </summary>
|
||||
/// <remarks>Isolation level is determined by the database, see UmbracoDatabase.DefaultIsolationLevel. Should be
|
||||
/// at least IsolationLevel.RepeatablRead else the node locks will not work correctly.</remarks>
|
||||
/// <inheritdoc />
|
||||
public override void Begin()
|
||||
{
|
||||
base.Begin();
|
||||
@@ -52,6 +46,39 @@ namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
_transaction = Database.GetTransaction();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void ReadLock(params int[] lockIds)
|
||||
{
|
||||
Begin(); // we need a transaction
|
||||
|
||||
if (Database.Transaction.IsolationLevel < IsolationLevel.RepeatableRead)
|
||||
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
|
||||
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
|
||||
foreach (var lockId in lockIds)
|
||||
{
|
||||
var i = Database.ExecuteScalar<int?>("SELECT value FROM umbracoLock WHERE id=@id", new { id = lockId });
|
||||
if (i == null) // ensure we are actually locking!
|
||||
throw new Exception($"LockObject with id={lockId} does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void WriteLock(params int[] lockIds)
|
||||
{
|
||||
Begin(); // we need a transaction
|
||||
|
||||
if (Database.Transaction.IsolationLevel < IsolationLevel.RepeatableRead)
|
||||
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
|
||||
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
|
||||
foreach (var lockId in lockIds)
|
||||
{
|
||||
var i = Database.Execute("UPDATE umbracoLock SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id", new { id = lockId });
|
||||
if (i == 0) // ensure we are actually locking!
|
||||
throw new Exception($"LockObject with id={lockId} does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
base.DisposeResources();
|
||||
@@ -69,37 +96,5 @@ namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
|
||||
_transaction = null;
|
||||
}
|
||||
|
||||
public void ReadLock(params int[] lockIds)
|
||||
{
|
||||
Begin(); // we need a transaction
|
||||
|
||||
if (Database.Transaction.IsolationLevel < IsolationLevel.RepeatableRead)
|
||||
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
|
||||
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
|
||||
foreach (var lockId in lockIds)
|
||||
{
|
||||
var i = Database.ExecuteScalar<int?>("SELECT value FROM umbracoLock WHERE id=@id",
|
||||
new { @id = lockId });
|
||||
if (i == null) // ensure we are actually locking!
|
||||
throw new Exception($"LockObject with id={lockId} does not exist.");
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteLock(params int[] lockIds)
|
||||
{
|
||||
Begin(); // we need a transaction
|
||||
|
||||
if (Database.Transaction.IsolationLevel < IsolationLevel.RepeatableRead)
|
||||
throw new InvalidOperationException("A transaction with minimum RepeatableRead isolation level is required.");
|
||||
// *not* using a unique 'WHERE IN' query here because the *order* of lockIds is important to avoid deadlocks
|
||||
foreach (var lockId in lockIds)
|
||||
{
|
||||
var i = Database.Execute("UPDATE umbracoLock SET value = (CASE WHEN (value=1) THEN -1 ELSE 1 END) WHERE id=@id",
|
||||
new { @id = lockId });
|
||||
if (i == 0) // ensure we are actually locking!
|
||||
throw new Exception($"LockObject with id={lockId} does not exist.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.DI;
|
||||
|
||||
namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
{
|
||||
@@ -28,35 +23,18 @@ namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
_repositoryFactory = repositoryFactory;
|
||||
}
|
||||
|
||||
// this should NOT be here, all tests should supply the appropriate providers,
|
||||
// however the above ctor is used in hundreds of tests at the moment, so...
|
||||
// will refactor later
|
||||
private static IEnumerable<ISqlSyntaxProvider> GetDefaultSqlSyntaxProviders(ILogger logger)
|
||||
{
|
||||
return new ISqlSyntaxProvider[]
|
||||
{
|
||||
new MySqlSyntaxProvider(logger),
|
||||
new SqlCeSyntaxProvider(),
|
||||
new SqlServerSyntaxProvider(new Lazy<IDatabaseFactory>(() => null))
|
||||
};
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public DatabaseContext DatabaseContext => Current.DatabaseContext; // fixme inject!
|
||||
|
||||
#region Implement IUnitOfWorkProvider
|
||||
|
||||
/// <summary>
|
||||
/// Creates a unit of work around a database obtained from the database factory.
|
||||
/// </summary>
|
||||
/// <returns>A unit of work.</returns>
|
||||
/// <remarks>The unit of work will execute on the database returned by the database factory.</remarks>
|
||||
/// <inheritdoc />
|
||||
public IDatabaseUnitOfWork CreateUnitOfWork()
|
||||
{
|
||||
// get a database from the factory - might be the "ambient" database eg
|
||||
// the one that's enlisted with the HttpContext - so it's not always a
|
||||
// the one that's enlisted with the HttpContext - so it's *not* necessary a
|
||||
// "new" database.
|
||||
var database = _databaseFactory.GetDatabase();
|
||||
return new NPocoUnitOfWork(database, _repositoryFactory);
|
||||
var databaseContext = Current.DatabaseContext; // fixme - inject!
|
||||
return new NPocoUnitOfWork(databaseContext, database, _repositoryFactory);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -9,12 +9,12 @@ namespace Umbraco.Core.Persistence.UnitOfWork
|
||||
{
|
||||
private readonly Queue<Operation> _operations = new Queue<Operation>();
|
||||
|
||||
protected UnitOfWorkBase(RepositoryFactory factory)
|
||||
protected UnitOfWorkBase(RepositoryFactory repositoryFactory)
|
||||
{
|
||||
Factory = factory;
|
||||
RepositoryFactory = repositoryFactory;
|
||||
}
|
||||
|
||||
protected RepositoryFactory Factory { get; }
|
||||
protected RepositoryFactory RepositoryFactory { get; }
|
||||
|
||||
public abstract TRepository CreateRepository<TRepository>(string name = null)
|
||||
where TRepository : IRepository;
|
||||
|
||||
@@ -21,6 +21,7 @@ namespace Umbraco.Core.Services
|
||||
public class ContentService : RepositoryService, IContentService, IContentServiceOperations
|
||||
{
|
||||
private readonly MediaFileSystem _mediaFileSystem;
|
||||
private IQuery<IContent> _queryNotTrashed;
|
||||
|
||||
#region Constructors
|
||||
|
||||
@@ -28,19 +29,19 @@ namespace Umbraco.Core.Services
|
||||
IDatabaseUnitOfWorkProvider provider,
|
||||
ILogger logger,
|
||||
IEventMessagesFactory eventMessagesFactory,
|
||||
IQueryFactory queryFactory,
|
||||
MediaFileSystem mediaFileSystem)
|
||||
: base(provider, logger, eventMessagesFactory)
|
||||
{
|
||||
_mediaFileSystem = mediaFileSystem;
|
||||
_notTrashedQuery = queryFactory.Create<IContent>().Where(x => x.Trashed == false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Static Queries
|
||||
#region Static queries
|
||||
|
||||
private readonly IQuery<IContent> _notTrashedQuery;
|
||||
// lazy-constructed because when the ctor runs, the query factory may not be ready
|
||||
|
||||
private IQuery<IContent> QueryNotTrashed => _queryNotTrashed ?? (_queryNotTrashed = UowProvider.DatabaseContext.Query<IContent>().Where(x => x.Trashed == false));
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -834,7 +835,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
uow.ReadLock(Constants.Locks.ContentTree);
|
||||
var repository = uow.CreateRepository<IContentRepository>();
|
||||
var content = repository.GetByPublishedVersion(_notTrashedQuery);
|
||||
var content = repository.GetByPublishedVersion(QueryNotTrashed);
|
||||
uow.Complete();
|
||||
return content;
|
||||
}
|
||||
|
||||
@@ -20,18 +20,17 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
private readonly IRuntimeCacheProvider _runtimeCache;
|
||||
private readonly Dictionary<string, Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>> _supportedObjectTypes;
|
||||
private IQuery<IUmbracoEntity> _queryRootEntity;
|
||||
|
||||
public EntityService(IDatabaseUnitOfWorkProvider provider, ILogger logger, IEventMessagesFactory eventMessagesFactory,
|
||||
IContentService contentService, IContentTypeService contentTypeService,
|
||||
IMediaService mediaService, IMediaTypeService mediaTypeService,
|
||||
IDataTypeService dataTypeService,
|
||||
IMemberService memberService, IMemberTypeService memberTypeService,
|
||||
IQueryFactory queryFactory,
|
||||
IRuntimeCacheProvider runtimeCache)
|
||||
: base(provider, logger, eventMessagesFactory)
|
||||
{
|
||||
_runtimeCache = runtimeCache;
|
||||
_rootEntityQuery = queryFactory.Create<IUmbracoEntity>().Where(x => x.ParentId == -1);
|
||||
|
||||
_supportedObjectTypes = new Dictionary<string, Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>>
|
||||
{
|
||||
@@ -69,7 +68,9 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#region Static Queries
|
||||
|
||||
private readonly IQuery<IUmbracoEntity> _rootEntityQuery;
|
||||
// lazy-constructed because when the ctor runs, the query factory may not be ready
|
||||
|
||||
private IQuery<IUmbracoEntity> QueryRootEntity => _queryRootEntity ?? (_queryRootEntity = UowProvider.DatabaseContext.Query<IUmbracoEntity>().Where(x => x.ParentId == -1));
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -98,7 +99,7 @@ namespace Umbraco.Core.Services
|
||||
case UmbracoObjectTypes.DataType:
|
||||
case UmbracoObjectTypes.DocumentTypeContainer:
|
||||
id = uow.Database.ExecuteScalar<int?>(
|
||||
uow.Database.Sql()
|
||||
uow.DatabaseContext.Sql()
|
||||
.Select("id")
|
||||
.From<NodeDto>()
|
||||
.Where<NodeDto>(dto => dto.UniqueId == key));
|
||||
@@ -144,7 +145,7 @@ namespace Umbraco.Core.Services
|
||||
case UmbracoObjectTypes.Member:
|
||||
case UmbracoObjectTypes.DataType:
|
||||
guid = uow.Database.ExecuteScalar<Guid?>(
|
||||
uow.Database.Sql()
|
||||
uow.DatabaseContext.Sql()
|
||||
.Select("uniqueID")
|
||||
.From<NodeDto>()
|
||||
.Where<NodeDto>(dto => dto.NodeId == id));
|
||||
@@ -442,7 +443,7 @@ namespace Umbraco.Core.Services
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var repository = uow.CreateRepository<IEntityRepository>();
|
||||
var entities = repository.GetByQuery(_rootEntityQuery, objectTypeId);
|
||||
var entities = repository.GetByQuery(QueryRootEntity, objectTypeId);
|
||||
uow.Complete();
|
||||
return entities;
|
||||
}
|
||||
@@ -547,7 +548,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var sql = uow.Database.Sql()
|
||||
var sql = uow.DatabaseContext.Sql()
|
||||
.Select("nodeObjectType")
|
||||
.From<NodeDto>()
|
||||
.Where<NodeDto>(x => x.NodeId == id);
|
||||
@@ -568,7 +569,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var uow = UowProvider.CreateUnitOfWork())
|
||||
{
|
||||
var sql = uow.Database.Sql()
|
||||
var sql = uow.DatabaseContext.Sql()
|
||||
.Select("nodeObjectType")
|
||||
.From<NodeDto>()
|
||||
.Where<NodeDto>(x => x.UniqueId == key);
|
||||
|
||||
@@ -6,7 +6,6 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using LightInject;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NPoco;
|
||||
@@ -40,7 +39,7 @@ namespace Umbraco.Core.Sync
|
||||
private bool _syncing;
|
||||
private bool _released;
|
||||
|
||||
protected DatabaseServerMessengerOptions Options { get; private set; }
|
||||
protected DatabaseServerMessengerOptions Options { get; }
|
||||
|
||||
public DatabaseServerMessenger(
|
||||
IRuntimeState runtime, DatabaseContext dbContext, ILogger logger, ProfilingLogger proflog,
|
||||
|
||||
@@ -223,6 +223,7 @@
|
||||
<Compile Include="Constants-Icons.cs" />
|
||||
<Compile Include="CoreRuntime.cs" />
|
||||
<Compile Include="CoreRuntimeComponent.cs" />
|
||||
<Compile Include="DatabaseBuilder.cs" />
|
||||
<Compile Include="DI\Current.cs" />
|
||||
<Compile Include="DatabaseContext.cs" />
|
||||
<Compile Include="DataTableExtensions.cs" />
|
||||
@@ -293,6 +294,7 @@
|
||||
<Compile Include="Models\PublishedContent\NoopPublishedContentModelFactory.cs" />
|
||||
<Compile Include="Models\PublishedContent\PropertyResult.cs" />
|
||||
<Compile Include="Models\PublishedContent\PropertyResultType.cs" />
|
||||
<Compile Include="Models\Rdbms\ContentNuDto.cs" />
|
||||
<Compile Include="Persistence\IUmbracoDatabaseAccessor.cs" />
|
||||
<Compile Include="Persistence\Mappers\IMapperCollection.cs" />
|
||||
<Compile Include="Persistence\Mappers\MapperCollection.cs" />
|
||||
@@ -451,8 +453,8 @@
|
||||
<Compile Include="Persistence\Repositories\EntityContainerRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\DomainRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\ExternalLoginRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\DataTypeContainerRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\DocumentTypeContainerRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\DataTypeContainerRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\DocumentTypeContainerRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IDataTypeContainerRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IDocumentTypeContainerRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IEntityContainerRepository.cs" />
|
||||
@@ -470,7 +472,7 @@
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IXsltFileRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\ITaskRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\ITaskTypeRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\MediaTypeContainerRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\MediaTypeContainerRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\MigrationEntryRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\PublicAccessRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\RedirectUrlRepository.cs" />
|
||||
@@ -1017,7 +1019,7 @@
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IMemberTypeRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IRelationRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IRelationTypeRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IRepositoryQueryable.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IQueryRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IRepositoryVersionable.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IScriptRepository.cs" />
|
||||
<Compile Include="Persistence\Repositories\Interfaces\IRepository.cs" />
|
||||
|
||||
@@ -55,20 +55,19 @@ namespace Umbraco.Tests.Benchmarks
|
||||
new [] { p },
|
||||
logger,
|
||||
new ThreadStaticUmbracoDatabaseAccessor(),
|
||||
new QueryFactory(p, new MapperCollection(Enumerable.Empty<BaseMapper>())));
|
||||
new MapperCollection(Enumerable.Empty<BaseMapper>()));
|
||||
return f.GetDatabase();
|
||||
}
|
||||
|
||||
private UmbracoDatabase GetSqlCeDatabase(string cstr, ILogger logger)
|
||||
{
|
||||
var p = new SqlCeSyntaxProvider();
|
||||
var f = new DefaultDatabaseFactory(
|
||||
cstr,
|
||||
Constants.DatabaseProviders.SqlCe,
|
||||
new[] { p },
|
||||
new[] { new SqlCeSyntaxProvider() },
|
||||
logger,
|
||||
new ThreadStaticUmbracoDatabaseAccessor(),
|
||||
new QueryFactory(p, new MapperCollection(Enumerable.Empty<BaseMapper>())));
|
||||
new MapperCollection(Enumerable.Empty<BaseMapper>()));
|
||||
return f.GetDatabase();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,8 @@ namespace Umbraco.Tests.Migrations
|
||||
_sqlSyntax = new SqlCeSyntaxProvider();
|
||||
|
||||
var dbProviderFactory = DbProviderFactories.GetFactory(Constants.DbProviderNames.SqlServer);
|
||||
_database = new UmbracoDatabase("cstr", _sqlSyntax, DatabaseType.SqlServer2008, dbProviderFactory, _logger);
|
||||
var sqlContext = new SqlContext(_sqlSyntax, Mock.Of<IPocoDataFactory>(), DatabaseType.SqlServer2008);
|
||||
_database = new UmbracoDatabase("cstr", sqlContext, dbProviderFactory, _logger);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace Umbraco.Tests.Migrations
|
||||
_sqlSyntax = new SqlCeSyntaxProvider();
|
||||
|
||||
var dbProviderFactory = DbProviderFactories.GetFactory(Constants.DbProviderNames.SqlCe);
|
||||
_database = new UmbracoDatabase("cstr", _sqlSyntax, DatabaseType.SQLCe, dbProviderFactory, _logger);
|
||||
var sqlContext = new SqlContext(_sqlSyntax, Mock.Of<IPocoDataFactory>(), DatabaseType.SQLCe);
|
||||
_database = new UmbracoDatabase("cstr", sqlContext, dbProviderFactory, _logger);
|
||||
_migrationContext = new MigrationContext(_database, _logger);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,10 +24,9 @@ namespace Umbraco.Tests.Migrations.Upgrades
|
||||
|
||||
public override UmbracoDatabase GetConfiguredDatabase()
|
||||
{
|
||||
var databaseType = DatabaseType.MySQL;
|
||||
var sqlSyntax = new MySqlSyntaxProvider(Mock.Of<ILogger>());
|
||||
var dbProviderFactory = DbProviderFactories.GetFactory(Constants.DbProviderNames.MySql);
|
||||
return new UmbracoDatabase("Server = 169.254.120.3; Database = upgradetest; Uid = umbraco; Pwd = umbraco", sqlSyntax, databaseType, dbProviderFactory, Mock.Of<ILogger>());
|
||||
var sqlContext = new SqlContext(new MySqlSyntaxProvider(Mock.Of<ILogger>()), Mock.Of<IPocoDataFactory>(), DatabaseType.MySQL);
|
||||
return new UmbracoDatabase("Server = 169.254.120.3; Database = upgradetest; Uid = umbraco; Pwd = umbraco", sqlContext, dbProviderFactory, Mock.Of<ILogger>());
|
||||
}
|
||||
|
||||
public override string GetDatabaseSpecificSqlScript()
|
||||
|
||||
@@ -65,10 +65,9 @@ namespace Umbraco.Tests.Migrations.Upgrades
|
||||
|
||||
public override UmbracoDatabase GetConfiguredDatabase()
|
||||
{
|
||||
var databaseType = DatabaseType.SQLCe;
|
||||
var sqlSyntax = new SqlCeSyntaxProvider();
|
||||
var dbProviderFactory = DbProviderFactories.GetFactory(Constants.DbProviderNames.SqlCe);
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoNPocoTests.sdf;Flush Interval=1;", sqlSyntax, databaseType, dbProviderFactory, Mock.Of<ILogger>());
|
||||
var sqlContext = new SqlContext(new SqlCeSyntaxProvider(), Mock.Of<IPocoDataFactory>(), DatabaseType.SQLCe);
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoNPocoTests.sdf;Flush Interval=1;", sqlContext, dbProviderFactory, Mock.Of<ILogger>());
|
||||
}
|
||||
|
||||
public override string GetDatabaseSpecificSqlScript()
|
||||
|
||||
@@ -65,10 +65,9 @@ namespace Umbraco.Tests.Migrations.Upgrades
|
||||
|
||||
public override UmbracoDatabase GetConfiguredDatabase()
|
||||
{
|
||||
var databaseType = DatabaseType.SQLCe;
|
||||
var sqlSyntax = new SqlCeSyntaxProvider();
|
||||
var dbProviderFactory = DbProviderFactories.GetFactory(Constants.DbProviderNames.SqlCe);
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoNPocoTests.sdf;Flush Interval=1;", sqlSyntax, databaseType, dbProviderFactory, Mock.Of<ILogger>());
|
||||
var sqlContext = new SqlContext(new SqlCeSyntaxProvider(), Mock.Of<IPocoDataFactory>(), DatabaseType.SQLCe);
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoNPocoTests.sdf;Flush Interval=1;", sqlContext, dbProviderFactory, Mock.Of<ILogger>());
|
||||
}
|
||||
|
||||
public override string GetDatabaseSpecificSqlScript()
|
||||
|
||||
@@ -23,10 +23,9 @@ namespace Umbraco.Tests.Migrations.Upgrades
|
||||
|
||||
public override UmbracoDatabase GetConfiguredDatabase()
|
||||
{
|
||||
var databaseType = DatabaseType.SqlServer2008;
|
||||
var sqlSyntax = new SqlServerSyntaxProvider(new Lazy<IDatabaseFactory>(() => null));
|
||||
var dbProviderFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");
|
||||
return new UmbracoDatabase(@"server=.\SQLEXPRESS;database=EmptyForTest;user id=umbraco;password=umbraco", sqlSyntax, databaseType, dbProviderFactory, Mock.Of<ILogger>());
|
||||
var sqlContext = new SqlContext(new SqlServerSyntaxProvider(new Lazy<IDatabaseFactory>(() => null)), Mock.Of<IPocoDataFactory>(), DatabaseType.SqlServer2008);
|
||||
return new UmbracoDatabase(@"server=.\SQLEXPRESS;database=EmptyForTest;user id=umbraco;password=umbraco", sqlContext, dbProviderFactory, Mock.Of<ILogger>());
|
||||
}
|
||||
|
||||
public override string GetDatabaseSpecificSqlScript()
|
||||
|
||||
@@ -99,9 +99,9 @@ namespace Umbraco.Tests.Migrations.Upgrades
|
||||
|
||||
public UmbracoDatabase GetConfiguredDatabase()
|
||||
{
|
||||
var databaseType = DatabaseType.SQLCe;
|
||||
var dbProviderFactory = DbProviderFactories.GetFactory(Constants.DbProviderNames.SqlCe);
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoNPocoTests.sdf;Flush Interval=1;", new SqlCeSyntaxProvider(), databaseType, dbProviderFactory, Mock.Of<ILogger>());
|
||||
var sqlContext = new SqlContext(new SqlCeSyntaxProvider(), Mock.Of<IPocoDataFactory>(), DatabaseType.SQLCe);
|
||||
return new UmbracoDatabase("Datasource=|DataDirectory|UmbracoNPocoTests.sdf;Flush Interval=1;", sqlContext, dbProviderFactory, Mock.Of<ILogger>());
|
||||
}
|
||||
|
||||
public string GetDatabaseSpecificSqlScript()
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace Umbraco.Tests.Migrations.Upgrades
|
||||
_sqlSyntax = new SqlCeSyntaxProvider();
|
||||
|
||||
var dbProviderFactory = DbProviderFactories.GetFactory(Constants.DbProviderNames.SqlCe);
|
||||
_database = new UmbracoDatabase("cstr", _sqlSyntax, DatabaseType.SQLCe, dbProviderFactory, _logger);
|
||||
var sqlContext = new SqlContext(_sqlSyntax, Mock.Of<IPocoDataFactory>(), DatabaseType.SQLCe);
|
||||
_database = new UmbracoDatabase("cstr", sqlContext, dbProviderFactory, _logger);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -38,10 +38,10 @@ namespace Umbraco.Tests.Persistence
|
||||
_sqlCeSyntaxProvider = new SqlCeSyntaxProvider();
|
||||
_sqlSyntaxProviders = new[] { (ISqlSyntaxProvider) _sqlCeSyntaxProvider };
|
||||
_logger = Mock.Of<ILogger>();
|
||||
var dbFactory = new DefaultDatabaseFactory(Core.Configuration.GlobalSettings.UmbracoConnectionName, _sqlSyntaxProviders, _logger, new TestUmbracoDatabaseAccessor(), Mock.Of<IQueryFactory>());
|
||||
var dbFactory = new DefaultDatabaseFactory(Core.Configuration.GlobalSettings.UmbracoConnectionName, _sqlSyntaxProviders, _logger, new TestUmbracoDatabaseAccessor(), Mock.Of<IMapperCollection>());
|
||||
_runtime = Mock.Of<IRuntimeState>();
|
||||
_migrationEntryService = Mock.Of<IMigrationEntryService>();
|
||||
_dbContext = new DatabaseContext(dbFactory, _logger, _runtime, _migrationEntryService);
|
||||
_dbContext = new DatabaseContext(dbFactory);
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
@@ -91,8 +91,8 @@ namespace Umbraco.Tests.Persistence
|
||||
}
|
||||
|
||||
// re-create the database factory and database context with proper connection string
|
||||
var dbFactory = new DefaultDatabaseFactory(connString, Constants.DbProviderNames.SqlCe, _sqlSyntaxProviders, _logger, new TestUmbracoDatabaseAccessor(), Mock.Of<IQueryFactory>());
|
||||
_dbContext = new DatabaseContext(dbFactory, _logger, _runtime, _migrationEntryService);
|
||||
var dbFactory = new DefaultDatabaseFactory(connString, Constants.DbProviderNames.SqlCe, _sqlSyntaxProviders, _logger, new TestUmbracoDatabaseAccessor(), Mock.Of<IMapperCollection>());
|
||||
_dbContext = new DatabaseContext(dbFactory);
|
||||
|
||||
// create application context
|
||||
//var appCtx = new ApplicationContext(
|
||||
@@ -126,7 +126,7 @@ namespace Umbraco.Tests.Persistence
|
||||
[TestCase("tcp:MyServer.database.windows.net,1433", "MyDatabase", "MyUser@MyServer", "MyPassword")]
|
||||
public void Build_Azure_Connection_String_Regular(string server, string databaseName, string userName, string password)
|
||||
{
|
||||
var connectionString = DatabaseContext.GetAzureConnectionString(server, databaseName, userName, password);
|
||||
var connectionString = DatabaseBuilder.GetAzureConnectionString(server, databaseName, userName, password);
|
||||
Assert.AreEqual(connectionString, "Server=tcp:MyServer.database.windows.net,1433;Database=MyDatabase;User ID=MyUser@MyServer;Password=MyPassword");
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace Umbraco.Tests.Persistence
|
||||
[TestCase("tcp:kzeej5z8ty.ssmsawacluster4.windowsazure.mscds.com", "MyDatabase", "MyUser@kzeej5z8ty", "MyPassword")]
|
||||
public void Build_Azure_Connection_String_CustomServer(string server, string databaseName, string userName, string password)
|
||||
{
|
||||
var connectionString = DatabaseContext.GetAzureConnectionString(server, databaseName, userName, password);
|
||||
var connectionString = DatabaseBuilder.GetAzureConnectionString(server, databaseName, userName, password);
|
||||
Assert.AreEqual(connectionString, "Server=tcp:kzeej5z8ty.ssmsawacluster4.windowsazure.mscds.com,1433;Database=MyDatabase;User ID=MyUser@kzeej5z8ty;Password=MyPassword");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Tests.Persistence.FaultHandling
|
||||
const string connectionString = @"server=.\SQLEXPRESS;database=EmptyForTest;user id=x;password=umbraco";
|
||||
const string providerName = Constants.DbProviderNames.SqlServer;
|
||||
var sqlSyntax = new[] { new SqlServerSyntaxProvider(new Lazy<IDatabaseFactory>(() => null)) };
|
||||
var factory = new DefaultDatabaseFactory(connectionString, providerName, sqlSyntax, Mock.Of<ILogger>(), new TestUmbracoDatabaseAccessor(), Mock.Of<IQueryFactory>());
|
||||
var factory = new DefaultDatabaseFactory(connectionString, providerName, sqlSyntax, Mock.Of<ILogger>(), new TestUmbracoDatabaseAccessor(), Mock.Of<IMapperCollection>());
|
||||
var database = factory.GetDatabase();
|
||||
|
||||
//Act
|
||||
@@ -38,7 +38,7 @@ namespace Umbraco.Tests.Persistence.FaultHandling
|
||||
const string connectionString = @"server=.\SQLEXPRESS;database=EmptyForTest;user id=umbraco;password=umbraco";
|
||||
const string providerName = Constants.DbProviderNames.SqlServer;
|
||||
var sqlSyntax = new[] { new SqlServerSyntaxProvider(new Lazy<IDatabaseFactory>(() => null)) };
|
||||
var factory = new DefaultDatabaseFactory(connectionString, providerName, sqlSyntax, Mock.Of<ILogger>(), new TestUmbracoDatabaseAccessor(), Mock.Of<IQueryFactory>());
|
||||
var factory = new DefaultDatabaseFactory(connectionString, providerName, sqlSyntax, Mock.Of<ILogger>(), new TestUmbracoDatabaseAccessor(), Mock.Of<IMapperCollection>());
|
||||
var database = factory.GetDatabase();
|
||||
|
||||
//Act
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetDatabaseUnitOfWorkProvider(Logger);
|
||||
using (var unitOfWork = provider.CreateUnitOfWork())
|
||||
{
|
||||
var repo = new AuditRepository(unitOfWork, CacheHelper, Logger, QueryFactory);
|
||||
var repo = new AuditRepository(unitOfWork, CacheHelper, Logger);
|
||||
repo.AddOrUpdate(new AuditItem(-1, "This is a System audit trail", AuditType.System, 0));
|
||||
unitOfWork.Complete();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
{
|
||||
TemplateRepository tr;
|
||||
var ctRepository = CreateRepository(unitOfWork, out contentTypeRepository, out tr);
|
||||
dtdRepository = new DataTypeDefinitionRepository(unitOfWork, CacheHelper, Logger, contentTypeRepository, QueryFactory);
|
||||
dtdRepository = new DataTypeDefinitionRepository(unitOfWork, CacheHelper, Logger, contentTypeRepository);
|
||||
return ctRepository;
|
||||
}
|
||||
|
||||
@@ -52,10 +52,10 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
private ContentRepository CreateRepository(IDatabaseUnitOfWork unitOfWork, out ContentTypeRepository contentTypeRepository, out TemplateRepository templateRepository)
|
||||
{
|
||||
templateRepository = new TemplateRepository(unitOfWork, CacheHelper, Logger, Mock.Of<IFileSystem>(), Mock.Of<IFileSystem>(), Mock.Of<ITemplatesSection>(), QueryFactory);
|
||||
var tagRepository = new TagRepository(unitOfWork, CacheHelper, Logger, QueryFactory);
|
||||
contentTypeRepository = new ContentTypeRepository(unitOfWork, CacheHelper, Logger, templateRepository, QueryFactory);
|
||||
var repository = new ContentRepository(unitOfWork, CacheHelper, Logger, contentTypeRepository, templateRepository, tagRepository, Mock.Of<IContentSection>(), QueryFactory);
|
||||
templateRepository = new TemplateRepository(unitOfWork, CacheHelper, Logger, Mock.Of<IFileSystem>(), Mock.Of<IFileSystem>(), Mock.Of<ITemplatesSection>());
|
||||
var tagRepository = new TagRepository(unitOfWork, CacheHelper, Logger);
|
||||
contentTypeRepository = new ContentTypeRepository(unitOfWork, CacheHelper, Logger, templateRepository);
|
||||
var repository = new ContentRepository(unitOfWork, CacheHelper, Logger, contentTypeRepository, templateRepository, tagRepository, Mock.Of<IContentSection>());
|
||||
return repository;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,29 +36,29 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
|
||||
private ContentRepository CreateRepository(IDatabaseUnitOfWork unitOfWork, out ContentTypeRepository contentTypeRepository)
|
||||
{
|
||||
var templateRepository = new TemplateRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, Mock.Of<IFileSystem>(), Mock.Of<IFileSystem>(), Mock.Of<ITemplatesSection>(), QueryFactory);
|
||||
var tagRepository = new TagRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, QueryFactory);
|
||||
contentTypeRepository = new ContentTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, templateRepository, QueryFactory);
|
||||
var repository = new ContentRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, contentTypeRepository, templateRepository, tagRepository, Mock.Of<IContentSection>(), QueryFactory);
|
||||
var templateRepository = new TemplateRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, Mock.Of<IFileSystem>(), Mock.Of<IFileSystem>(), Mock.Of<ITemplatesSection>());
|
||||
var tagRepository = new TagRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger);
|
||||
contentTypeRepository = new ContentTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, templateRepository);
|
||||
var repository = new ContentRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, contentTypeRepository, templateRepository, tagRepository, Mock.Of<IContentSection>());
|
||||
return repository;
|
||||
}
|
||||
|
||||
private ContentTypeRepository CreateRepository(IDatabaseUnitOfWork unitOfWork)
|
||||
{
|
||||
var templateRepository = new TemplateRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, Mock.Of<IFileSystem>(), Mock.Of<IFileSystem>(), Mock.Of<ITemplatesSection>(), QueryFactory);
|
||||
var contentTypeRepository = new ContentTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, templateRepository, QueryFactory);
|
||||
var templateRepository = new TemplateRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, Mock.Of<IFileSystem>(), Mock.Of<IFileSystem>(), Mock.Of<ITemplatesSection>());
|
||||
var contentTypeRepository = new ContentTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, templateRepository);
|
||||
return contentTypeRepository;
|
||||
}
|
||||
|
||||
private MediaTypeRepository CreateMediaTypeRepository(IDatabaseUnitOfWork unitOfWork)
|
||||
{
|
||||
var contentTypeRepository = new MediaTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, QueryFactory);
|
||||
var contentTypeRepository = new MediaTypeRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger);
|
||||
return contentTypeRepository;
|
||||
}
|
||||
|
||||
private EntityContainerRepository CreateContainerRepository(IDatabaseUnitOfWork unitOfWork, Guid containerEntityType)
|
||||
{
|
||||
return new EntityContainerRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, QueryFactory, containerEntityType);
|
||||
return new EntityContainerRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, containerEntityType);
|
||||
}
|
||||
|
||||
//TODO Add test to verify SetDefaultTemplates updates both AllowedTemplates and DefaultTemplate(id).
|
||||
@@ -71,7 +71,7 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
var provider = TestObjects.GetDatabaseUnitOfWorkProvider(Logger);
|
||||
using (var unitOfWork = provider.CreateUnitOfWork())
|
||||
{
|
||||
var templateRepo = new TemplateRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, Mock.Of<IFileSystem>(), Mock.Of<IFileSystem>(), Mock.Of<ITemplatesSection>(), QueryFactory);
|
||||
var templateRepo = new TemplateRepository(unitOfWork, CacheHelper.CreateDisabledCacheHelper(), Logger, Mock.Of<IFileSystem>(), Mock.Of<IFileSystem>(), Mock.Of<ITemplatesSection>());
|
||||
var repository = CreateRepository(unitOfWork);
|
||||
var templates = new[]
|
||||
{
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user